Fri 16 Mar 2007 07:32:24 PM UTC, original submission:
To reproduce the issue call FT_Embolden_Bitmap(library, bitmap, 7*64, 0) on a monochrome bitmap. It's most visible on round letters, ex. 'o' or 'e'. In the resulting bitmap the right edge of the letters appear cropped.
For example lets consider that we loaded and rendered the letter 'l' and it's bitmap looks the following way:
... ... ...
0xff 0xfe 0x00
0xff 0xfe 0x00
0xff 0xfe 0x00
0xff 0xfe 0x00
0xff 0xfe 0x00
0xff 0xfe 0x00
... ... ...
width = 15 pitch = 3 ppb = 8
Now we call FT_Embolden_Bitmap(library, bitmap, 7*64, 0) to embolden it. We'll end up in ft_bitmap_assure_bitmap_buffer() at the following code (lines 136 -> 165):
/* if no need to allocate memory */
if ( ypixels == 0 && pitch * ppb >= bitmap->width + xpixels )
{
/* zero the padding */
for ( i = 0; i < bitmap->rows; i++ )
{
unsigned char* last_byte;
int bits = xpixels * ( 8 / ppb );
int mask = 0;
last_byte = bitmap->buffer + i * pitch + ( bitmap->width - 1 ) / ppb;
if ( bits >= 8 )
{
FT_MEM_ZERO( last_byte + 1, bits / 8 );
bits %= 8;
}
if ( bits > 0 )
{
while ( bits-- > 0 )
mask |= 1 << bits;
*last_byte &= ~mask;
}
}
return FT_Err_Ok;
}
What happens now:
last_byte = bitmap->buffer + i * pitch + 1;
The while loop will clear the last 7 bits from last_byte !! That will erase the last 6 valid pixels from our bitmap. That will be done on every single row. And before the embolding begins our bitmap will look as:
... ... ...
0xff 0x80 0x00
0xff 0x80 0x00
0xff 0x80 0x00
0xff 0x80 0x00
0xff 0x80 0x00
... ... ...
To address this I modified the above code to this:
/* if no need to allocate memory */
if ( ypixels == 0 && pitch * ppb >= bitmap->width + xpixels )
{
/* zero the padding */
for ( i = 0; i < bitmap->rows; i++ )
{
if ( ppb == 1 )
{
unsigned char* last_byte;
last_byte = bitmap->buffer + i * pitch + bitmap->width - 1;
FT_MEM_ZERO( last_byte + 1, xpixels );
}
else
{
unsigned char* first_byte = bitmap->buffer + i * pitch;
int bits = xpixels * ( 8 / ppb );
for (j = 0; j < bits; j++)
{
unsigned char* crt_byte;
int crt_bit;
int mask;
crt_byte = first_byte + (bitmap->width + j) / 8;
crt_bit = (bitmap->width + j) % 8;
mask = 1 << (7 - crt_bit);
*crt_byte &= ~mask;
}
}
}
return FT_Err_Ok;
}
This seems to solve the problem with the cropping. The code for the monochrome bitmaps probably could be optimized to minimize the number of memory writes.
|