1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftbitmap.c                                                             */
4 /*                                                                         */
5 /*    FreeType utility functions for bitmaps (body).                       */
6 /*                                                                         */
7 /*  Copyright 2004-2018 by                                                 */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17 
18 
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 
22 #include FT_BITMAP_H
23 #include FT_IMAGE_H
24 #include FT_INTERNAL_OBJECTS_H
25 
26 
27   static
28   const FT_Bitmap  null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 };
29 
30 
31   /* documentation is in ftbitmap.h */
32 
33   FT_EXPORT_DEF( void )
FT_Bitmap_Init(FT_Bitmap * abitmap)34   FT_Bitmap_Init( FT_Bitmap  *abitmap )
35   {
36     if ( abitmap )
37       *abitmap = null_bitmap;
38   }
39 
40 
41   /* deprecated function name; retained for ABI compatibility */
42 
43   FT_EXPORT_DEF( void )
FT_Bitmap_New(FT_Bitmap * abitmap)44   FT_Bitmap_New( FT_Bitmap  *abitmap )
45   {
46     if ( abitmap )
47       *abitmap = null_bitmap;
48   }
49 
50 
51   /* documentation is in ftbitmap.h */
52 
53   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Copy(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target)54   FT_Bitmap_Copy( FT_Library        library,
55                   const FT_Bitmap  *source,
56                   FT_Bitmap        *target)
57   {
58     FT_Memory  memory;
59     FT_Error   error  = FT_Err_Ok;
60 
61     FT_Int    pitch;
62     FT_ULong  size;
63 
64     FT_Int  source_pitch_sign, target_pitch_sign;
65 
66 
67     if ( !library )
68       return FT_THROW( Invalid_Library_Handle );
69 
70     if ( !source || !target )
71       return FT_THROW( Invalid_Argument );
72 
73     if ( source == target )
74       return FT_Err_Ok;
75 
76     source_pitch_sign = source->pitch < 0 ? -1 : 1;
77     target_pitch_sign = target->pitch < 0 ? -1 : 1;
78 
79     if ( !source->buffer )
80     {
81       *target = *source;
82       if ( source_pitch_sign != target_pitch_sign )
83         target->pitch = -target->pitch;
84 
85       return FT_Err_Ok;
86     }
87 
88     memory = library->memory;
89     pitch  = source->pitch;
90 
91     if ( pitch < 0 )
92       pitch = -pitch;
93     size = (FT_ULong)pitch * source->rows;
94 
95     if ( target->buffer )
96     {
97       FT_Int    target_pitch = target->pitch;
98       FT_ULong  target_size;
99 
100 
101       if ( target_pitch < 0 )
102         target_pitch = -target_pitch;
103       target_size = (FT_ULong)target_pitch * target->rows;
104 
105       if ( target_size != size )
106         (void)FT_QREALLOC( target->buffer, target_size, size );
107     }
108     else
109       (void)FT_QALLOC( target->buffer, size );
110 
111     if ( !error )
112     {
113       unsigned char *p;
114 
115 
116       p = target->buffer;
117       *target = *source;
118       target->buffer = p;
119 
120       if ( source_pitch_sign == target_pitch_sign )
121         FT_MEM_COPY( target->buffer, source->buffer, size );
122       else
123       {
124         /* take care of bitmap flow */
125         FT_UInt   i;
126         FT_Byte*  s = source->buffer;
127         FT_Byte*  t = target->buffer;
128 
129 
130         t += (FT_ULong)pitch * ( target->rows - 1 );
131 
132         for ( i = target->rows; i > 0; i-- )
133         {
134           FT_ARRAY_COPY( t, s, pitch );
135 
136           s += pitch;
137           t -= pitch;
138         }
139       }
140     }
141 
142     return error;
143   }
144 
145 
146   /* Enlarge `bitmap' horizontally and vertically by `xpixels' */
147   /* and `ypixels', respectively.                              */
148 
149   static FT_Error
ft_bitmap_assure_buffer(FT_Memory memory,FT_Bitmap * bitmap,FT_UInt xpixels,FT_UInt ypixels)150   ft_bitmap_assure_buffer( FT_Memory   memory,
151                            FT_Bitmap*  bitmap,
152                            FT_UInt     xpixels,
153                            FT_UInt     ypixels )
154   {
155     FT_Error        error;
156     unsigned int    pitch;
157     unsigned int    new_pitch;
158     FT_UInt         bpp;
159     FT_UInt         width, height;
160     unsigned char*  buffer = NULL;
161 
162 
163     width  = bitmap->width;
164     height = bitmap->rows;
165     pitch  = (unsigned int)FT_ABS( bitmap->pitch );
166 
167     switch ( bitmap->pixel_mode )
168     {
169     case FT_PIXEL_MODE_MONO:
170       bpp       = 1;
171       new_pitch = ( width + xpixels + 7 ) >> 3;
172       break;
173     case FT_PIXEL_MODE_GRAY2:
174       bpp       = 2;
175       new_pitch = ( width + xpixels + 3 ) >> 2;
176       break;
177     case FT_PIXEL_MODE_GRAY4:
178       bpp       = 4;
179       new_pitch = ( width + xpixels + 1 ) >> 1;
180       break;
181     case FT_PIXEL_MODE_GRAY:
182     case FT_PIXEL_MODE_LCD:
183     case FT_PIXEL_MODE_LCD_V:
184       bpp       = 8;
185       new_pitch = width + xpixels;
186       break;
187     default:
188       return FT_THROW( Invalid_Glyph_Format );
189     }
190 
191     /* if no need to allocate memory */
192     if ( ypixels == 0 && new_pitch <= pitch )
193     {
194       /* zero the padding */
195       FT_UInt  bit_width = pitch * 8;
196       FT_UInt  bit_last  = ( width + xpixels ) * bpp;
197 
198 
199       if ( bit_last < bit_width )
200       {
201         FT_Byte*  line  = bitmap->buffer + ( bit_last >> 3 );
202         FT_Byte*  end   = bitmap->buffer + pitch;
203         FT_UInt   shift = bit_last & 7;
204         FT_UInt   mask  = 0xFF00U >> shift;
205         FT_UInt   count = height;
206 
207 
208         for ( ; count > 0; count--, line += pitch, end += pitch )
209         {
210           FT_Byte*  write = line;
211 
212 
213           if ( shift > 0 )
214           {
215             write[0] = (FT_Byte)( write[0] & mask );
216             write++;
217           }
218           if ( write < end )
219             FT_MEM_ZERO( write, end - write );
220         }
221       }
222 
223       return FT_Err_Ok;
224     }
225 
226     /* otherwise allocate new buffer */
227     if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) )
228       return error;
229 
230     /* new rows get added at the top of the bitmap, */
231     /* thus take care of the flow direction         */
232     if ( bitmap->pitch > 0 )
233     {
234       FT_UInt  len = ( width * bpp + 7 ) >> 3;
235 
236       unsigned char*  in  = bitmap->buffer;
237       unsigned char*  out = buffer;
238 
239       unsigned char*  limit = bitmap->buffer + pitch * bitmap->rows;
240       unsigned int    delta = new_pitch - pitch;
241 
242 
243       FT_MEM_ZERO( out, new_pitch * ypixels );
244       out += new_pitch * ypixels;
245 
246       while ( in < limit )
247       {
248         FT_MEM_COPY( out, in, len );
249         in  += pitch;
250         out += pitch;
251 
252         FT_MEM_ZERO( out, delta );
253         out += delta;
254       }
255     }
256     else
257     {
258       FT_UInt  len = ( width * bpp + 7 ) >> 3;
259 
260       unsigned char*  in  = bitmap->buffer;
261       unsigned char*  out = buffer;
262 
263       unsigned char*  limit = bitmap->buffer + pitch * bitmap->rows;
264       unsigned int    delta = new_pitch - pitch;
265 
266 
267       while ( in < limit )
268       {
269         FT_MEM_COPY( out, in, len );
270         in  += pitch;
271         out += pitch;
272 
273         FT_MEM_ZERO( out, delta );
274         out += delta;
275       }
276 
277       FT_MEM_ZERO( out, new_pitch * ypixels );
278     }
279 
280     FT_FREE( bitmap->buffer );
281     bitmap->buffer = buffer;
282 
283     /* set pitch only, width and height are left untouched */
284     if ( bitmap->pitch < 0 )
285       bitmap->pitch = -(int)new_pitch;
286     else
287       bitmap->pitch = (int)new_pitch;
288 
289     return FT_Err_Ok;
290   }
291 
292 
293   /* documentation is in ftbitmap.h */
294 
295   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Embolden(FT_Library library,FT_Bitmap * bitmap,FT_Pos xStrength,FT_Pos yStrength)296   FT_Bitmap_Embolden( FT_Library  library,
297                       FT_Bitmap*  bitmap,
298                       FT_Pos      xStrength,
299                       FT_Pos      yStrength )
300   {
301     FT_Error        error;
302     unsigned char*  p;
303     FT_Int          i, x, pitch;
304     FT_UInt         y;
305     FT_Int          xstr, ystr;
306 
307 
308     if ( !library )
309       return FT_THROW( Invalid_Library_Handle );
310 
311     if ( !bitmap || !bitmap->buffer )
312       return FT_THROW( Invalid_Argument );
313 
314     if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) ||
315          ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) )
316       return FT_THROW( Invalid_Argument );
317 
318     xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6;
319     ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6;
320 
321     if ( xstr == 0 && ystr == 0 )
322       return FT_Err_Ok;
323     else if ( xstr < 0 || ystr < 0 )
324       return FT_THROW( Invalid_Argument );
325 
326     switch ( bitmap->pixel_mode )
327     {
328     case FT_PIXEL_MODE_GRAY2:
329     case FT_PIXEL_MODE_GRAY4:
330       {
331         FT_Bitmap  tmp;
332 
333 
334         /* convert to 8bpp */
335         FT_Bitmap_Init( &tmp );
336         error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 );
337         if ( error )
338           return error;
339 
340         FT_Bitmap_Done( library, bitmap );
341         *bitmap = tmp;
342       }
343       break;
344 
345     case FT_PIXEL_MODE_MONO:
346       if ( xstr > 8 )
347         xstr = 8;
348       break;
349 
350     case FT_PIXEL_MODE_LCD:
351       xstr *= 3;
352       break;
353 
354     case FT_PIXEL_MODE_LCD_V:
355       ystr *= 3;
356       break;
357 
358     case FT_PIXEL_MODE_BGRA:
359       /* We don't embolden color glyphs. */
360       return FT_Err_Ok;
361     }
362 
363     error = ft_bitmap_assure_buffer( library->memory, bitmap,
364                                      (FT_UInt)xstr, (FT_UInt)ystr );
365     if ( error )
366       return error;
367 
368     /* take care of bitmap flow */
369     pitch = bitmap->pitch;
370     if ( pitch > 0 )
371       p = bitmap->buffer + pitch * ystr;
372     else
373     {
374       pitch = -pitch;
375       p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 );
376     }
377 
378     /* for each row */
379     for ( y = 0; y < bitmap->rows; y++ )
380     {
381       /*
382        * Horizontally:
383        *
384        * From the last pixel on, make each pixel or'ed with the
385        * `xstr' pixels before it.
386        */
387       for ( x = pitch - 1; x >= 0; x-- )
388       {
389         unsigned char  tmp;
390 
391 
392         tmp = p[x];
393         for ( i = 1; i <= xstr; i++ )
394         {
395           if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO )
396           {
397             p[x] |= tmp >> i;
398 
399             /* the maximum value of 8 for `xstr' comes from here */
400             if ( x > 0 )
401               p[x] |= p[x - 1] << ( 8 - i );
402 
403 #if 0
404             if ( p[x] == 0xFF )
405               break;
406 #endif
407           }
408           else
409           {
410             if ( x - i >= 0 )
411             {
412               if ( p[x] + p[x - i] > bitmap->num_grays - 1 )
413               {
414                 p[x] = (unsigned char)( bitmap->num_grays - 1 );
415                 break;
416               }
417               else
418               {
419                 p[x] = (unsigned char)( p[x] + p[x - i] );
420                 if ( p[x] == bitmap->num_grays - 1 )
421                   break;
422               }
423             }
424             else
425               break;
426           }
427         }
428       }
429 
430       /*
431        * Vertically:
432        *
433        * Make the above `ystr' rows or'ed with it.
434        */
435       for ( x = 1; x <= ystr; x++ )
436       {
437         unsigned char*  q;
438 
439 
440         q = p - bitmap->pitch * x;
441         for ( i = 0; i < pitch; i++ )
442           q[i] |= p[i];
443       }
444 
445       p += bitmap->pitch;
446     }
447 
448     bitmap->width += (FT_UInt)xstr;
449     bitmap->rows += (FT_UInt)ystr;
450 
451     return FT_Err_Ok;
452   }
453 
454 
455   static FT_Byte
ft_gray_for_premultiplied_srgb_bgra(const FT_Byte * bgra)456   ft_gray_for_premultiplied_srgb_bgra( const FT_Byte*  bgra )
457   {
458     FT_UInt  a = bgra[3];
459     FT_UInt  l;
460 
461 
462     /* Short-circuit transparent color to avoid division by zero. */
463     if ( !a )
464       return 0;
465 
466     /*
467      * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722
468      * coefficients for RGB channels *on the linear colors*.
469      * A gamma of 2.2 is fair to assume.  And then, we need to
470      * undo the premultiplication too.
471      *
472      *   https://accessibility.kde.org/hsl-adjusted.php
473      *
474      * We do the computation with integers only, applying a gamma of 2.0.
475      * We guarantee 32-bit arithmetic to avoid overflow but the resulting
476      * luminosity fits into 16 bits.
477      *
478      */
479 
480     l = (  4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] +
481           46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] +
482           13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16;
483 
484     /*
485      * Final transparency can be determined as follows.
486      *
487      * - If alpha is zero, we want 0.
488      * - If alpha is zero and luminosity is zero, we want 255.
489      * - If alpha is zero and luminosity is one, we want 0.
490      *
491      * So the formula is a * (1 - l) = a - l * a.
492      *
493      * We still need to undo premultiplication by dividing l by a*a.
494      *
495      */
496 
497     return (FT_Byte)( a - l / a );
498   }
499 
500 
501   /* documentation is in ftbitmap.h */
502 
503   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Convert(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target,FT_Int alignment)504   FT_Bitmap_Convert( FT_Library        library,
505                      const FT_Bitmap  *source,
506                      FT_Bitmap        *target,
507                      FT_Int            alignment )
508   {
509     FT_Error   error = FT_Err_Ok;
510     FT_Memory  memory;
511 
512     FT_Byte*  s;
513     FT_Byte*  t;
514 
515 
516     if ( !library )
517       return FT_THROW( Invalid_Library_Handle );
518 
519     if ( !source || !target )
520       return FT_THROW( Invalid_Argument );
521 
522     memory = library->memory;
523 
524     switch ( source->pixel_mode )
525     {
526     case FT_PIXEL_MODE_MONO:
527     case FT_PIXEL_MODE_GRAY:
528     case FT_PIXEL_MODE_GRAY2:
529     case FT_PIXEL_MODE_GRAY4:
530     case FT_PIXEL_MODE_LCD:
531     case FT_PIXEL_MODE_LCD_V:
532     case FT_PIXEL_MODE_BGRA:
533       {
534         FT_Int    pad, old_target_pitch, target_pitch;
535         FT_ULong  old_size;
536 
537 
538         old_target_pitch = target->pitch;
539         if ( old_target_pitch < 0 )
540           old_target_pitch = -old_target_pitch;
541 
542         old_size = target->rows * (FT_UInt)old_target_pitch;
543 
544         target->pixel_mode = FT_PIXEL_MODE_GRAY;
545         target->rows       = source->rows;
546         target->width      = source->width;
547 
548         pad = 0;
549         if ( alignment > 0 )
550         {
551           pad = (FT_Int)source->width % alignment;
552           if ( pad != 0 )
553             pad = alignment - pad;
554         }
555 
556         target_pitch = (FT_Int)source->width + pad;
557 
558         if ( target_pitch > 0                                               &&
559              (FT_ULong)target->rows > FT_ULONG_MAX / (FT_ULong)target_pitch )
560           return FT_THROW( Invalid_Argument );
561 
562         if ( FT_QREALLOC( target->buffer,
563                           old_size, target->rows * (FT_UInt)target_pitch ) )
564           return error;
565 
566         target->pitch = target->pitch < 0 ? -target_pitch : target_pitch;
567       }
568       break;
569 
570     default:
571       error = FT_THROW( Invalid_Argument );
572     }
573 
574     s = source->buffer;
575     t = target->buffer;
576 
577     /* take care of bitmap flow */
578     if ( source->pitch < 0 )
579       s -= source->pitch * (FT_Int)( source->rows - 1 );
580     if ( target->pitch < 0 )
581       t -= target->pitch * (FT_Int)( target->rows - 1 );
582 
583     switch ( source->pixel_mode )
584     {
585     case FT_PIXEL_MODE_MONO:
586       {
587         FT_UInt  i;
588 
589 
590         target->num_grays = 2;
591 
592         for ( i = source->rows; i > 0; i-- )
593         {
594           FT_Byte*  ss = s;
595           FT_Byte*  tt = t;
596           FT_UInt   j;
597 
598 
599           /* get the full bytes */
600           for ( j = source->width >> 3; j > 0; j-- )
601           {
602             FT_Int  val = ss[0]; /* avoid a byte->int cast on each line */
603 
604 
605             tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 );
606             tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 );
607             tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 );
608             tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 );
609             tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 );
610             tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 );
611             tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 );
612             tt[7] = (FT_Byte)(   val & 0x01 );
613 
614             tt += 8;
615             ss += 1;
616           }
617 
618           /* get remaining pixels (if any) */
619           j = source->width & 7;
620           if ( j > 0 )
621           {
622             FT_Int  val = *ss;
623 
624 
625             for ( ; j > 0; j-- )
626             {
627               tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7);
628               val <<= 1;
629               tt   += 1;
630             }
631           }
632 
633           s += source->pitch;
634           t += target->pitch;
635         }
636       }
637       break;
638 
639 
640     case FT_PIXEL_MODE_GRAY:
641     case FT_PIXEL_MODE_LCD:
642     case FT_PIXEL_MODE_LCD_V:
643       {
644         FT_UInt  width = source->width;
645         FT_UInt  i;
646 
647 
648         target->num_grays = 256;
649 
650         for ( i = source->rows; i > 0; i-- )
651         {
652           FT_ARRAY_COPY( t, s, width );
653 
654           s += source->pitch;
655           t += target->pitch;
656         }
657       }
658       break;
659 
660 
661     case FT_PIXEL_MODE_GRAY2:
662       {
663         FT_UInt  i;
664 
665 
666         target->num_grays = 4;
667 
668         for ( i = source->rows; i > 0; i-- )
669         {
670           FT_Byte*  ss = s;
671           FT_Byte*  tt = t;
672           FT_UInt   j;
673 
674 
675           /* get the full bytes */
676           for ( j = source->width >> 2; j > 0; j-- )
677           {
678             FT_Int  val = ss[0];
679 
680 
681             tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
682             tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 );
683             tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 );
684             tt[3] = (FT_Byte)( ( val & 0x03 ) );
685 
686             ss += 1;
687             tt += 4;
688           }
689 
690           j = source->width & 3;
691           if ( j > 0 )
692           {
693             FT_Int  val = ss[0];
694 
695 
696             for ( ; j > 0; j-- )
697             {
698               tt[0]  = (FT_Byte)( ( val & 0xC0 ) >> 6 );
699               val  <<= 2;
700               tt    += 1;
701             }
702           }
703 
704           s += source->pitch;
705           t += target->pitch;
706         }
707       }
708       break;
709 
710 
711     case FT_PIXEL_MODE_GRAY4:
712       {
713         FT_UInt  i;
714 
715 
716         target->num_grays = 16;
717 
718         for ( i = source->rows; i > 0; i-- )
719         {
720           FT_Byte*  ss = s;
721           FT_Byte*  tt = t;
722           FT_UInt   j;
723 
724 
725           /* get the full bytes */
726           for ( j = source->width >> 1; j > 0; j-- )
727           {
728             FT_Int  val = ss[0];
729 
730 
731             tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 );
732             tt[1] = (FT_Byte)( ( val & 0x0F ) );
733 
734             ss += 1;
735             tt += 2;
736           }
737 
738           if ( source->width & 1 )
739             tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 );
740 
741           s += source->pitch;
742           t += target->pitch;
743         }
744       }
745       break;
746 
747 
748     case FT_PIXEL_MODE_BGRA:
749       {
750         FT_UInt  i;
751 
752 
753         target->num_grays = 256;
754 
755         for ( i = source->rows; i > 0; i-- )
756         {
757           FT_Byte*  ss = s;
758           FT_Byte*  tt = t;
759           FT_UInt   j;
760 
761 
762           for ( j = source->width; j > 0; j-- )
763           {
764             tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss );
765 
766             ss += 4;
767             tt += 1;
768           }
769 
770           s += source->pitch;
771           t += target->pitch;
772         }
773       }
774       break;
775 
776     default:
777       ;
778     }
779 
780     return error;
781   }
782 
783 
784   /* documentation is in ftbitmap.h */
785 
786   FT_EXPORT_DEF( FT_Error )
FT_GlyphSlot_Own_Bitmap(FT_GlyphSlot slot)787   FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot  slot )
788   {
789     if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP   &&
790          !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
791     {
792       FT_Bitmap  bitmap;
793       FT_Error   error;
794 
795 
796       FT_Bitmap_Init( &bitmap );
797       error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap );
798       if ( error )
799         return error;
800 
801       slot->bitmap = bitmap;
802       slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
803     }
804 
805     return FT_Err_Ok;
806   }
807 
808 
809   /* documentation is in ftbitmap.h */
810 
811   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Done(FT_Library library,FT_Bitmap * bitmap)812   FT_Bitmap_Done( FT_Library  library,
813                   FT_Bitmap  *bitmap )
814   {
815     FT_Memory  memory;
816 
817 
818     if ( !library )
819       return FT_THROW( Invalid_Library_Handle );
820 
821     if ( !bitmap )
822       return FT_THROW( Invalid_Argument );
823 
824     memory = library->memory;
825 
826     FT_FREE( bitmap->buffer );
827     *bitmap = null_bitmap;
828 
829     return FT_Err_Ok;
830   }
831 
832 
833 /* END */
834