Minor refactoring, related to lzah
[deark.git] / src / deark-bitmap.c
blob0e89785aa513ebde33a1e982cb115606d5c01f7c
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // deark-bitmap.c
6 //
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) {
16 return 0;
18 return 1;
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)",
25 (int)w, (int)h);
26 return 0;
28 return 1;
31 #define DE_MAX_IMAGES_PER_FILE 10000
33 // This is meant as a sanity check for fields that indicate how many images
34 // are in a file.
35 // TODO: It is not used very consistently, and should probably be re-thought
36 // or removed.
37 int de_good_image_count(deark *c, i64 n)
39 i64 maximages;
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);
48 return 0;
50 return 1;
53 int de_is_grayscale_palette(const de_color *pal, i64 num_entries)
55 i64 k;
56 de_colorsample cr;
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;
63 return 1;
66 static void de_bitmap_free_pixels(de_bitmap *b)
68 if(b) {
69 deark *c = b->c;
71 if(b->bitmap) {
72 de_free(c, b->bitmap);
73 b->bitmap = NULL;
75 b->bitmap_size = 0;
79 static void de_bitmap_alloc_pixels(de_bitmap *img)
81 if(img->bitmap) {
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;
90 img->width = 1;
91 img->height = 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 {
99 int has_color;
100 int has_trns;
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)
107 i64 i, j;
108 de_color clr;
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;
115 return;
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.
122 a = DE_COLOR_A(clr);
123 r = DE_COLOR_R(clr);
124 g = DE_COLOR_G(clr);
125 b = DE_COLOR_B(clr);
126 if(!isres->has_visible_pixels && a!=0) {
127 isres->has_visible_pixels = 1;
129 if(!isres->has_trns && a<255) {
130 isres->has_trns = 1;
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
140 // about this image.
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))
145 return;
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)
156 de_bitmap *img2;
158 img2 = de_bitmap_create_noinit(img1->c);
159 de_memcpy(img2, img1, sizeof(de_bitmap));
160 img2->bitmap = NULL;
161 img2->bitmap_size = 0;
162 return img2;
165 static de_bitmap *de_bitmap_clone(de_bitmap *img1)
167 de_bitmap *img2;
168 i64 nbytes_to_copy;
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);
174 return img2;
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;
182 de_bitmap *optimg;
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) {
189 return NULL;
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);
195 return optimg;
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)
209 deark *c;
210 dbuf *f;
211 de_bitmap *optimg = NULL;
213 if(!img) return;
214 c = img->c;
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);
223 if(optimg) {
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);
230 if(optimg) {
231 de_write_png(c, optimg, f, createflags);
233 else {
234 de_write_png(c, img, f, createflags);
236 dbuf_close(f);
238 if(optimg) de_bitmap_destroy(optimg);
241 // "token" - A (UTF-8) filename component, like "output.000.<token>.png".
242 // It can be NULL.
243 void de_bitmap_write_to_file(de_bitmap *img, const char *token,
244 unsigned int createflags)
246 deark *c = img->c;
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);
254 else {
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)
263 i64 pos;
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) {
272 case 1: // gray
273 if(samplenum<3) {
274 img->bitmap[pos] = v;
276 break;
277 case 2: // gray+alpha
278 if(samplenum==3) {
279 img->bitmap[pos+1] = v;
281 else {
282 img->bitmap[pos] = v;
284 break;
285 case 3: // RGB
286 if(samplenum<3) {
287 img->bitmap[pos+samplenum] = v;
289 break;
290 case 4: // RGBA
291 img->bitmap[pos+samplenum] = v;
292 break;
296 void de_bitmap_setpixel_gray(de_bitmap *img, i64 x, i64 y, de_colorsample v)
298 i64 pos;
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;
309 break;
310 case 3: // RGB
311 img->bitmap[pos+1] = v;
312 img->bitmap[pos+2] = v;
313 break;
314 case 4: // RGBA
315 img->bitmap[pos+1] = v;
316 img->bitmap[pos+2] = v;
317 img->bitmap[pos+3] = 255;
318 break;
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,
325 de_color color)
327 de_bitmap_setpixel_rgba(img, x, y, color);
330 void de_bitmap_setpixel_rgba(de_bitmap *img, i64 x, i64 y,
331 de_color color)
333 i64 pos;
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) {
341 case 4:
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);
346 break;
347 case 3:
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);
351 break;
352 case 2:
353 img->bitmap[pos] = DE_COLOR_G(color);
354 img->bitmap[pos+1] = DE_COLOR_A(color);
355 break;
356 case 1:
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);
361 break;
365 de_color de_bitmap_getpixel(de_bitmap *img, i64 x, i64 y)
367 i64 pos;
369 if(!img) return 0;
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) {
375 case 4:
376 return DE_MAKE_RGBA(img->bitmap[pos], img->bitmap[pos+1],
377 img->bitmap[pos+2], img->bitmap[pos+3]);
378 case 3:
379 return DE_MAKE_RGBA(img->bitmap[pos], img->bitmap[pos+1],
380 img->bitmap[pos+2], 0xff);
381 break;
382 case 2:
383 return DE_MAKE_RGBA(img->bitmap[pos], img->bitmap[pos],
384 img->bitmap[pos], img->bitmap[pos+1]);
385 break;
386 case 1:
387 return DE_MAKE_RGBA(img->bitmap[pos], img->bitmap[pos],
388 img->bitmap[pos], 0xff);
389 break;
391 return 0;
394 static de_bitmap *de_bitmap_create_noinit(deark *c)
396 de_bitmap *img;
397 img = de_malloc(c, sizeof(de_bitmap));
398 img->c = c;
399 return img;
402 de_bitmap *de_bitmap_create(deark *c, i64 width, i64 height, int bypp)
404 de_bitmap *img;
405 img = de_bitmap_create_noinit(c);
406 img->width = width;
407 img->unpadded_width = width;
408 img->height = height;
409 img->bytes_per_pixel = bypp;
410 //img->rowspan = img->width * img->bytes_per_pixel;
411 return img;
414 de_bitmap *de_bitmap_create2(deark *c, i64 npwidth, i64 pdwidth, i64 height, int bypp)
416 de_bitmap *img;
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;
426 return img;
429 void de_bitmap_destroy(de_bitmap *b)
431 if(b) {
432 deark *c = b->c;
434 de_bitmap_free_pixels(b);
435 de_free(c, b);
439 u8 de_get_bits_symbol(dbuf *f, i64 bps, i64 rowstart, i64 index)
441 i64 byte_offset;
442 u8 b;
443 u8 x = 0;
445 switch(bps) {
446 case 1:
447 byte_offset = rowstart + index/8;
448 b = dbuf_getbyte(f, byte_offset);
449 x = (b >> (7 - index%8)) & 0x01;
450 break;
451 case 2:
452 byte_offset = rowstart + index/4;
453 b = dbuf_getbyte(f, byte_offset);
454 x = (b >> (2 * (3 - index%4))) & 0x03;
455 break;
456 case 4:
457 byte_offset = rowstart + index/2;
458 b = dbuf_getbyte(f, byte_offset);
459 x = (b >> (4 * (1 - index%2))) & 0x0f;
460 break;
461 case 8:
462 byte_offset = rowstart + index;
463 x = dbuf_getbyte(f, byte_offset);
465 return x;
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)
471 i64 byte_offset;
472 u8 b;
473 u8 x = 0;
475 switch(bps) {
476 case 1:
477 byte_offset = rowstart + index/8;
478 b = dbuf_getbyte(f, byte_offset);
479 x = (b >> (index%8)) & 0x01;
480 break;
481 case 2:
482 byte_offset = rowstart + index/4;
483 b = dbuf_getbyte(f, byte_offset);
484 x = (b >> (2 * (index%4))) & 0x03;
485 break;
486 case 4:
487 byte_offset = rowstart + index/2;
488 b = dbuf_getbyte(f, byte_offset);
489 x = (b >> (4 * (index%2))) & 0x0f;
490 break;
491 case 8:
492 byte_offset = rowstart + index;
493 x = dbuf_getbyte(f, byte_offset);
495 return x;
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)
502 u8 b0, b1;
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
516 return b0;
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)
532 i64 i;
533 u8 x;
534 u8 b;
535 u8 black, white;
537 if(flags & DE_CVTF_WHITEISZERO) {
538 white = 0; black = 255;
540 else {
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;
548 else
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)
557 i64 j;
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()
565 // when appropriate.
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;
572 deark *c = f->c;
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;
590 deark *c = f->c;
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,
604 unsigned int flags)
606 i64 k;
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)
619 i64 i, j;
620 unsigned int palent;
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)
636 i64 i, j;
637 de_color clr;
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)
658 i64 i, j;
659 i64 nr;
661 nr = img->height/2;
663 for(j=0; j<nr; j++) {
664 i64 row1, row2;
666 row1 = j;
667 row2 = img->height-1-j;
669 for(i=0; i<img->width; i++) {
670 de_color tmp1, tmp2;
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
684 // real pixels.
685 void de_bitmap_mirror(de_bitmap *img)
687 i64 i, j;
688 i64 nc;
690 de_bitmap_apply_padding(img);
691 nc = img->width/2;
693 for(j=0; j<img->height; j++) {
694 for(i=0; i<nc; i++) {
695 i64 col1, col2;
696 de_color tmp1, tmp2;
698 col1 = 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)
713 i64 i, j;
715 for(j=0; j<img->height; j++) {
716 for(i=0; i<j; i++) {
717 de_color tmp1, tmp2;
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)
733 i64 i, j;
734 de_bitmap *imgtmp = NULL;
736 de_bitmap_apply_padding(img);
738 if(img->width == img->height) {
739 bitmap_transpose_square(img);
740 goto done;
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++) {
752 de_color tmp1;
754 tmp1 = de_bitmap_getpixel(imgtmp, j, i);
755 de_bitmap_setpixel_rgba(img, i, j, tmp1);
759 done:
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)
769 i64 i, j;
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.
781 // Flags supported:
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)
787 i64 i, j;
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)) {
795 clr = src_clr;
797 else {
798 src_a = DE_COLOR_A(src_clr);
799 if(src_a>0) {
800 // TODO: Support partial transparency (of both foreground and
801 // background, ideally)
802 clr = src_clr;
804 else {
805 dst_clr = de_bitmap_getpixel(dstimg, dstxpos+i, dstypos+j);
806 clr = dst_clr;
809 de_bitmap_setpixel_rgba(dstimg, dstxpos+i, dstypos+j, clr);
814 void de_bitmap_apply_mask(de_bitmap *fg, de_bitmap *mask,
815 unsigned int flags)
817 i64 i, j;
818 de_color clr;
819 de_colorsample a;
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);
824 a = DE_COLOR_K(clr);
825 if(flags&DE_BITMAPFLAG_WHITEISTRNS)
826 a = 0xff-a;
827 de_bitmap_setsample(fg, i, j, 3, a);
832 void de_bitmap_remove_alpha(de_bitmap *img)
834 i64 i, j;
835 i64 k;
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.
857 // flags:
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)) {
869 if(flags&0x2) {
870 de_warn(img->c, "Invisible image detected. Ignoring transparency.");
873 else if(isres.has_trns) {
874 return;
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)
886 i64 k;
887 u8 b;
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);