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