mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-14 03:42:34 +00:00
b7f89b6aa6
svn path=/trunk/kdegraphics/kdvi/; revision=92031
149 lines
4.8 KiB
C++
149 lines
4.8 KiB
C++
|
|
/* glyph.cpp
|
|
*
|
|
* part of kdvi, a dvi-previewer for the KDE desktop environement
|
|
*
|
|
* written by Stefan Kebekus, originally based on code by Paul Vojta
|
|
* and a large number of co-authors */
|
|
|
|
#include "dviwin.h"
|
|
#include "glyph.h"
|
|
#include "oconfig.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <qbitmap.h>
|
|
#include <qimage.h>
|
|
#include <qpainter.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
glyph::glyph()
|
|
{
|
|
bitmap.bits = 0;
|
|
SmallChar = 0;
|
|
}
|
|
|
|
glyph::~glyph()
|
|
{
|
|
if (bitmap.bits != NULL)
|
|
free(bitmap.bits);
|
|
clearShrunkCharacter();
|
|
}
|
|
|
|
void glyph::clearShrunkCharacter()
|
|
{
|
|
if (SmallChar != NULL) {
|
|
delete SmallChar;
|
|
SmallChar = NULL;
|
|
}
|
|
}
|
|
|
|
/** This method returns the SmallChar of the glyph-class, if it
|
|
* exists. If not, it is generated by shrinking the bitmap according
|
|
* to the shrink_factor. */
|
|
|
|
QPixmap glyph::shrunkCharacter()
|
|
{
|
|
if (SmallChar == NULL) {
|
|
// Rescaling a character is an art that requires some
|
|
// explanation...
|
|
//
|
|
// If we would just divide the size of the character and the
|
|
// coordinates by the shrink factor, then the result would look
|
|
// quite ugly: due to the ineviatable rounding errors in the
|
|
// integer arithmetic, the characters would be displaced by up to
|
|
// a pixel. That doesn't sound much, but on low-resolution
|
|
// devices, such as a notebook screen, the effect would be a
|
|
// "dancing line" of characters, which looks really bad.
|
|
//
|
|
// The cure is the following procedure:
|
|
//
|
|
// (a) scale the hot point
|
|
//
|
|
// (b) fit the unshrunken bitmap into a bitmap which is even
|
|
// bigger. Use this to produce extra empty rows and columns at the
|
|
// borders. The proper choice of the border size will ensure that
|
|
// the hot point will fall exactly onto the coordinates which we
|
|
// calculated previously.
|
|
|
|
// Here the cheating starts ... on the screen many fonts look very
|
|
// light. We improve on the looks by lowering the shrink factor
|
|
// just when shrinking the characters. The position of the chars
|
|
// on the screen will not be affected, the chars are just slightly
|
|
// larger.
|
|
float sf = shrink_factor * 0.9;
|
|
|
|
// Calculate the coordinates of the hot point in the shrunken
|
|
// bitmap
|
|
x2 = (int)(x/sf);
|
|
y2 = (int)(y/sf);
|
|
|
|
// Calculate the size of the target bitmap for the
|
|
int shrunk_width = x2 + (int)((bitmap.w-x) / sf + 0.5) + 1;
|
|
int shrunk_height = y2 + (int)((bitmap.h-y) / sf + 0.5) + 1;
|
|
|
|
// Now calculate the size of the white border. This is some sort
|
|
// of black magic. Don't modify unless you know what you are doing.
|
|
int pre_rows = (int)((1.0 + y2)*sf + 0.5) - y - 1;
|
|
if (pre_rows < 0)
|
|
pre_rows = 0;
|
|
int post_rows = (int)(shrunk_height*sf + 0.5) - bitmap.h;
|
|
if (post_rows < 0)
|
|
post_rows = 0;
|
|
|
|
int pre_cols = (int)((1.0 + x2)*sf + 0.5) - x - 1;
|
|
if (pre_cols < 0)
|
|
pre_cols = 0;
|
|
int post_cols = (int)(shrunk_width*sf + 0.5) - bitmap.w;
|
|
if (post_cols < 0)
|
|
post_cols = 0;
|
|
|
|
// Now shrinking may begin. Produce a QBitmap with the unshrunk
|
|
// character.
|
|
QBitmap bm(bitmap.bytes_wide*8, (int)bitmap.h, (const uchar *)(bitmap.bits) ,TRUE);
|
|
// ... turn it into a Pixmap (highly inefficient, please improve)
|
|
SmallChar = new QPixmap(bitmap.w+pre_cols+post_cols, bitmap.h+pre_rows+post_rows);
|
|
if ((SmallChar == 0) || (SmallChar->isNull())) {
|
|
kdError(4300) << "Could not properly allocate SmallChar in glyph::shrunkCharacter!" << endl;
|
|
if (SmallChar != 0)
|
|
delete SmallChar;
|
|
SmallChar = 0;
|
|
return 0;
|
|
}
|
|
|
|
if (!bm.isNull()) {
|
|
QPainter paint(SmallChar);
|
|
paint.setBackgroundColor(Qt::white);
|
|
paint.setPen( Qt::black );
|
|
paint.fillRect(0,0,bitmap.w+pre_cols+post_cols, bitmap.h+pre_rows+post_rows, Qt::white);
|
|
paint.drawPixmap(pre_cols, pre_rows, bm);
|
|
paint.end();
|
|
} else
|
|
kdError(4300) << "Null Bitmap in glyph::shrunkCharacter encountered!" << endl;
|
|
|
|
// Generate an Image and shrink it to the proper size. By the
|
|
// documentation of smoothScale, the resulting Image will be
|
|
// 8-bit.
|
|
QImage im = SmallChar->convertToImage().smoothScale(shrunk_width, shrunk_height);
|
|
// Generate the alpha-channel. This again is highly inefficient.
|
|
// Would anybody please produce a faster routine?
|
|
QImage im32 = im.convertDepth(32);
|
|
im32.setAlphaBuffer(TRUE);
|
|
for(int y=0; y<im.height(); y++) {
|
|
QRgb *imag_scanline = (QRgb *)im32.scanLine(y);
|
|
for(int x=0; x<im.width(); x++) {
|
|
// Make White => Transparent
|
|
if ((0x00ffffff & *imag_scanline) == 0x00ffffff)
|
|
*imag_scanline &= 0x00ffffff;
|
|
else
|
|
*imag_scanline |= 0xff000000;
|
|
imag_scanline++; // Disgusting pointer arithmetic. Should be forbidden.
|
|
}
|
|
}
|
|
SmallChar->convertFromImage(im32,0);
|
|
SmallChar->setOptimization(QPixmap::BestOptim);
|
|
}
|
|
return *SmallChar;
|
|
}
|