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