1/****************************************************************************
2 *
3 * ftbitmap.c
4 *
5 * FreeType utility functions for bitmaps (body).
6 *
7 * Copyright (C) 2004-2023 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 <freetype/internal/ftdebug.h>
20
21#include <freetype/ftbitmap.h>
22#include <freetype/ftimage.h>
23#include <freetype/internal/ftobjs.h>
24
25
26 /**************************************************************************
27 *
28 * The macro FT_COMPONENT is used in trace mode. It is an implicit
29 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
30 * messages during execution.
31 */
32#undef FT_COMPONENT
33#define FT_COMPONENT bitmap
34
35
36 static
37 const FT_Bitmap null_bitmap = { 0, 0, 0, NULL, 0, 0, 0, NULL };
38
39
40 /* documentation is in ftbitmap.h */
41
42 FT_EXPORT_DEF( void )
43 FT_Bitmap_Init( FT_Bitmap *abitmap )
44 {
45 if ( abitmap )
46 *abitmap = null_bitmap;
47 }
48
49
50 /* deprecated function name; retained for ABI compatibility */
51
52 FT_EXPORT_DEF( void )
53 FT_Bitmap_New( FT_Bitmap *abitmap )
54 {
55 if ( abitmap )
56 *abitmap = null_bitmap;
57 }
58
59
60 /* documentation is in ftbitmap.h */
61
62 FT_EXPORT_DEF( FT_Error )
63 FT_Bitmap_Copy( FT_Library library,
64 const FT_Bitmap *source,
65 FT_Bitmap *target)
66 {
67 FT_Memory memory;
68 FT_Error error = FT_Err_Ok;
69 FT_Int pitch;
70 FT_Int flip;
71
72
73 if ( !library )
74 return FT_THROW( Invalid_Library_Handle );
75
76 if ( !source || !target )
77 return FT_THROW( Invalid_Argument );
78
79 if ( source == target )
80 return FT_Err_Ok;
81
82 flip = ( source->pitch < 0 && target->pitch > 0 ) ||
83 ( source->pitch > 0 && target->pitch < 0 );
84
85 memory = library->memory;
86 FT_FREE( target->buffer );
87
88 *target = *source;
89
90 if ( flip )
91 target->pitch = -target->pitch;
92
93 if ( !source->buffer )
94 return FT_Err_Ok;
95
96 pitch = source->pitch;
97 if ( pitch < 0 )
98 pitch = -pitch;
99
100 FT_MEM_QALLOC_MULT( target->buffer, target->rows, pitch );
101
102 if ( !error )
103 {
104 if ( flip )
105 {
106 /* take care of bitmap flow */
107 FT_UInt i;
108 FT_Byte* s = source->buffer;
109 FT_Byte* t = target->buffer;
110
111
112 t += (FT_ULong)pitch * ( target->rows - 1 );
113
114 for ( i = target->rows; i > 0; i-- )
115 {
116 FT_ARRAY_COPY( t, s, pitch );
117
118 s += pitch;
119 t -= pitch;
120 }
121 }
122 else
123 FT_MEM_COPY( target->buffer, source->buffer,
124 (FT_Long)source->rows * pitch );
125 }
126
127 return error;
128 }
129
130
131 /* Enlarge `bitmap' horizontally and vertically by `xpixels' */
132 /* and `ypixels', respectively. */
133
134 static FT_Error
135 ft_bitmap_assure_buffer( FT_Memory memory,
136 FT_Bitmap* bitmap,
137 FT_UInt xpixels,
138 FT_UInt ypixels )
139 {
140 FT_Error error;
141 unsigned int pitch;
142 unsigned int new_pitch;
143 FT_UInt bpp;
144 FT_UInt width, height;
145 unsigned char* buffer = NULL;
146
147
148 width = bitmap->width;
149 height = bitmap->rows;
150 pitch = (unsigned int)FT_ABS( bitmap->pitch );
151
152 switch ( bitmap->pixel_mode )
153 {
154 case FT_PIXEL_MODE_MONO:
155 bpp = 1;
156 new_pitch = ( width + xpixels + 7 ) >> 3;
157 break;
158 case FT_PIXEL_MODE_GRAY2:
159 bpp = 2;
160 new_pitch = ( width + xpixels + 3 ) >> 2;
161 break;
162 case FT_PIXEL_MODE_GRAY4:
163 bpp = 4;
164 new_pitch = ( width + xpixels + 1 ) >> 1;
165 break;
166 case FT_PIXEL_MODE_GRAY:
167 case FT_PIXEL_MODE_LCD:
168 case FT_PIXEL_MODE_LCD_V:
169 bpp = 8;
170 new_pitch = width + xpixels;
171 break;
172 default:
173 return FT_THROW( Invalid_Glyph_Format );
174 }
175
176 /* if no need to allocate memory */
177 if ( ypixels == 0 && new_pitch <= pitch )
178 {
179 /* zero the padding */
180 FT_UInt bit_width = pitch * 8;
181 FT_UInt bit_last = ( width + xpixels ) * bpp;
182
183
184 if ( bit_last < bit_width )
185 {
186 FT_Byte* line = bitmap->buffer + ( bit_last >> 3 );
187 FT_Byte* end = bitmap->buffer + pitch;
188 FT_UInt shift = bit_last & 7;
189 FT_UInt mask = 0xFF00U >> shift;
190 FT_UInt count = height;
191
192
193 for ( ; count > 0; count--, line += pitch, end += pitch )
194 {
195 FT_Byte* write = line;
196
197
198 if ( shift > 0 )
199 {
200 write[0] = (FT_Byte)( write[0] & mask );
201 write++;
202 }
203 if ( write < end )
204 FT_MEM_ZERO( write, end - write );
205 }
206 }
207
208 return FT_Err_Ok;
209 }
210
211 /* otherwise allocate new buffer */
212 if ( FT_QALLOC_MULT( buffer, bitmap->rows + ypixels, new_pitch ) )
213 return error;
214
215 /* new rows get added at the top of the bitmap, */
216 /* thus take care of the flow direction */
217 if ( bitmap->pitch > 0 )
218 {
219 FT_UInt len = ( width * bpp + 7 ) >> 3;
220
221 unsigned char* in = bitmap->buffer;
222 unsigned char* out = buffer;
223
224 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows;
225 unsigned int delta = new_pitch - len;
226
227
228 FT_MEM_ZERO( out, new_pitch * ypixels );
229 out += new_pitch * ypixels;
230
231 while ( in < limit )
232 {
233 FT_MEM_COPY( out, in, len );
234 in += pitch;
235 out += len;
236
237 /* we use FT_QALLOC_MULT, which doesn't zero out the buffer; */
238 /* consequently, we have to manually zero out the remaining bytes */
239 FT_MEM_ZERO( out, delta );
240 out += delta;
241 }
242 }
243 else
244 {
245 FT_UInt len = ( width * bpp + 7 ) >> 3;
246
247 unsigned char* in = bitmap->buffer;
248 unsigned char* out = buffer;
249
250 unsigned char* limit = bitmap->buffer + pitch * bitmap->rows;
251 unsigned int delta = new_pitch - len;
252
253
254 while ( in < limit )
255 {
256 FT_MEM_COPY( out, in, len );
257 in += pitch;
258 out += len;
259
260 FT_MEM_ZERO( out, delta );
261 out += delta;
262 }
263
264 FT_MEM_ZERO( out, new_pitch * ypixels );
265 }
266
267 FT_FREE( bitmap->buffer );
268 bitmap->buffer = buffer;
269
270 /* set pitch only, width and height are left untouched */
271 if ( bitmap->pitch < 0 )
272 bitmap->pitch = -(int)new_pitch;
273 else
274 bitmap->pitch = (int)new_pitch;
275
276 return FT_Err_Ok;
277 }
278
279
280 /* documentation is in ftbitmap.h */
281
282 FT_EXPORT_DEF( FT_Error )
283 FT_Bitmap_Embolden( FT_Library library,
284 FT_Bitmap* bitmap,
285 FT_Pos xStrength,
286 FT_Pos yStrength )
287 {
288 FT_Error error;
289 unsigned char* p;
290 FT_Int i, x, pitch;
291 FT_UInt y;
292 FT_Int xstr, ystr;
293
294
295 if ( !library )
296 return FT_THROW( Invalid_Library_Handle );
297
298 if ( !bitmap || !bitmap->buffer )
299 return FT_THROW( Invalid_Argument );
300
301 if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) ||
302 ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) )
303 return FT_THROW( Invalid_Argument );
304
305 xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6;
306 ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6;
307
308 if ( xstr == 0 && ystr == 0 )
309 return FT_Err_Ok;
310 else if ( xstr < 0 || ystr < 0 )
311 return FT_THROW( Invalid_Argument );
312
313 switch ( bitmap->pixel_mode )
314 {
315 case FT_PIXEL_MODE_GRAY2:
316 case FT_PIXEL_MODE_GRAY4:
317 {
318 FT_Bitmap tmp;
319
320
321 /* convert to 8bpp */
322 FT_Bitmap_Init( &tmp );
323 error = FT_Bitmap_Convert( library, bitmap, &tmp, 1 );
324 if ( error )
325 return error;
326
327 FT_Bitmap_Done( library, bitmap );
328 *bitmap = tmp;
329 }
330 break;
331
332 case FT_PIXEL_MODE_MONO:
333 if ( xstr > 8 )
334 xstr = 8;
335 break;
336
337 case FT_PIXEL_MODE_LCD:
338 xstr *= 3;
339 break;
340
341 case FT_PIXEL_MODE_LCD_V:
342 ystr *= 3;
343 break;
344
345 case FT_PIXEL_MODE_BGRA:
346 /* We don't embolden color glyphs. */
347 return FT_Err_Ok;
348 }
349
350 error = ft_bitmap_assure_buffer( library->memory, bitmap,
351 (FT_UInt)xstr, (FT_UInt)ystr );
352 if ( error )
353 return error;
354
355 /* take care of bitmap flow */
356 pitch = bitmap->pitch;
357 if ( pitch > 0 )
358 p = bitmap->buffer + pitch * ystr;
359 else
360 {
361 pitch = -pitch;
362 p = bitmap->buffer + (FT_UInt)pitch * ( bitmap->rows - 1 );
363 }
364
365 /* for each row */
366 for ( y = 0; y < bitmap->rows; y++ )
367 {
368 /*
369 * Horizontally:
370 *
371 * From the last pixel on, make each pixel or'ed with the
372 * `xstr' pixels before it.
373 */
374 for ( x = pitch - 1; x >= 0; x-- )
375 {
376 unsigned char tmp;
377
378
379 tmp = p[x];
380 for ( i = 1; i <= xstr; i++ )
381 {
382 if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO )
383 {
384 p[x] |= tmp >> i;
385
386 /* the maximum value of 8 for `xstr' comes from here */
387 if ( x > 0 )
388 p[x] |= p[x - 1] << ( 8 - i );
389
390#if 0
391 if ( p[x] == 0xFF )
392 break;
393#endif
394 }
395 else
396 {
397 if ( x - i >= 0 )
398 {
399 if ( p[x] + p[x - i] > bitmap->num_grays - 1 )
400 {
401 p[x] = (unsigned char)( bitmap->num_grays - 1 );
402 break;
403 }
404 else
405 {
406 p[x] = (unsigned char)( p[x] + p[x - i] );
407 if ( p[x] == bitmap->num_grays - 1 )
408 break;
409 }
410 }
411 else
412 break;
413 }
414 }
415 }
416
417 /*
418 * Vertically:
419 *
420 * Make the above `ystr' rows or'ed with it.
421 */
422 for ( x = 1; x <= ystr; x++ )
423 {
424 unsigned char* q;
425
426
427 q = p - bitmap->pitch * x;
428 for ( i = 0; i < pitch; i++ )
429 q[i] |= p[i];
430 }
431
432 p += bitmap->pitch;
433 }
434
435 bitmap->width += (FT_UInt)xstr;
436 bitmap->rows += (FT_UInt)ystr;
437
438 return FT_Err_Ok;
439 }
440
441
442 static FT_Byte
443 ft_gray_for_premultiplied_srgb_bgra( const FT_Byte* bgra )
444 {
445 FT_UInt a = bgra[3];
446 FT_UInt l;
447
448
449 /* Short-circuit transparent color to avoid division by zero. */
450 if ( !a )
451 return 0;
452
453 /*
454 * Luminosity for sRGB is defined using ~0.2126,0.7152,0.0722
455 * coefficients for RGB channels *on the linear colors*.
456 * A gamma of 2.2 is fair to assume. And then, we need to
457 * undo the premultiplication too.
458 *
459 * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#SideNotes
460 *
461 * We do the computation with integers only, applying a gamma of 2.0.
462 * We guarantee 32-bit arithmetic to avoid overflow but the resulting
463 * luminosity fits into 16 bits.
464 *
465 */
466
467 l = ( 4731UL /* 0.072186 * 65536 */ * bgra[0] * bgra[0] +
468 46868UL /* 0.715158 * 65536 */ * bgra[1] * bgra[1] +
469 13937UL /* 0.212656 * 65536 */ * bgra[2] * bgra[2] ) >> 16;
470
471 /*
472 * Final transparency can be determined as follows.
473 *
474 * - If alpha is zero, we want 0.
475 * - If alpha is zero and luminosity is zero, we want 255.
476 * - If alpha is zero and luminosity is one, we want 0.
477 *
478 * So the formula is a * (1 - l) = a - l * a.
479 *
480 * We still need to undo premultiplication by dividing l by a*a.
481 *
482 */
483
484 return (FT_Byte)( a - l / a );
485 }
486
487
488 /* documentation is in ftbitmap.h */
489
490 FT_EXPORT_DEF( FT_Error )
491 FT_Bitmap_Convert( FT_Library library,
492 const FT_Bitmap *source,
493 FT_Bitmap *target,
494 FT_Int alignment )
495 {
496 FT_Error error = FT_Err_Ok;
497 FT_Memory memory;
498
499 FT_Byte* s;
500 FT_Byte* t;
501
502
503 if ( !library )
504 return FT_THROW( Invalid_Library_Handle );
505
506 if ( !source || !target )
507 return FT_THROW( Invalid_Argument );
508
509 memory = library->memory;
510
511 switch ( source->pixel_mode )
512 {
513 case FT_PIXEL_MODE_MONO:
514 case FT_PIXEL_MODE_GRAY:
515 case FT_PIXEL_MODE_GRAY2:
516 case FT_PIXEL_MODE_GRAY4:
517 case FT_PIXEL_MODE_LCD:
518 case FT_PIXEL_MODE_LCD_V:
519 case FT_PIXEL_MODE_BGRA:
520 {
521 FT_Int width = (FT_Int)source->width;
522 FT_Int neg = ( target->pitch == 0 && source->pitch < 0 ) ||
523 target->pitch < 0;
524
525
526 FT_Bitmap_Done( library, target );
527
528 target->pixel_mode = FT_PIXEL_MODE_GRAY;
529 target->rows = source->rows;
530 target->width = source->width;
531
532 if ( alignment )
533 {
534 FT_Int rem = width % alignment;
535
536
537 if ( rem )
538 width = alignment > 0 ? width - rem + alignment
539 : width - rem - alignment;
540 }
541
542 if ( FT_QALLOC_MULT( target->buffer, target->rows, width ) )
543 return error;
544
545 target->pitch = neg ? -width : width;
546 }
547 break;
548
549 default:
550 error = FT_THROW( Invalid_Argument );
551 }
552
553 s = source->buffer;
554 t = target->buffer;
555
556 /* take care of bitmap flow */
557 if ( source->pitch < 0 )
558 s -= source->pitch * (FT_Int)( source->rows - 1 );
559 if ( target->pitch < 0 )
560 t -= target->pitch * (FT_Int)( target->rows - 1 );
561
562 switch ( source->pixel_mode )
563 {
564 case FT_PIXEL_MODE_MONO:
565 {
566 FT_UInt i;
567
568
569 target->num_grays = 2;
570
571 for ( i = source->rows; i > 0; i-- )
572 {
573 FT_Byte* ss = s;
574 FT_Byte* tt = t;
575 FT_UInt j;
576
577
578 /* get the full bytes */
579 for ( j = source->width >> 3; j > 0; j-- )
580 {
581 FT_Int val = ss[0]; /* avoid a byte->int cast on each line */
582
583
584 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 );
585 tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 );
586 tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 );
587 tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 );
588 tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 );
589 tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 );
590 tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 );
591 tt[7] = (FT_Byte)( val & 0x01 );
592
593 tt += 8;
594 ss += 1;
595 }
596
597 /* get remaining pixels (if any) */
598 j = source->width & 7;
599 if ( j > 0 )
600 {
601 FT_Int val = *ss;
602
603
604 for ( ; j > 0; j-- )
605 {
606 tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7);
607 val <<= 1;
608 tt += 1;
609 }
610 }
611
612 s += source->pitch;
613 t += target->pitch;
614 }
615 }
616 break;
617
618
619 case FT_PIXEL_MODE_GRAY:
620 case FT_PIXEL_MODE_LCD:
621 case FT_PIXEL_MODE_LCD_V:
622 {
623 FT_UInt width = source->width;
624 FT_UInt i;
625
626
627 target->num_grays = 256;
628
629 for ( i = source->rows; i > 0; i-- )
630 {
631 FT_ARRAY_COPY( t, s, width );
632
633 s += source->pitch;
634 t += target->pitch;
635 }
636 }
637 break;
638
639
640 case FT_PIXEL_MODE_GRAY2:
641 {
642 FT_UInt i;
643
644
645 target->num_grays = 4;
646
647 for ( i = source->rows; i > 0; i-- )
648 {
649 FT_Byte* ss = s;
650 FT_Byte* tt = t;
651 FT_UInt j;
652
653
654 /* get the full bytes */
655 for ( j = source->width >> 2; j > 0; j-- )
656 {
657 FT_Int val = ss[0];
658
659
660 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
661 tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 );
662 tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 );
663 tt[3] = (FT_Byte)( ( val & 0x03 ) );
664
665 ss += 1;
666 tt += 4;
667 }
668
669 j = source->width & 3;
670 if ( j > 0 )
671 {
672 FT_Int val = ss[0];
673
674
675 for ( ; j > 0; j-- )
676 {
677 tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
678 val <<= 2;
679 tt += 1;
680 }
681 }
682
683 s += source->pitch;
684 t += target->pitch;
685 }
686 }
687 break;
688
689
690 case FT_PIXEL_MODE_GRAY4:
691 {
692 FT_UInt i;
693
694
695 target->num_grays = 16;
696
697 for ( i = source->rows; i > 0; i-- )
698 {
699 FT_Byte* ss = s;
700 FT_Byte* tt = t;
701 FT_UInt j;
702
703
704 /* get the full bytes */
705 for ( j = source->width >> 1; j > 0; j-- )
706 {
707 FT_Int val = ss[0];
708
709
710 tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 );
711 tt[1] = (FT_Byte)( ( val & 0x0F ) );
712
713 ss += 1;
714 tt += 2;
715 }
716
717 if ( source->width & 1 )
718 tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 );
719
720 s += source->pitch;
721 t += target->pitch;
722 }
723 }
724 break;
725
726
727 case FT_PIXEL_MODE_BGRA:
728 {
729 FT_UInt i;
730
731
732 target->num_grays = 256;
733
734 for ( i = source->rows; i > 0; i-- )
735 {
736 FT_Byte* ss = s;
737 FT_Byte* tt = t;
738 FT_UInt j;
739
740
741 for ( j = source->width; j > 0; j-- )
742 {
743 tt[0] = ft_gray_for_premultiplied_srgb_bgra( ss );
744
745 ss += 4;
746 tt += 1;
747 }
748
749 s += source->pitch;
750 t += target->pitch;
751 }
752 }
753 break;
754
755 default:
756 ;
757 }
758
759 return error;
760 }
761
762
763 /* documentation is in ftbitmap.h */
764
765 FT_EXPORT_DEF( FT_Error )
766 FT_Bitmap_Blend( FT_Library library,
767 const FT_Bitmap* source_,
768 const FT_Vector source_offset_,
769 FT_Bitmap* target,
770 FT_Vector *atarget_offset,
771 FT_Color color )
772 {
773 FT_Error error = FT_Err_Ok;
774 FT_Memory memory;
775
776 FT_Bitmap source_bitmap;
777 const FT_Bitmap* source;
778
779 FT_Vector source_offset;
780 FT_Vector target_offset;
781
782 FT_Bool free_source_bitmap = 0;
783 FT_Bool free_target_bitmap_on_error = 0;
784
785 FT_Pos source_llx, source_lly, source_urx, source_ury;
786 FT_Pos target_llx, target_lly, target_urx, target_ury;
787 FT_Pos final_llx, final_lly, final_urx, final_ury;
788
789 unsigned int final_rows, final_width;
790 long x, y;
791
792
793 if ( !library || !target || !source_ || !atarget_offset )
794 return FT_THROW( Invalid_Argument );
795
796 memory = library->memory;
797
798 if ( !( target->pixel_mode == FT_PIXEL_MODE_NONE ||
799 ( target->pixel_mode == FT_PIXEL_MODE_BGRA &&
800 target->buffer ) ) )
801 return FT_THROW( Invalid_Argument );
802
803 if ( source_->pixel_mode == FT_PIXEL_MODE_NONE )
804 return FT_Err_Ok; /* nothing to do */
805
806 /* pitches must have the same sign */
807 if ( target->pixel_mode == FT_PIXEL_MODE_BGRA &&
808 ( source_->pitch ^ target->pitch ) < 0 )
809 return FT_THROW( Invalid_Argument );
810
811 if ( !( source_->width && source_->rows ) )
812 return FT_Err_Ok; /* nothing to do */
813
814 /* assure integer pixel offsets */
815 source_offset.x = FT_PIX_FLOOR( source_offset_.x );
816 source_offset.y = FT_PIX_FLOOR( source_offset_.y );
817 target_offset.x = FT_PIX_FLOOR( atarget_offset->x );
818 target_offset.y = FT_PIX_FLOOR( atarget_offset->y );
819
820 /* get source bitmap dimensions */
821 source_llx = source_offset.x;
822 if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y )
823 {
824 FT_TRACE5((
825 "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" ));
826 return FT_THROW( Invalid_Argument );
827 }
828 source_lly = source_offset.y - ( source_->rows << 6 );
829
830 if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx )
831 {
832 FT_TRACE5((
833 "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" ));
834 return FT_THROW( Invalid_Argument );
835 }
836 source_urx = source_llx + ( source_->width << 6 );
837 source_ury = source_offset.y;
838
839 /* get target bitmap dimensions */
840 if ( target->width && target->rows )
841 {
842 target_llx = target_offset.x;
843 if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y )
844 {
845 FT_TRACE5((
846 "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" ));
847 return FT_THROW( Invalid_Argument );
848 }
849 target_lly = target_offset.y - ( target->rows << 6 );
850
851 if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx )
852 {
853 FT_TRACE5((
854 "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" ));
855 return FT_THROW( Invalid_Argument );
856 }
857 target_urx = target_llx + ( target->width << 6 );
858 target_ury = target_offset.y;
859 }
860 else
861 {
862 target_llx = FT_LONG_MAX;
863 target_lly = FT_LONG_MAX;
864 target_urx = FT_LONG_MIN;
865 target_ury = FT_LONG_MIN;
866 }
867
868 /* compute final bitmap dimensions */
869 final_llx = FT_MIN( source_llx, target_llx );
870 final_lly = FT_MIN( source_lly, target_lly );
871 final_urx = FT_MAX( source_urx, target_urx );
872 final_ury = FT_MAX( source_ury, target_ury );
873
874 final_width = ( final_urx - final_llx ) >> 6;
875 final_rows = ( final_ury - final_lly ) >> 6;
876
877#ifdef FT_DEBUG_LEVEL_TRACE
878 FT_TRACE5(( "FT_Bitmap_Blend:\n" ));
879 FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n",
880 source_llx / 64, source_lly / 64,
881 source_urx / 64, source_ury / 64,
882 source_->width, source_->rows ));
883
884 if ( target->width && target->rows )
885 FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n",
886 target_llx / 64, target_lly / 64,
887 target_urx / 64, target_ury / 64,
888 target->width, target->rows ));
889 else
890 FT_TRACE5(( " target bitmap: empty\n" ));
891
892 if ( final_width && final_rows )
893 FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n",
894 final_llx / 64, final_lly / 64,
895 final_urx / 64, final_ury / 64,
896 final_width, final_rows ));
897 else
898 FT_TRACE5(( " final bitmap: empty\n" ));
899#endif /* FT_DEBUG_LEVEL_TRACE */
900
901 if ( !( final_width && final_rows ) )
902 return FT_Err_Ok; /* nothing to do */
903
904 /* for blending, set offset vector of final bitmap */
905 /* temporarily to (0,0) */
906 source_llx -= final_llx;
907 source_lly -= final_lly;
908
909 if ( target->width && target->rows )
910 {
911 target_llx -= final_llx;
912 target_lly -= final_lly;
913 }
914
915 /* set up target bitmap */
916 if ( target->pixel_mode == FT_PIXEL_MODE_NONE )
917 {
918 /* create new empty bitmap */
919 target->width = final_width;
920 target->rows = final_rows;
921 target->pixel_mode = FT_PIXEL_MODE_BGRA;
922 target->pitch = (int)final_width * 4;
923 target->num_grays = 256;
924
925 if ( FT_LONG_MAX / target->pitch < (int)target->rows )
926 {
927 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n",
928 final_width, final_rows ));
929 return FT_THROW( Invalid_Argument );
930 }
931
932 if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) )
933 return error;
934
935 free_target_bitmap_on_error = 1;
936 }
937 else if ( target->width != final_width ||
938 target->rows != final_rows )
939 {
940 /* adjust old bitmap to enlarged size */
941 int pitch, new_pitch;
942
943 unsigned char* buffer = NULL;
944
945
946 pitch = target->pitch;
947
948 if ( pitch < 0 )
949 pitch = -pitch;
950
951 new_pitch = (int)final_width * 4;
952
953 if ( FT_LONG_MAX / new_pitch < (int)final_rows )
954 {
955 FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n",
956 final_width, final_rows ));
957 return FT_THROW( Invalid_Argument );
958 }
959
960 /* TODO: provide an in-buffer solution for large bitmaps */
961 /* to avoid allocation of a new buffer */
962 if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) )
963 goto Error;
964
965 /* copy data to new buffer */
966 x = target_llx >> 6;
967 y = target_lly >> 6;
968
969 /* the bitmap flow is from top to bottom, */
970 /* but y is measured from bottom to top */
971 if ( target->pitch < 0 )
972 {
973 /* XXX */
974 }
975 else
976 {
977 unsigned char* p =
978 target->buffer;
979 unsigned char* q =
980 buffer +
981 ( final_rows - y - target->rows ) * new_pitch +
982 x * 4;
983 unsigned char* limit_p =
984 p + pitch * (int)target->rows;
985
986
987 while ( p < limit_p )
988 {
989 FT_MEM_COPY( q, p, pitch );
990
991 p += pitch;
992 q += new_pitch;
993 }
994 }
995
996 FT_FREE( target->buffer );
997
998 target->width = final_width;
999 target->rows = final_rows;
1000
1001 if ( target->pitch < 0 )
1002 target->pitch = -new_pitch;
1003 else
1004 target->pitch = new_pitch;
1005
1006 target->buffer = buffer;
1007 }
1008
1009 /* adjust source bitmap if necessary */
1010 if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY )
1011 {
1012 FT_Bitmap_Init( &source_bitmap );
1013 error = FT_Bitmap_Convert( library, source_, &source_bitmap, 1 );
1014 if ( error )
1015 goto Error;
1016
1017 source = &source_bitmap;
1018 free_source_bitmap = 1;
1019 }
1020 else
1021 source = source_;
1022
1023 /* do blending; the code below returns pre-multiplied channels, */
1024 /* similar to what FreeType gets from `CBDT' tables */
1025 x = source_llx >> 6;
1026 y = source_lly >> 6;
1027
1028 /* the bitmap flow is from top to bottom, */
1029 /* but y is measured from bottom to top */
1030 if ( target->pitch < 0 )
1031 {
1032 /* XXX */
1033 }
1034 else
1035 {
1036 unsigned char* p =
1037 source->buffer;
1038 unsigned char* q =
1039 target->buffer +
1040 ( target->rows - y - source->rows ) * target->pitch +
1041 x * 4;
1042 unsigned char* limit_p =
1043 p + source->pitch * (int)source->rows;
1044
1045
1046 while ( p < limit_p )
1047 {
1048 unsigned char* r = p;
1049 unsigned char* s = q;
1050 unsigned char* limit_r = r + source->width;
1051
1052
1053 while ( r < limit_r )
1054 {
1055 int aa = *r++;
1056 int fa = color.alpha * aa / 255;
1057
1058 int fb = color.blue * fa / 255;
1059 int fg = color.green * fa / 255;
1060 int fr = color.red * fa / 255;
1061
1062 int ba2 = 255 - fa;
1063
1064 int bb = s[0];
1065 int bg = s[1];
1066 int br = s[2];
1067 int ba = s[3];
1068
1069
1070 *s++ = (unsigned char)( bb * ba2 / 255 + fb );
1071 *s++ = (unsigned char)( bg * ba2 / 255 + fg );
1072 *s++ = (unsigned char)( br * ba2 / 255 + fr );
1073 *s++ = (unsigned char)( ba * ba2 / 255 + fa );
1074 }
1075
1076 p += source->pitch;
1077 q += target->pitch;
1078 }
1079 }
1080
1081 atarget_offset->x = final_llx;
1082 atarget_offset->y = final_lly + ( final_rows << 6 );
1083
1084 Error:
1085 if ( error && free_target_bitmap_on_error )
1086 FT_Bitmap_Done( library, target );
1087
1088 if ( free_source_bitmap )
1089 FT_Bitmap_Done( library, &source_bitmap );
1090
1091 return error;
1092 }
1093
1094
1095 /* documentation is in ftbitmap.h */
1096
1097 FT_EXPORT_DEF( FT_Error )
1098 FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot )
1099 {
1100 if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP &&
1101 !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
1102 {
1103 FT_Bitmap bitmap;
1104 FT_Error error;
1105
1106
1107 FT_Bitmap_Init( &bitmap );
1108 error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap );
1109 if ( error )
1110 return error;
1111
1112 slot->bitmap = bitmap;
1113 slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
1114 }
1115
1116 return FT_Err_Ok;
1117 }
1118
1119
1120 /* documentation is in ftbitmap.h */
1121
1122 FT_EXPORT_DEF( FT_Error )
1123 FT_Bitmap_Done( FT_Library library,
1124 FT_Bitmap *bitmap )
1125 {
1126 FT_Memory memory;
1127
1128
1129 if ( !library )
1130 return FT_THROW( Invalid_Library_Handle );
1131
1132 if ( !bitmap )
1133 return FT_THROW( Invalid_Argument );
1134
1135 memory = library->memory;
1136
1137 FT_FREE( bitmap->buffer );
1138 *bitmap = null_bitmap;
1139
1140 return FT_Err_Ok;
1141 }
1142
1143
1144/* END */
1145