• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftbitmap.c                                                             */
4 /*                                                                         */
5 /*    FreeType utility functions for bitmaps (body).                       */
6 /*                                                                         */
7 /*  Copyright 2004-2015 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 == NULL )
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     int             pitch;
157     int             new_pitch;
158     FT_UInt         bpp;
159     FT_UInt         i, width, height;
160     unsigned char*  buffer = NULL;
161 
162 
163     width  = bitmap->width;
164     height = bitmap->rows;
165     pitch  = bitmap->pitch;
166     if ( pitch < 0 )
167       pitch = -pitch;
168 
169     switch ( bitmap->pixel_mode )
170     {
171     case FT_PIXEL_MODE_MONO:
172       bpp       = 1;
173       new_pitch = (int)( ( width + xpixels + 7 ) >> 3 );
174       break;
175     case FT_PIXEL_MODE_GRAY2:
176       bpp       = 2;
177       new_pitch = (int)( ( width + xpixels + 3 ) >> 2 );
178       break;
179     case FT_PIXEL_MODE_GRAY4:
180       bpp       = 4;
181       new_pitch = (int)( ( width + xpixels + 1 ) >> 1 );
182       break;
183     case FT_PIXEL_MODE_GRAY:
184     case FT_PIXEL_MODE_LCD:
185     case FT_PIXEL_MODE_LCD_V:
186       bpp       = 8;
187       new_pitch = (int)( width + xpixels );
188       break;
189     default:
190       return FT_THROW( Invalid_Glyph_Format );
191     }
192 
193     /* if no need to allocate memory */
194     if ( ypixels == 0 && new_pitch <= pitch )
195     {
196       /* zero the padding */
197       FT_UInt  bit_width = (FT_UInt)pitch * 8;
198       FT_UInt  bit_last  = ( width + xpixels ) * bpp;
199 
200 
201       if ( bit_last < bit_width )
202       {
203         FT_Byte*  line  = bitmap->buffer + ( bit_last >> 3 );
204         FT_Byte*  end   = bitmap->buffer + pitch;
205         FT_UInt   shift = bit_last & 7;
206         FT_UInt   mask  = 0xFF00U >> shift;
207         FT_UInt   count = height;
208 
209 
210         for ( ; count > 0; count--, line += pitch, end += pitch )
211         {
212           FT_Byte*  write = line;
213 
214 
215           if ( shift > 0 )
216           {
217             write[0] = (FT_Byte)( write[0] & mask );
218             write++;
219           }
220           if ( write < end )
221             FT_MEM_ZERO( write, end - write );
222         }
223       }
224 
225       return FT_Err_Ok;
226     }
227 
228     /* otherwise allocate new buffer */
229     if ( FT_QALLOC_MULT( buffer, new_pitch, bitmap->rows + ypixels ) )
230       return error;
231 
232     /* new rows get added at the top of the bitmap, */
233     /* thus take care of the flow direction         */
234     if ( bitmap->pitch > 0 )
235     {
236       FT_UInt  len = ( width * bpp + 7 ) >> 3;
237 
238 
239       for ( i = 0; i < bitmap->rows; i++ )
240         FT_MEM_COPY( buffer + (FT_UInt)new_pitch * ( ypixels + i ),
241                      bitmap->buffer + (FT_UInt)pitch * i,
242                      len );
243     }
244     else
245     {
246       FT_UInt  len = ( width * bpp + 7 ) >> 3;
247 
248 
249       for ( i = 0; i < bitmap->rows; i++ )
250         FT_MEM_COPY( buffer + (FT_UInt)new_pitch * i,
251                      bitmap->buffer + (FT_UInt)pitch * i,
252                      len );
253     }
254 
255     FT_FREE( bitmap->buffer );
256     bitmap->buffer = buffer;
257 
258     if ( bitmap->pitch < 0 )
259       new_pitch = -new_pitch;
260 
261     /* set pitch only, width and height are left untouched */
262     bitmap->pitch = new_pitch;
263 
264     return FT_Err_Ok;
265   }
266 
267 
268   /* documentation is in ftbitmap.h */
269 
270   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Embolden(FT_Library library,FT_Bitmap * bitmap,FT_Pos xStrength,FT_Pos yStrength)271   FT_Bitmap_Embolden( FT_Library  library,
272                       FT_Bitmap*  bitmap,
273                       FT_Pos      xStrength,
274                       FT_Pos      yStrength )
275   {
276     FT_Error        error;
277     unsigned char*  p;
278     FT_Int          i, x, pitch;
279     FT_UInt         y;
280     FT_Int          xstr, ystr;
281 
282 
283     if ( !library )
284       return FT_THROW( Invalid_Library_Handle );
285 
286     if ( !bitmap || !bitmap->buffer )
287       return FT_THROW( Invalid_Argument );
288 
289     if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) ||
290          ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) )
291       return FT_THROW( Invalid_Argument );
292 
293     xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6;
294     ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6;
295 
296     if ( xstr == 0 && ystr == 0 )
297       return FT_Err_Ok;
298     else if ( xstr < 0 || ystr < 0 )
299       return FT_THROW( Invalid_Argument );
300 
301     switch ( bitmap->pixel_mode )
302     {
303     case FT_PIXEL_MODE_GRAY2:
304     case FT_PIXEL_MODE_GRAY4:
305       {
306         FT_Bitmap  tmp;
307 
308 
309         /* convert to 8bpp */
310         FT_Bitmap_Init( &tmp );
311         error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 );
312         if ( error )
313           return error;
314 
315         FT_Bitmap_Done( library, bitmap );
316         *bitmap = tmp;
317       }
318       break;
319 
320     case FT_PIXEL_MODE_MONO:
321       if ( xstr > 8 )
322         xstr = 8;
323       break;
324 
325     case FT_PIXEL_MODE_LCD:
326       xstr *= 3;
327       break;
328 
329     case FT_PIXEL_MODE_LCD_V:
330       ystr *= 3;
331       break;
332 
333     case FT_PIXEL_MODE_BGRA:
334       /* We don't embolden color glyphs. */
335       return FT_Err_Ok;
336     }
337 
338     error = ft_bitmap_assure_buffer( library->memory, bitmap,
339                                      (FT_UInt)xstr, (FT_UInt)ystr );
340     if ( error )
341       return error;
342 
343     /* take care of bitmap flow */
344     pitch = bitmap->pitch;
345     if ( pitch > 0 )
346       p = bitmap->buffer + pitch * ystr;
347     else
348     {
349       pitch = -pitch;
350       p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 );
351     }
352 
353     /* for each row */
354     for ( y = 0; y < bitmap->rows ; y++ )
355     {
356       /*
357        * Horizontally:
358        *
359        * From the last pixel on, make each pixel or'ed with the
360        * `xstr' pixels before it.
361        */
362       for ( x = pitch - 1; x >= 0; x-- )
363       {
364         unsigned char  tmp;
365 
366 
367         tmp = p[x];
368         for ( i = 1; i <= xstr; i++ )
369         {
370           if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO )
371           {
372             p[x] |= tmp >> i;
373 
374             /* the maximum value of 8 for `xstr' comes from here */
375             if ( x > 0 )
376               p[x] |= p[x - 1] << ( 8 - i );
377 
378 #if 0
379             if ( p[x] == 0xFF )
380               break;
381 #endif
382           }
383           else
384           {
385             if ( x - i >= 0 )
386             {
387               if ( p[x] + p[x - i] > bitmap->num_grays - 1 )
388               {
389                 p[x] = (unsigned char)( bitmap->num_grays - 1 );
390                 break;
391               }
392               else
393               {
394                 p[x] = (unsigned char)( p[x] + p[x - i] );
395                 if ( p[x] == bitmap->num_grays - 1 )
396                   break;
397               }
398             }
399             else
400               break;
401           }
402         }
403       }
404 
405       /*
406        * Vertically:
407        *
408        * Make the above `ystr' rows or'ed with it.
409        */
410       for ( x = 1; x <= ystr; x++ )
411       {
412         unsigned char*  q;
413 
414 
415         q = p - bitmap->pitch * x;
416         for ( i = 0; i < pitch; i++ )
417           q[i] |= p[i];
418       }
419 
420       p += bitmap->pitch;
421     }
422 
423     bitmap->width += (FT_UInt)xstr;
424     bitmap->rows += (FT_UInt)ystr;
425 
426     return FT_Err_Ok;
427   }
428 
429 
430   static FT_Byte
ft_gray_for_premultiplied_srgb_bgra(const FT_Byte * bgra)431   ft_gray_for_premultiplied_srgb_bgra( const FT_Byte*  bgra )
432   {
433     FT_UInt  a = bgra[3];
434     FT_UInt  l;
435 
436 
437     /* Short-circuit transparent color to avoid division by zero. */
438     if ( !a )
439       return 0;
440 
441     /*
442      * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722
443      * coefficients for RGB channels *on the linear colors*.
444      * A gamma of 2.2 is fair to assume.  And then, we need to
445      * undo the premultiplication too.
446      *
447      *   http://accessibility.kde.org/hsl-adjusted.php
448      *
449      * We do the computation with integers only, applying a gamma of 2.0.
450      * We guarantee 32-bit arithmetic to avoid overflow but the resulting
451      * luminosity fits into 16 bits.
452      *
453      */
454 
455     l = (  4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] +
456           46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] +
457           13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16;
458 
459     /*
460      * Final transparency can be determined as follows.
461      *
462      * - If alpha is zero, we want 0.
463      * - If alpha is zero and luminosity is zero, we want 255.
464      * - If alpha is zero and luminosity is one, we want 0.
465      *
466      * So the formula is a * (1 - l) = a - l * a.
467      *
468      * We still need to undo premultiplication by dividing l by a*a.
469      *
470      */
471 
472     return (FT_Byte)( a - l / a );
473   }
474 
475 
476   /* documentation is in ftbitmap.h */
477 
478   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Convert(FT_Library library,const FT_Bitmap * source,FT_Bitmap * target,FT_Int alignment)479   FT_Bitmap_Convert( FT_Library        library,
480                      const FT_Bitmap  *source,
481                      FT_Bitmap        *target,
482                      FT_Int            alignment )
483   {
484     FT_Error   error = FT_Err_Ok;
485     FT_Memory  memory;
486 
487     FT_Byte*  s;
488     FT_Byte*  t;
489 
490 
491     if ( !library )
492       return FT_THROW( Invalid_Library_Handle );
493 
494     if ( !source || !target )
495       return FT_THROW( Invalid_Argument );
496 
497     memory = library->memory;
498 
499     switch ( source->pixel_mode )
500     {
501     case FT_PIXEL_MODE_MONO:
502     case FT_PIXEL_MODE_GRAY:
503     case FT_PIXEL_MODE_GRAY2:
504     case FT_PIXEL_MODE_GRAY4:
505     case FT_PIXEL_MODE_LCD:
506     case FT_PIXEL_MODE_LCD_V:
507     case FT_PIXEL_MODE_BGRA:
508       {
509         FT_Int    pad, old_target_pitch, target_pitch;
510         FT_ULong  old_size;
511 
512 
513         old_target_pitch = target->pitch;
514         if ( old_target_pitch < 0 )
515           old_target_pitch = -old_target_pitch;
516 
517         old_size = target->rows * (FT_UInt)old_target_pitch;
518 
519         target->pixel_mode = FT_PIXEL_MODE_GRAY;
520         target->rows       = source->rows;
521         target->width      = source->width;
522 
523         pad = 0;
524         if ( alignment > 0 )
525         {
526           pad = (FT_Int)source->width % alignment;
527           if ( pad != 0 )
528             pad = alignment - pad;
529         }
530 
531         target_pitch = (FT_Int)source->width + pad;
532 
533         if ( target_pitch > 0                                               &&
534              (FT_ULong)target->rows > FT_ULONG_MAX / (FT_ULong)target_pitch )
535           return FT_THROW( Invalid_Argument );
536 
537         if ( target->rows * (FT_ULong)target_pitch > old_size              &&
538              FT_QREALLOC( target->buffer,
539                           old_size, target->rows * (FT_UInt)target_pitch ) )
540           return error;
541 
542         target->pitch = target->pitch < 0 ? -target_pitch : target_pitch;
543       }
544       break;
545 
546     default:
547       error = FT_THROW( Invalid_Argument );
548     }
549 
550     s = source->buffer;
551     t = target->buffer;
552 
553     /* take care of bitmap flow */
554     if ( source->pitch < 0 )
555       s -= source->pitch * (FT_Int)( source->rows - 1 );
556     if ( target->pitch < 0 )
557       t -= target->pitch * (FT_Int)( target->rows - 1 );
558 
559     switch ( source->pixel_mode )
560     {
561     case FT_PIXEL_MODE_MONO:
562       {
563         FT_UInt  i;
564 
565 
566         target->num_grays = 2;
567 
568         for ( i = source->rows; i > 0; i-- )
569         {
570           FT_Byte*  ss = s;
571           FT_Byte*  tt = t;
572           FT_UInt   j;
573 
574 
575           /* get the full bytes */
576           for ( j = source->width >> 3; j > 0; j-- )
577           {
578             FT_Int  val = ss[0]; /* avoid a byte->int cast on each line */
579 
580 
581             tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 );
582             tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 );
583             tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 );
584             tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 );
585             tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 );
586             tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 );
587             tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 );
588             tt[7] = (FT_Byte)(   val & 0x01 );
589 
590             tt += 8;
591             ss += 1;
592           }
593 
594           /* get remaining pixels (if any) */
595           j = source->width & 7;
596           if ( j > 0 )
597           {
598             FT_Int  val = *ss;
599 
600 
601             for ( ; j > 0; j-- )
602             {
603               tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7);
604               val <<= 1;
605               tt   += 1;
606             }
607           }
608 
609           s += source->pitch;
610           t += target->pitch;
611         }
612       }
613       break;
614 
615 
616     case FT_PIXEL_MODE_GRAY:
617     case FT_PIXEL_MODE_LCD:
618     case FT_PIXEL_MODE_LCD_V:
619       {
620         FT_UInt  width = source->width;
621         FT_UInt  i;
622 
623 
624         target->num_grays = 256;
625 
626         for ( i = source->rows; i > 0; i-- )
627         {
628           FT_ARRAY_COPY( t, s, width );
629 
630           s += source->pitch;
631           t += target->pitch;
632         }
633       }
634       break;
635 
636 
637     case FT_PIXEL_MODE_GRAY2:
638       {
639         FT_UInt  i;
640 
641 
642         target->num_grays = 4;
643 
644         for ( i = source->rows; i > 0; i-- )
645         {
646           FT_Byte*  ss = s;
647           FT_Byte*  tt = t;
648           FT_UInt   j;
649 
650 
651           /* get the full bytes */
652           for ( j = source->width >> 2; j > 0; j-- )
653           {
654             FT_Int  val = ss[0];
655 
656 
657             tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
658             tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 );
659             tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 );
660             tt[3] = (FT_Byte)( ( val & 0x03 ) );
661 
662             ss += 1;
663             tt += 4;
664           }
665 
666           j = source->width & 3;
667           if ( j > 0 )
668           {
669             FT_Int  val = ss[0];
670 
671 
672             for ( ; j > 0; j-- )
673             {
674               tt[0]  = (FT_Byte)( ( val & 0xC0 ) >> 6 );
675               val  <<= 2;
676               tt    += 1;
677             }
678           }
679 
680           s += source->pitch;
681           t += target->pitch;
682         }
683       }
684       break;
685 
686 
687     case FT_PIXEL_MODE_GRAY4:
688       {
689         FT_UInt  i;
690 
691 
692         target->num_grays = 16;
693 
694         for ( i = source->rows; i > 0; i-- )
695         {
696           FT_Byte*  ss = s;
697           FT_Byte*  tt = t;
698           FT_UInt   j;
699 
700 
701           /* get the full bytes */
702           for ( j = source->width >> 1; j > 0; j-- )
703           {
704             FT_Int  val = ss[0];
705 
706 
707             tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 );
708             tt[1] = (FT_Byte)( ( val & 0x0F ) );
709 
710             ss += 1;
711             tt += 2;
712           }
713 
714           if ( source->width & 1 )
715             tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 );
716 
717           s += source->pitch;
718           t += target->pitch;
719         }
720       }
721       break;
722 
723 
724     case FT_PIXEL_MODE_BGRA:
725       {
726         FT_UInt  i;
727 
728 
729         target->num_grays = 256;
730 
731         for ( i = source->rows; i > 0; i-- )
732         {
733           FT_Byte*  ss = s;
734           FT_Byte*  tt = t;
735           FT_UInt   j;
736 
737 
738           for ( j = source->width; j > 0; j-- )
739           {
740             tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss );
741 
742             ss += 4;
743             tt += 1;
744           }
745 
746           s += source->pitch;
747           t += target->pitch;
748         }
749       }
750       break;
751 
752     default:
753       ;
754     }
755 
756     return error;
757   }
758 
759 
760   /* documentation is in ftbitmap.h */
761 
762   FT_EXPORT_DEF( FT_Error )
FT_GlyphSlot_Own_Bitmap(FT_GlyphSlot slot)763   FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot  slot )
764   {
765     if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP   &&
766          !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
767     {
768       FT_Bitmap  bitmap;
769       FT_Error   error;
770 
771 
772       FT_Bitmap_Init( &bitmap );
773       error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap );
774       if ( error )
775         return error;
776 
777       slot->bitmap = bitmap;
778       slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
779     }
780 
781     return FT_Err_Ok;
782   }
783 
784 
785   /* documentation is in ftbitmap.h */
786 
787   FT_EXPORT_DEF( FT_Error )
FT_Bitmap_Done(FT_Library library,FT_Bitmap * bitmap)788   FT_Bitmap_Done( FT_Library  library,
789                   FT_Bitmap  *bitmap )
790   {
791     FT_Memory  memory;
792 
793 
794     if ( !library )
795       return FT_THROW( Invalid_Library_Handle );
796 
797     if ( !bitmap )
798       return FT_THROW( Invalid_Argument );
799 
800     memory = library->memory;
801 
802     FT_FREE( bitmap->buffer );
803     *bitmap = null_bitmap;
804 
805     return FT_Err_Ok;
806   }
807 
808 
809 /* END */
810