/* 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 #include #include #include #include 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 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; }