[Ffmpeg-devel] [PATCH] drawtext.c: 09 fix draw_glyph
Gustavo Sverzut Barbieri
barbieri
Wed Sep 13 13:37:16 CEST 2006
On 9/13/06, Michael Niedermayer <michaelni at gmx.at> wrote:
> Hi
>
> On Sun, Sep 10, 2006 at 04:29:56PM -0300, Gustavo Sverzut Barbieri wrote:
> > This fix the other major remaining bug with drawtext.c: drawing glyphs.
> >
> > The previous code was flawed due over-complicated outline detection,
> > this is much more simple: while visiting a glyph pixel, check if
> > neighbours are not pixels, in this case they're border and should be
> > draw as outline if this is the case.
> >
> > I believe this is the last patch to fix bugs and improve code. If
> > they're all ok then I'll post a "code cleanup" series of patches.
> [...]
> > @@ -317,65 +305,55 @@
> > }
> >
> >
> > +static inline int bitmap_is_set(const FT_Bitmap *bitmap, const int x, const int y)
> > +{
> > + const int idx = bitmap->pitch * y + x / 8;
> > + const int is_pixel = bitmap->buffer[idx] & (0x80 >> (x % 8));
>
> /8 and %8 of signed integers is slow, you should use >>3 and &7
okay
> > +
> > + return is_pixel;
> > +}
> > +
> > +static inline int bitmap_is_border(const FT_Bitmap *bitmap, const int x, const int y, const int dx, const int dy)
> > +{
> > + if (x == 0 || x >= bitmap->width || y == 0 || y >= bitmap->rows)
> > + return 1;
> > + return !bitmap_is_set(bitmap, x + dx, y + dy);
> > +}
> >
> >
> > static inline void draw_glyph(AVPicture *picture, FT_Bitmap *bitmap, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned char yuv_fgcolor[3], unsigned char yuv_bgcolor[3], int outline)
> > {
> > int r, c;
> > - int spixel, dpixel[3], in_glyph=0;
> >
> > if (bitmap->pixel_mode == ft_pixel_mode_mono)
> > {
> > - in_glyph = 0;
> > - for (r=0; (r < bitmap->rows) && (r+y < height); r++)
> > + for (r=0; r < bitmap->rows; r++)
> > {
> > - for (c=0; (c < bitmap->width) && (c+x < width); c++)
> > + for (c=0; c < bitmap->width; c++)
> > {
> > - /* pixel in the picture (destination) */
> > - GET_PIXEL(picture, dpixel, (c+x), (y+r));
> > -
> > - /* pixel in the glyph bitmap (source) */
> > - spixel = bitmap->buffer[r*bitmap->pitch +c/8] & (0x80>>(c%8));
> > -
> > - if (spixel)
> > - COPY_3(dpixel, yuv_fgcolor);
> > -
> > - if (outline)
> > + if (bitmap_is_set(bitmap, c, r))
> > {
> > - /* border detection: */
> > - if ( (!in_glyph) && (spixel) )
> > - /* left border detected */
> > - {
> > - in_glyph = 1;
> > - /* draw left pixel border */
> > - if (c-1 >= 0)
> > - SET_PIXEL(picture, yuv_bgcolor, (c+x-1), (y+r));
> > - }
> > - else if ( (in_glyph) && (!spixel) )
> > - /* right border detected */
> > + if (outline)
> > {
> > - in_glyph = 0;
> > - /* 'draw' right pixel border */
> > - COPY_3(dpixel, yuv_bgcolor);
> > + if (bitmap_is_border(bitmap, c, r, -1, 0) &&
> > + c - 1 + x >= 0)
> > + SET_PIXEL(picture, yuv_bgcolor, c - 1 + x, r + y);
> > +
> > + if (bitmap_is_border(bitmap, c, r, +1, 0) &&
> > + c + 1 + x < width)
> > + SET_PIXEL(picture, yuv_bgcolor, c + 1 + x, r + y);
> > +
> > + if (bitmap_is_border(bitmap, c, r, 0, -1) &&
> > + r - 1 + y >= 0)
> > + SET_PIXEL(picture, yuv_bgcolor, c + x, r - 1 + y);
> > +
> > + if (bitmap_is_border(bitmap, c, r, 0, +1) &&
> > + r + 1 + y < height)
> > + SET_PIXEL(picture, yuv_bgcolor, c + x, r + 1 + y);
> > }
>
> the outline should be precalculated, instead of redoing the calculation for
> every pixel, also the code should be split into a inner optimized part and
> one for the areas close to the borders of the image to avoid the
> 0/width/height checks
I don't think pre-calculation will help here, since I'm already
visiting each pixel, then I must check if it's a border or not.
What I could do is something that ressembles the first version, where,
instead of looking at 4 neighbours, look at the next one (col + 1).
But this would add more conditionals, since I would have a state where
I'm at borders and still need to check if col + 1 < width.
> > - if (in_glyph)
> > - /* see if we have a top/bottom border */
> > - {
> > - /* top */
> > - if ( (r-1 >= 0) && (! bitmap->buffer[(r-1)*bitmap->pitch +c/8] & (0x80>>(c%8))) )
> > - /* we have a top border */
> > - SET_PIXEL(picture, yuv_bgcolor, (c+x), (y+r-1));
> > -
> > - /* bottom */
> > - if ( (r+1 < height) && (! bitmap->buffer[(r+1)*bitmap->pitch +c/8] & (0x80>>(c%8))) )
> > - /* we have a bottom border */
> > - SET_PIXEL(picture, yuv_bgcolor, (c+x), (y+r+1));
> > -
> > - }
> > + SET_PIXEL(picture, yuv_fgcolor, c + x, r + y);
>
> arent the chroma values totally wrong here? they are subsampled and just
> setting them to the color of the font if any of the 4 luma samples is part
> of the text isnt correct
> and actually the whole should be "antialiased" instead of the binary
> transparent vs. opaque
Yes, chroma values are not that right. But this was what the code did
and I keep it, since results are not that bad. I'll check how to
calculate the correct color based on other pixel value, any hints?
Thank you!
--
Gustavo Sverzut Barbieri
--------------------------------------
Jabber: barbieri at gmail.com
MSN: barbieri at gmail.com
ICQ#: 17249123
Skype: gsbarbieri
Mobile: +55 (81) 9927 0010
Phone: +1 (347) 624 6296; 08122692 at sip.stanaphone.com
GPG: 0xB640E1A2 @ wwwkeys.pgp.net
More information about the ffmpeg-devel
mailing list