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 // DE_CVTF_ONLYWHITE = Don't paint the black pixels (presumably because
530 // they are already black). Use with caution if the format supports transparency.
531 void de_unpack_pixels_bilevel_from_byte(de_bitmap
*img
, i64 xpos
, i64 ypos
,
532 u8 val
, UI npixels
, unsigned int flags
)
537 if(npixels
>8) return;
538 xv
= (flags
& DE_CVTF_WHITEISZERO
) ? 0xff : 0x00;
540 for(i
=0; i
<npixels
; i
++) {
543 if(flags
& DE_CVTF_LSBFIRST
) {
544 x
= (val
& 0x01) ? 0xff : 0x00;
548 x
= (val
& 0x80) ? 0xff : 0x00;
553 if(x
==0x00 && DE_CVTF_ONLYWHITE
) continue;
554 de_bitmap_setpixel_gray(img
, xpos
+(i64
)i
, ypos
, x
);
558 // Generalization of de_convert_row_bilevel(), to support just part of a row.
559 void de_convert_pixels_bilevel(dbuf
*f
, i64 pos1
, de_bitmap
*img
,
560 i64 xpos1
, i64 ypos
, i64 npixels
, unsigned int flags
)
564 i64 npixels_remaining
= npixels
;
565 i64 npixels_this_time
;
567 while(npixels_remaining
>0) {
570 b
= dbuf_getbyte_p(f
, &pos
);
571 npixels_this_time
= de_min_int(npixels_remaining
, 8);
572 de_unpack_pixels_bilevel_from_byte(img
, xpos
, ypos
, b
,
573 (UI
)npixels_this_time
, flags
);
574 npixels_remaining
-= npixels_this_time
;
579 void de_convert_row_bilevel(dbuf
*f
, i64 fpos
, de_bitmap
*img
,
580 i64 rownum
, unsigned int flags
)
582 de_convert_pixels_bilevel(f
, fpos
, img
, 0, rownum
, img
->width
, flags
);
585 void de_convert_image_bilevel(dbuf
*f
, i64 fpos
, i64 rowspan
,
586 de_bitmap
*img
, unsigned int flags
)
590 for(j
=0; j
<img
->height
; j
++) {
591 de_convert_row_bilevel(f
, fpos
+j
*rowspan
, img
, j
, flags
);
595 // TODO: Review everything using this function, and convert to ..._bilevel2()
597 // Maybe remove/rename this function.
598 void de_convert_and_write_image_bilevel(dbuf
*f
, i64 fpos
,
599 i64 width
, i64 height
, i64 rowspan
, unsigned int cvtflags
,
600 de_finfo
*fi
, unsigned int createflags
)
602 de_bitmap
*img
= NULL
;
605 if(!de_good_image_dimensions(c
, width
, height
)) return;
607 img
= de_bitmap_create(c
, width
, height
, 1);
608 de_convert_image_bilevel(f
, fpos
, rowspan
, img
, cvtflags
);
609 de_bitmap_write_to_file_finfo(img
, fi
, createflags
);
610 de_bitmap_destroy(img
);
613 // This function automatically handles padding pixels, for the -padpix option.
614 // This means the "rowspan" param cannot be used to do clever things --
615 // there cannot be any data between the rows, other than padding bits.
616 void de_convert_and_write_image_bilevel2(dbuf
*f
, i64 fpos
,
617 i64 width
, i64 height
, i64 rowspan
, unsigned int cvtflags
,
618 de_finfo
*fi
, unsigned int createflags
)
620 de_bitmap
*img
= NULL
;
623 if(!de_good_image_dimensions(c
, width
, height
)) return;
624 img
= de_bitmap_create2(c
, width
, rowspan
*8, height
, 1);
625 de_convert_image_bilevel(f
, fpos
, rowspan
, img
, cvtflags
);
626 de_bitmap_write_to_file_finfo(img
, fi
, createflags
);
627 de_bitmap_destroy(img
);
630 // Read a palette of 24-bit RGB colors.
631 // flags = flags used by dbuf_getRGB()
632 void de_read_palette_rgb(dbuf
*f
,
633 i64 fpos
, i64 num_entries
, i64 entryspan
,
634 de_color
*pal
, i64 ncolors_in_pal
,
639 if(num_entries
> ncolors_in_pal
) num_entries
= ncolors_in_pal
;
640 for(k
=0; k
<num_entries
; k
++) {
641 pal
[k
] = dbuf_getRGB(f
, fpos
+ k
*entryspan
, flags
);
642 de_dbg_pal_entry(f
->c
, k
, pal
[k
]);
646 void de_convert_image_paletted(dbuf
*f
, i64 fpos
,
647 i64 bpp
, i64 rowspan
, const de_color
*pal
,
648 de_bitmap
*img
, unsigned int flags
)
653 if(bpp
!=1 && bpp
!=2 && bpp
!=4 && bpp
!=8) return;
654 if(!de_good_image_dimensions_noerr(f
->c
, img
->width
, img
->height
)) return;
656 for(j
=0; j
<img
->height
; j
++) {
657 for(i
=0; i
<img
->width
; i
++) {
658 palent
= (unsigned int)de_get_bits_symbol(f
, bpp
, fpos
+j
*rowspan
, i
);
659 de_bitmap_setpixel_rgba(img
, i
, j
, pal
[palent
]);
664 void de_convert_image_rgb(dbuf
*f
, i64 fpos
,
665 i64 rowspan
, i64 pixelspan
, de_bitmap
*img
, unsigned int flags
)
670 for(j
=0; j
<img
->height
; j
++) {
671 for(i
=0; i
<img
->width
; i
++) {
672 clr
= dbuf_getRGB(f
, fpos
+ j
*rowspan
+ i
*pixelspan
, flags
);
673 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
678 // Turn padding pixels into real pixels.
679 static void de_bitmap_apply_padding(de_bitmap
*img
)
681 if(img
->unpadded_width
!= img
->width
) {
682 img
->unpadded_width
= img
->width
;
686 // TODO: This function could be made more efficient.
687 void de_bitmap_flip(de_bitmap
*img
)
694 for(j
=0; j
<nr
; j
++) {
698 row2
= img
->height
-1-j
;
700 for(i
=0; i
<img
->width
; i
++) {
703 tmp1
= de_bitmap_getpixel(img
, i
, row1
);
704 tmp2
= de_bitmap_getpixel(img
, i
, row2
);
705 if(tmp1
==tmp2
) continue;
706 de_bitmap_setpixel_rgba(img
, i
, row2
, tmp1
);
707 de_bitmap_setpixel_rgba(img
, i
, row1
, tmp2
);
712 // Not recommended for use with padded bitmaps (e.g. those created with
713 // de_bitmap_create2()). We don't support padding pixels on the left, so we can't
714 // truly mirror such an image. Current behavior is to turn padding pixels into
716 void de_bitmap_mirror(de_bitmap
*img
)
721 de_bitmap_apply_padding(img
);
724 for(j
=0; j
<img
->height
; j
++) {
725 for(i
=0; i
<nc
; i
++) {
730 col2
= img
->width
-1-i
;
732 tmp1
= de_bitmap_getpixel(img
, col1
, j
);
733 tmp2
= de_bitmap_getpixel(img
, col2
, j
);
734 if(tmp1
==tmp2
) continue;
735 de_bitmap_setpixel_rgba(img
, col2
, j
, tmp1
);
736 de_bitmap_setpixel_rgba(img
, col1
, j
, tmp2
);
741 // Transpose (flip over the line y=x) a square bitmap.
742 static void bitmap_transpose_square(de_bitmap
*img
)
746 for(j
=0; j
<img
->height
; j
++) {
750 tmp1
= de_bitmap_getpixel(img
, i
, j
);
751 tmp2
= de_bitmap_getpixel(img
, j
, i
);
752 if(tmp1
==tmp2
) continue;
753 de_bitmap_setpixel_rgba(img
, j
, i
, tmp1
);
754 de_bitmap_setpixel_rgba(img
, i
, j
, tmp2
);
759 // Transpose (flip over the line y=x) a bitmap.
760 // Not recommended for use with padded bitmaps (e.g. those created with
761 // de_bitmap_create2()).
762 void de_bitmap_transpose(de_bitmap
*img
)
765 de_bitmap
*imgtmp
= NULL
;
767 de_bitmap_apply_padding(img
);
769 if(img
->width
== img
->height
) {
770 bitmap_transpose_square(img
);
774 imgtmp
= de_bitmap_clone(img
);
776 de_bitmap_free_pixels(img
);
777 img
->width
= imgtmp
->height
;
778 img
->unpadded_width
= imgtmp
->height
;
779 img
->height
= imgtmp
->width
;
781 for(j
=0; j
<img
->height
; j
++) {
782 for(i
=0; i
<img
->width
; i
++) {
785 tmp1
= de_bitmap_getpixel(imgtmp
, j
, i
);
786 de_bitmap_setpixel_rgba(img
, i
, j
, tmp1
);
791 if(imgtmp
) de_bitmap_destroy(imgtmp
);
794 // Paint a solid, solid-color rectangle onto an image.
795 // (Pixels will be replaced, not merged.)
796 void de_bitmap_rect(de_bitmap
*img
,
797 i64 xpos
, i64 ypos
, i64 width
, i64 height
,
798 de_color clr
, unsigned int flags
)
802 for(j
=0; j
<height
; j
++) {
803 for(i
=0; i
<width
; i
++) {
804 de_bitmap_setpixel_rgba(img
, xpos
+i
, ypos
+j
, clr
);
809 // Paint or copy (all or part of) srcimg onto dstimg.
810 // If srcimg and dstimg are the same image, the source and destination
811 // rectangles must not overlap.
813 // DE_BITMAPFLAG_MERGE - Merge transparent pixels (partially supported)
814 void de_bitmap_copy_rect(de_bitmap
*srcimg
, de_bitmap
*dstimg
,
815 i64 srcxpos
, i64 srcypos
, i64 width
, i64 height
,
816 i64 dstxpos
, i64 dstypos
, unsigned int flags
)
819 de_color dst_clr
, src_clr
, clr
;
820 de_colorsample src_a
;
822 for(j
=0; j
<height
; j
++) {
823 for(i
=0; i
<width
; i
++) {
824 src_clr
= de_bitmap_getpixel(srcimg
, srcxpos
+i
, srcypos
+j
);
825 if(!(flags
&DE_BITMAPFLAG_MERGE
)) {
829 src_a
= DE_COLOR_A(src_clr
);
831 // TODO: Support partial transparency (of both foreground and
832 // background, ideally)
836 dst_clr
= de_bitmap_getpixel(dstimg
, dstxpos
+i
, dstypos
+j
);
840 de_bitmap_setpixel_rgba(dstimg
, dstxpos
+i
, dstypos
+j
, clr
);
845 void de_bitmap_apply_mask(de_bitmap
*fg
, de_bitmap
*mask
,
852 for(j
=0; j
<fg
->height
&& j
<mask
->height
; j
++) {
853 for(i
=0; i
<fg
->width
&& i
<mask
->width
; i
++) {
854 clr
= de_bitmap_getpixel(mask
, i
, j
);
856 if(flags
&DE_BITMAPFLAG_WHITEISTRNS
)
858 de_bitmap_setsample(fg
, i
, j
, 3, a
);
863 void de_bitmap_remove_alpha(de_bitmap
*img
)
868 if(img
->bytes_per_pixel
!=2 && img
->bytes_per_pixel
!=4) return;
870 // Note that the format conversion is done in-place. The extra memory used
871 // by the alpha channel is not de-allocated.
872 for(j
=0; j
<img
->height
; j
++) {
873 for(i
=0; i
<img
->width
; i
++) {
874 for(k
=0; k
<(i64
)img
->bytes_per_pixel
-1; k
++) {
875 img
->bitmap
[(j
*img
->width
+i
)*((i64
)img
->bytes_per_pixel
-1) + k
] =
876 img
->bitmap
[(j
*img
->width
+i
)*(img
->bytes_per_pixel
) + k
];
881 img
->bytes_per_pixel
--;
884 // Note: This function's features overlap with the DE_CREATEFLAG_OPT_IMAGE
885 // flag supported by de_bitmap_write_to_file().
886 // If the image is 100% opaque, remove the alpha channel.
887 // Otherwise do nothing.
889 // 0x1: Make 100% invisible images 100% opaque
890 // 0x2: Warn if an invisible image was made opaque
891 void de_bitmap_optimize_alpha(de_bitmap
*img
, unsigned int flags
)
893 struct image_scan_results isres
;
895 if(img
->bytes_per_pixel
!=2 && img
->bytes_per_pixel
!=4) return;
897 scan_image(img
, &isres
);
899 if(isres
.has_trns
&& !isres
.has_visible_pixels
&& (flags
&0x1)) {
901 de_warn(img
->c
, "Invisible image detected. Ignoring transparency.");
904 else if(isres
.has_trns
) {
908 // No meaningful transparency found.
909 de_dbg3(img
->c
, "Removing alpha channel from image");
911 de_bitmap_remove_alpha(img
);
914 // flag 0x1: white-is-min
915 void de_make_grayscale_palette(de_color
*pal
, i64 num_entries
, unsigned int flags
)
920 for(k
=0; k
<num_entries
; k
++) {
921 b
= (u8
)(0.5+ (double)k
* (255.0 / (double)(num_entries
-1)));
922 if(flags
&0x1) b
= 255-b
;
923 pal
[k
] = DE_MAKE_GRAY(b
);