1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
7 // Functions related to bitmaps and de_bitmap.
9 #define DE_NOT_IN_MODULE
10 #include "deark-config.h"
11 #include "deark-private.h"
13 int de_good_image_dimensions_noerr(deark
*c
, i64 w
, i64 h
)
15 if(w
<1 || h
<1 || w
>c
->max_image_dimension
|| h
>c
->max_image_dimension
) {
21 int de_good_image_dimensions(deark
*c
, i64 w
, i64 h
)
23 if(!de_good_image_dimensions_noerr(c
, w
, h
)) {
24 de_err(c
, "Bad or unsupported image dimensions (%d"DE_CHAR_TIMES
"%d)",
31 #define DE_MAX_IMAGES_PER_FILE 10000
33 // This is meant as a sanity check for fields that indicate how many images
35 // TODO: It is not used very consistently, and should probably be re-thought
37 int de_good_image_count(deark
*c
, i64 n
)
41 maximages
= DE_MAX_IMAGES_PER_FILE
;
42 if(c
->max_output_files
>DE_MAX_IMAGES_PER_FILE
) {
43 maximages
= c
->max_output_files
;
46 if(n
<0 || n
>maximages
) {
47 de_err(c
, "Bad or unsupported number of images (%d)", (int)n
);
53 int de_is_grayscale_palette(const de_color
*pal
, i64 num_entries
)
58 for(k
=0; k
<num_entries
; k
++) {
59 cr
= DE_COLOR_R(pal
[k
]);
60 if(cr
!= DE_COLOR_G(pal
[k
])) return 0;
61 if(cr
!= DE_COLOR_B(pal
[k
])) return 0;
66 static void de_bitmap_free_pixels(de_bitmap
*b
)
72 de_free(c
, b
->bitmap
);
79 static void de_bitmap_alloc_pixels(de_bitmap
*img
)
82 de_bitmap_free_pixels(img
);
85 if(!de_good_image_dimensions(img
->c
, img
->width
, img
->height
)) {
86 // This function is not allowed to fail. If something goes wrong, create
87 // a dummy image, and set invalid_image_flag.
88 img
->invalid_image_flag
= 1;
94 img
->bitmap_size
= (img
->width
*img
->bytes_per_pixel
) * img
->height
;
95 img
->bitmap
= de_malloc(img
->c
, img
->bitmap_size
);
98 struct image_scan_results
{
101 int has_visible_pixels
;
104 // Scan the image's pixels, and report whether any are transparent, etc.
105 static void scan_image(de_bitmap
*img
, struct image_scan_results
*isres
)
109 de_colorsample a
, r
, g
, b
;
111 de_zeromem(isres
, sizeof(struct image_scan_results
));
112 if(img
->bytes_per_pixel
==1) {
113 // No reason to scan opaque grayscale images.
114 isres
->has_visible_pixels
= 1;
117 for(j
=0; j
<img
->height
; j
++) {
118 for(i
=0; i
<img
->width
; i
++) {
119 clr
= de_bitmap_getpixel(img
, i
, j
);
120 // TODO: Optimize these tests. We check for too many things we
121 // already know the answer to.
126 if(!isres
->has_visible_pixels
&& a
!=0) {
127 isres
->has_visible_pixels
= 1;
129 if(!isres
->has_trns
&& a
<255) {
132 if(!isres
->has_color
&& img
->bytes_per_pixel
>=3 &&
133 ((g
!=r
|| b
!=r
) && a
!=0) )
135 isres
->has_color
= 1;
139 // After each row, test whether we've learned everything we can learn
141 if((isres
->has_trns
|| img
->bytes_per_pixel
==1 || img
->bytes_per_pixel
==3) &&
142 (isres
->has_visible_pixels
) &&
143 (isres
->has_color
|| img
->bytes_per_pixel
<=2))
150 static de_bitmap
*de_bitmap_create_noinit(deark
*c
);
152 // Clone an existing bitmap's metadata, but don't allocate the new pixels.
153 // The caller can then change the bytes_per_pixel if desired.
154 static de_bitmap
*de_bitmap_clone_noalloc(de_bitmap
*img1
)
158 img2
= de_bitmap_create_noinit(img1
->c
);
159 de_memcpy(img2
, img1
, sizeof(de_bitmap
));
161 img2
->bitmap_size
= 0;
165 static de_bitmap
*de_bitmap_clone(de_bitmap
*img1
)
170 img2
= de_bitmap_clone_noalloc(img1
);
171 de_bitmap_alloc_pixels(img2
);
172 nbytes_to_copy
= de_min_int(img2
->bitmap_size
, img1
->bitmap_size
);
173 de_memcpy(img2
->bitmap
, img1
->bitmap
, (size_t)nbytes_to_copy
);
177 // Returns NULL if there's no need to optimize the image
178 static de_bitmap
*get_optimized_image(de_bitmap
*img1
)
180 struct image_scan_results isres
;
181 int opt_bytes_per_pixel
;
184 scan_image(img1
, &isres
);
185 opt_bytes_per_pixel
= isres
.has_color
? 3 : 1;
186 if(isres
.has_trns
) opt_bytes_per_pixel
++;
188 if(opt_bytes_per_pixel
>=img1
->bytes_per_pixel
) {
192 optimg
= de_bitmap_clone_noalloc(img1
);
193 optimg
->bytes_per_pixel
= opt_bytes_per_pixel
;
194 de_bitmap_copy_rect(img1
, optimg
, 0, 0, img1
->width
, img1
->height
, 0, 0, 0);
198 // When calling this function, the "name" data associated with fi, if set, should
199 // be set to something like a filename, but *without* a final ".png" extension.
200 // Image-specific createflags:
201 // - DE_CREATEFLAG_OPT_IMAGE
202 // - DE_CREATEFLAG_FLIP_IMAGE
203 // Write the rows in reverse order ("bottom-up"). This affects only the pixels,
204 // not the finfo metadata (e.g. hotspot). It's equivalent to flipping the image
205 // immediately before writing it, then flipping it back immediately after.
206 void de_bitmap_write_to_file_finfo(de_bitmap
*img
, de_finfo
*fi
,
207 unsigned int createflags
)
211 de_bitmap
*optimg
= NULL
;
215 if(img
->invalid_image_flag
) return;
217 if(!img
->bitmap
) de_bitmap_alloc_pixels(img
);
219 if(createflags
& DE_CREATEFLAG_OPT_IMAGE
) {
220 // This should probably be the default, but our optimization routine
221 // isn't very efficient, and wouldn't change anything in most cases.
222 optimg
= get_optimized_image(img
);
224 de_dbg3(c
, "reducing image depth (%d->%d)", img
->bytes_per_pixel
,
225 optimg
->bytes_per_pixel
);
229 f
= dbuf_create_output_file(c
, "png", fi
, createflags
);
231 de_write_png(c
, optimg
, f
, createflags
);
234 de_write_png(c
, img
, f
, createflags
);
238 if(optimg
) de_bitmap_destroy(optimg
);
241 // "token" - A (UTF-8) filename component, like "output.000.<token>.png".
243 void de_bitmap_write_to_file(de_bitmap
*img
, const char *token
,
244 unsigned int createflags
)
248 if(token
&& token
[0]) {
249 de_finfo
*tmpfi
= de_finfo_create(c
);
250 de_finfo_set_name_from_sz(c
, tmpfi
, token
, 0, DE_ENCODING_UTF8
);
251 de_bitmap_write_to_file_finfo(img
, tmpfi
, createflags
);
252 de_finfo_destroy(c
, tmpfi
);
255 de_bitmap_write_to_file_finfo(img
, NULL
, createflags
);
259 // samplenum 0=Red, 1=Green, 2=Blue, 3=Alpha
260 void de_bitmap_setsample(de_bitmap
*img
, i64 x
, i64 y
,
261 i64 samplenum
, de_colorsample v
)
265 if(!img
->bitmap
) de_bitmap_alloc_pixels(img
);
266 if(!img
->bitmap
) return;
267 if(x
<0 || y
<0 || x
>=img
->width
|| y
>=img
->height
) return;
268 if(samplenum
<0 || samplenum
>3) return;
269 pos
= (img
->width
*img
->bytes_per_pixel
)*y
+ img
->bytes_per_pixel
*x
;
271 switch(img
->bytes_per_pixel
) {
274 img
->bitmap
[pos
] = v
;
277 case 2: // gray+alpha
279 img
->bitmap
[pos
+1] = v
;
282 img
->bitmap
[pos
] = v
;
287 img
->bitmap
[pos
+samplenum
] = v
;
291 img
->bitmap
[pos
+samplenum
] = v
;
296 void de_bitmap_setpixel_gray(de_bitmap
*img
, i64 x
, i64 y
, de_colorsample v
)
300 if(!img
->bitmap
) de_bitmap_alloc_pixels(img
);
301 if(!img
->bitmap
) return;
302 if(x
<0 || y
<0 || x
>=img
->width
|| y
>=img
->height
) return;
303 pos
= (img
->width
*img
->bytes_per_pixel
)*y
+ img
->bytes_per_pixel
*x
;
305 img
->bitmap
[pos
] = v
;
306 switch(img
->bytes_per_pixel
) {
307 case 2: // gray+alpha
308 img
->bitmap
[pos
+1] = 255;
311 img
->bitmap
[pos
+1] = v
;
312 img
->bitmap
[pos
+2] = v
;
315 img
->bitmap
[pos
+1] = v
;
316 img
->bitmap
[pos
+2] = v
;
317 img
->bitmap
[pos
+3] = 255;
322 // TODO: Decide if this should just be an alias of setpixel_rgba, or if it will
323 // force colors to be opaque.
324 void de_bitmap_setpixel_rgb(de_bitmap
*img
, i64 x
, i64 y
,
327 de_bitmap_setpixel_rgba(img
, x
, y
, color
);
330 void de_bitmap_setpixel_rgba(de_bitmap
*img
, i64 x
, i64 y
,
335 if(!img
->bitmap
) de_bitmap_alloc_pixels(img
);
336 if(!img
->bitmap
) return;
337 if(x
<0 || y
<0 || x
>=img
->width
|| y
>=img
->height
) return;
338 pos
= (img
->width
*img
->bytes_per_pixel
)*y
+ img
->bytes_per_pixel
*x
;
340 switch(img
->bytes_per_pixel
) {
342 img
->bitmap
[pos
] = DE_COLOR_R(color
);
343 img
->bitmap
[pos
+1] = DE_COLOR_G(color
);
344 img
->bitmap
[pos
+2] = DE_COLOR_B(color
);
345 img
->bitmap
[pos
+3] = DE_COLOR_A(color
);
348 img
->bitmap
[pos
] = DE_COLOR_R(color
);
349 img
->bitmap
[pos
+1] = DE_COLOR_G(color
);
350 img
->bitmap
[pos
+2] = DE_COLOR_B(color
);
353 img
->bitmap
[pos
] = DE_COLOR_G(color
);
354 img
->bitmap
[pos
+1] = DE_COLOR_A(color
);
357 // TODO: We could do real grayscale conversion, but for now we
358 // assume this won't happen, or that if it does the color given to
359 // us is a gray shade.
360 img
->bitmap
[pos
] = DE_COLOR_G(color
);
365 de_color
de_bitmap_getpixel(de_bitmap
*img
, i64 x
, i64 y
)
370 if(!img
->bitmap
) return 0;
371 if(x
<0 || y
<0 || x
>=img
->width
|| y
>=img
->height
) return 0;
372 pos
= (img
->width
*img
->bytes_per_pixel
)*y
+ img
->bytes_per_pixel
*x
;
374 switch(img
->bytes_per_pixel
) {
376 return DE_MAKE_RGBA(img
->bitmap
[pos
], img
->bitmap
[pos
+1],
377 img
->bitmap
[pos
+2], img
->bitmap
[pos
+3]);
379 return DE_MAKE_RGBA(img
->bitmap
[pos
], img
->bitmap
[pos
+1],
380 img
->bitmap
[pos
+2], 0xff);
383 return DE_MAKE_RGBA(img
->bitmap
[pos
], img
->bitmap
[pos
],
384 img
->bitmap
[pos
], img
->bitmap
[pos
+1]);
387 return DE_MAKE_RGBA(img
->bitmap
[pos
], img
->bitmap
[pos
],
388 img
->bitmap
[pos
], 0xff);
394 static de_bitmap
*de_bitmap_create_noinit(deark
*c
)
397 img
= de_malloc(c
, sizeof(de_bitmap
));
402 de_bitmap
*de_bitmap_create(deark
*c
, i64 width
, i64 height
, int bypp
)
405 img
= de_bitmap_create_noinit(c
);
407 img
->unpadded_width
= width
;
408 img
->height
= height
;
409 img
->bytes_per_pixel
= bypp
;
410 //img->rowspan = img->width * img->bytes_per_pixel;
414 de_bitmap
*de_bitmap_create2(deark
*c
, i64 npwidth
, i64 pdwidth
, i64 height
, int bypp
)
418 if(pdwidth
<npwidth
) pdwidth
= npwidth
;
420 img
= de_bitmap_create(c
, pdwidth
, height
, bypp
);
422 if(npwidth
>0 && npwidth
<img
->width
) {
423 img
->unpadded_width
= npwidth
;
429 void de_bitmap_destroy(de_bitmap
*b
)
434 de_bitmap_free_pixels(b
);
439 u8
de_get_bits_symbol(dbuf
*f
, i64 bps
, i64 rowstart
, i64 index
)
447 byte_offset
= rowstart
+ index
/8;
448 b
= dbuf_getbyte(f
, byte_offset
);
449 x
= (b
>> (7 - index
%8)) & 0x01;
452 byte_offset
= rowstart
+ index
/4;
453 b
= dbuf_getbyte(f
, byte_offset
);
454 x
= (b
>> (2 * (3 - index
%4))) & 0x03;
457 byte_offset
= rowstart
+ index
/2;
458 b
= dbuf_getbyte(f
, byte_offset
);
459 x
= (b
>> (4 * (1 - index
%2))) & 0x0f;
462 byte_offset
= rowstart
+ index
;
463 x
= dbuf_getbyte(f
, byte_offset
);
468 // Like de_get_bits_symbol, but with LSB-first bit order
469 u8
de_get_bits_symbol_lsb(dbuf
*f
, i64 bps
, i64 rowstart
, i64 index
)
477 byte_offset
= rowstart
+ index
/8;
478 b
= dbuf_getbyte(f
, byte_offset
);
479 x
= (b
>> (index
%8)) & 0x01;
482 byte_offset
= rowstart
+ index
/4;
483 b
= dbuf_getbyte(f
, byte_offset
);
484 x
= (b
>> (2 * (index
%4))) & 0x03;
487 byte_offset
= rowstart
+ index
/2;
488 b
= dbuf_getbyte(f
, byte_offset
);
489 x
= (b
>> (4 * (index
%2))) & 0x0f;
492 byte_offset
= rowstart
+ index
;
493 x
= dbuf_getbyte(f
, byte_offset
);
498 // Read a symbol (up to 8 bits) that starts at an arbitrary bit position.
499 // It may span (two) bytes.
500 u8
de_get_bits_symbol2(dbuf
*f
, int nbits
, i64 bytepos
, i64 bitpos
)
503 int bits_in_first_byte
;
504 int bits_in_second_byte
;
506 bits_in_first_byte
= 8-(bitpos
%8);
508 b0
= dbuf_getbyte(f
, bytepos
+ bitpos
/8);
510 if(bits_in_first_byte
<8) {
511 b0
&= (0xff >> (8-bits_in_first_byte
)); // Zero out insignificant bits
514 if(bits_in_first_byte
== nbits
) {
515 // First byte has all the bits
518 else if(bits_in_first_byte
>= nbits
) {
519 // First byte has all the bits
520 return b0
>> (bits_in_first_byte
- nbits
);
523 bits_in_second_byte
= nbits
- bits_in_first_byte
;
524 b1
= dbuf_getbyte(f
, bytepos
+ bitpos
/8 +1);
526 return (b0
<<bits_in_second_byte
) | (b1
>>(8-bits_in_second_byte
));
529 void de_convert_row_bilevel(dbuf
*f
, i64 fpos
, de_bitmap
*img
,
530 i64 rownum
, unsigned int flags
)
537 if(flags
& DE_CVTF_WHITEISZERO
) {
538 white
= 0; black
= 255;
541 black
= 0; white
= 255;
544 for(i
=0; i
<img
->width
; i
++) {
545 b
= dbuf_getbyte(f
, fpos
+ i
/8);
546 if(flags
& DE_CVTF_LSBFIRST
)
547 x
= (b
>> (i
%8)) & 0x01;
549 x
= (b
>> (7 - i
%8)) & 0x01;
550 de_bitmap_setpixel_gray(img
, i
, rownum
, x
? white
: black
);
554 void de_convert_image_bilevel(dbuf
*f
, i64 fpos
, i64 rowspan
,
555 de_bitmap
*img
, unsigned int flags
)
559 for(j
=0; j
<img
->height
; j
++) {
560 de_convert_row_bilevel(f
, fpos
+j
*rowspan
, img
, j
, flags
);
564 // TODO: Review everything using this function, and convert to ..._bilevel2()
566 // Maybe remove/rename this function.
567 void de_convert_and_write_image_bilevel(dbuf
*f
, i64 fpos
,
568 i64 width
, i64 height
, i64 rowspan
, unsigned int cvtflags
,
569 de_finfo
*fi
, unsigned int createflags
)
571 de_bitmap
*img
= NULL
;
574 if(!de_good_image_dimensions(c
, width
, height
)) return;
576 img
= de_bitmap_create(c
, width
, height
, 1);
577 de_convert_image_bilevel(f
, fpos
, rowspan
, img
, cvtflags
);
578 de_bitmap_write_to_file_finfo(img
, fi
, createflags
);
579 de_bitmap_destroy(img
);
582 // This function automatically handles padding pixels, for the -padpix option.
583 // This means the "rowspan" param cannot be used to do clever things --
584 // there cannot be any data between the rows, other than padding bits.
585 void de_convert_and_write_image_bilevel2(dbuf
*f
, i64 fpos
,
586 i64 width
, i64 height
, i64 rowspan
, unsigned int cvtflags
,
587 de_finfo
*fi
, unsigned int createflags
)
589 de_bitmap
*img
= NULL
;
592 if(!de_good_image_dimensions(c
, width
, height
)) return;
593 img
= de_bitmap_create2(c
, width
, rowspan
*8, height
, 1);
594 de_convert_image_bilevel(f
, fpos
, rowspan
, img
, cvtflags
);
595 de_bitmap_write_to_file_finfo(img
, fi
, createflags
);
596 de_bitmap_destroy(img
);
599 // Read a palette of 24-bit RGB colors.
600 // flags = flags used by dbuf_getRGB()
601 void de_read_palette_rgb(dbuf
*f
,
602 i64 fpos
, i64 num_entries
, i64 entryspan
,
603 de_color
*pal
, i64 ncolors_in_pal
,
608 if(num_entries
> ncolors_in_pal
) num_entries
= ncolors_in_pal
;
609 for(k
=0; k
<num_entries
; k
++) {
610 pal
[k
] = dbuf_getRGB(f
, fpos
+ k
*entryspan
, flags
);
611 de_dbg_pal_entry(f
->c
, k
, pal
[k
]);
615 void de_convert_image_paletted(dbuf
*f
, i64 fpos
,
616 i64 bpp
, i64 rowspan
, const de_color
*pal
,
617 de_bitmap
*img
, unsigned int flags
)
622 if(bpp
!=1 && bpp
!=2 && bpp
!=4 && bpp
!=8) return;
623 if(!de_good_image_dimensions_noerr(f
->c
, img
->width
, img
->height
)) return;
625 for(j
=0; j
<img
->height
; j
++) {
626 for(i
=0; i
<img
->width
; i
++) {
627 palent
= (unsigned int)de_get_bits_symbol(f
, bpp
, fpos
+j
*rowspan
, i
);
628 de_bitmap_setpixel_rgba(img
, i
, j
, pal
[palent
]);
633 void de_convert_image_rgb(dbuf
*f
, i64 fpos
,
634 i64 rowspan
, i64 pixelspan
, de_bitmap
*img
, unsigned int flags
)
639 for(j
=0; j
<img
->height
; j
++) {
640 for(i
=0; i
<img
->width
; i
++) {
641 clr
= dbuf_getRGB(f
, fpos
+ j
*rowspan
+ i
*pixelspan
, flags
);
642 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
647 // Turn padding pixels into real pixels.
648 static void de_bitmap_apply_padding(de_bitmap
*img
)
650 if(img
->unpadded_width
!= img
->width
) {
651 img
->unpadded_width
= img
->width
;
655 // TODO: This function could be made more efficient.
656 void de_bitmap_flip(de_bitmap
*img
)
663 for(j
=0; j
<nr
; j
++) {
667 row2
= img
->height
-1-j
;
669 for(i
=0; i
<img
->width
; i
++) {
672 tmp1
= de_bitmap_getpixel(img
, i
, row1
);
673 tmp2
= de_bitmap_getpixel(img
, i
, row2
);
674 if(tmp1
==tmp2
) continue;
675 de_bitmap_setpixel_rgba(img
, i
, row2
, tmp1
);
676 de_bitmap_setpixel_rgba(img
, i
, row1
, tmp2
);
681 // Not recommended for use with padded bitmaps (e.g. those created with
682 // de_bitmap_create2()). We don't support padding pixels on the left, so we can't
683 // truly mirror such an image. Current behavior is to turn padding pixels into
685 void de_bitmap_mirror(de_bitmap
*img
)
690 de_bitmap_apply_padding(img
);
693 for(j
=0; j
<img
->height
; j
++) {
694 for(i
=0; i
<nc
; i
++) {
699 col2
= img
->width
-1-i
;
701 tmp1
= de_bitmap_getpixel(img
, col1
, j
);
702 tmp2
= de_bitmap_getpixel(img
, col2
, j
);
703 if(tmp1
==tmp2
) continue;
704 de_bitmap_setpixel_rgba(img
, col2
, j
, tmp1
);
705 de_bitmap_setpixel_rgba(img
, col1
, j
, tmp2
);
710 // Transpose (flip over the line y=x) a square bitmap.
711 static void bitmap_transpose_square(de_bitmap
*img
)
715 for(j
=0; j
<img
->height
; j
++) {
719 tmp1
= de_bitmap_getpixel(img
, i
, j
);
720 tmp2
= de_bitmap_getpixel(img
, j
, i
);
721 if(tmp1
==tmp2
) continue;
722 de_bitmap_setpixel_rgba(img
, j
, i
, tmp1
);
723 de_bitmap_setpixel_rgba(img
, i
, j
, tmp2
);
728 // Transpose (flip over the line y=x) a bitmap.
729 // Not recommended for use with padded bitmaps (e.g. those created with
730 // de_bitmap_create2()).
731 void de_bitmap_transpose(de_bitmap
*img
)
734 de_bitmap
*imgtmp
= NULL
;
736 de_bitmap_apply_padding(img
);
738 if(img
->width
== img
->height
) {
739 bitmap_transpose_square(img
);
743 imgtmp
= de_bitmap_clone(img
);
745 de_bitmap_free_pixels(img
);
746 img
->width
= imgtmp
->height
;
747 img
->unpadded_width
= imgtmp
->height
;
748 img
->height
= imgtmp
->width
;
750 for(j
=0; j
<img
->height
; j
++) {
751 for(i
=0; i
<img
->width
; i
++) {
754 tmp1
= de_bitmap_getpixel(imgtmp
, j
, i
);
755 de_bitmap_setpixel_rgba(img
, i
, j
, tmp1
);
760 if(imgtmp
) de_bitmap_destroy(imgtmp
);
763 // Paint a solid, solid-color rectangle onto an image.
764 // (Pixels will be replaced, not merged.)
765 void de_bitmap_rect(de_bitmap
*img
,
766 i64 xpos
, i64 ypos
, i64 width
, i64 height
,
767 de_color clr
, unsigned int flags
)
771 for(j
=0; j
<height
; j
++) {
772 for(i
=0; i
<width
; i
++) {
773 de_bitmap_setpixel_rgba(img
, xpos
+i
, ypos
+j
, clr
);
778 // Paint or copy (all or part of) srcimg onto dstimg.
779 // If srcimg and dstimg are the same image, the source and destination
780 // rectangles must not overlap.
782 // DE_BITMAPFLAG_MERGE - Merge transparent pixels (partially supported)
783 void de_bitmap_copy_rect(de_bitmap
*srcimg
, de_bitmap
*dstimg
,
784 i64 srcxpos
, i64 srcypos
, i64 width
, i64 height
,
785 i64 dstxpos
, i64 dstypos
, unsigned int flags
)
788 de_color dst_clr
, src_clr
, clr
;
789 de_colorsample src_a
;
791 for(j
=0; j
<height
; j
++) {
792 for(i
=0; i
<width
; i
++) {
793 src_clr
= de_bitmap_getpixel(srcimg
, srcxpos
+i
, srcypos
+j
);
794 if(!(flags
&DE_BITMAPFLAG_MERGE
)) {
798 src_a
= DE_COLOR_A(src_clr
);
800 // TODO: Support partial transparency (of both foreground and
801 // background, ideally)
805 dst_clr
= de_bitmap_getpixel(dstimg
, dstxpos
+i
, dstypos
+j
);
809 de_bitmap_setpixel_rgba(dstimg
, dstxpos
+i
, dstypos
+j
, clr
);
814 void de_bitmap_apply_mask(de_bitmap
*fg
, de_bitmap
*mask
,
821 for(j
=0; j
<fg
->height
&& j
<mask
->height
; j
++) {
822 for(i
=0; i
<fg
->width
&& i
<mask
->width
; i
++) {
823 clr
= de_bitmap_getpixel(mask
, i
, j
);
825 if(flags
&DE_BITMAPFLAG_WHITEISTRNS
)
827 de_bitmap_setsample(fg
, i
, j
, 3, a
);
832 void de_bitmap_remove_alpha(de_bitmap
*img
)
837 if(img
->bytes_per_pixel
!=2 && img
->bytes_per_pixel
!=4) return;
839 // Note that the format conversion is done in-place. The extra memory used
840 // by the alpha channel is not de-allocated.
841 for(j
=0; j
<img
->height
; j
++) {
842 for(i
=0; i
<img
->width
; i
++) {
843 for(k
=0; k
<(i64
)img
->bytes_per_pixel
-1; k
++) {
844 img
->bitmap
[(j
*img
->width
+i
)*((i64
)img
->bytes_per_pixel
-1) + k
] =
845 img
->bitmap
[(j
*img
->width
+i
)*(img
->bytes_per_pixel
) + k
];
850 img
->bytes_per_pixel
--;
853 // Note: This function's features overlap with the DE_CREATEFLAG_OPT_IMAGE
854 // flag supported by de_bitmap_write_to_file().
855 // If the image is 100% opaque, remove the alpha channel.
856 // Otherwise do nothing.
858 // 0x1: Make 100% invisible images 100% opaque
859 // 0x2: Warn if an invisible image was made opaque
860 void de_bitmap_optimize_alpha(de_bitmap
*img
, unsigned int flags
)
862 struct image_scan_results isres
;
864 if(img
->bytes_per_pixel
!=2 && img
->bytes_per_pixel
!=4) return;
866 scan_image(img
, &isres
);
868 if(isres
.has_trns
&& !isres
.has_visible_pixels
&& (flags
&0x1)) {
870 de_warn(img
->c
, "Invisible image detected. Ignoring transparency.");
873 else if(isres
.has_trns
) {
877 // No meaningful transparency found.
878 de_dbg3(img
->c
, "Removing alpha channel from image");
880 de_bitmap_remove_alpha(img
);
883 // flag 0x1: white-is-min
884 void de_make_grayscale_palette(de_color
*pal
, i64 num_entries
, unsigned int flags
)
889 for(k
=0; k
<num_entries
; k
++) {
890 b
= (u8
)(0.5+ (double)k
* (255.0 / (double)(num_entries
-1)));
891 if(flags
&0x1) b
= 255-b
;
892 pal
[k
] = DE_MAKE_GRAY(b
);