Refactored the convert_row_bilevel function
[deark.git] / src / deark-bitmap.c
blobb99fc13c953f3a0708e4d4c41bcf3e2832b65a22
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 // 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)
534 UI i;
535 u8 xv;
537 if(npixels>8) return;
538 xv = (flags & DE_CVTF_WHITEISZERO) ? 0xff : 0x00;
540 for(i=0; i<npixels; i++) {
541 u8 x;
543 if(flags & DE_CVTF_LSBFIRST) {
544 x = (val & 0x01) ? 0xff : 0x00;
545 val >>= 1;
547 else {
548 x = (val & 0x80) ? 0xff : 0x00;
549 val <<= 1;
552 x ^= xv;
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)
562 i64 pos = pos1;
563 i64 xpos = xpos1;
564 i64 npixels_remaining = npixels;
565 i64 npixels_this_time;
567 while(npixels_remaining>0) {
568 u8 b;
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;
575 xpos += 8;
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)
588 i64 j;
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()
596 // when appropriate.
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;
603 deark *c = f->c;
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;
621 deark *c = f->c;
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,
635 unsigned int flags)
637 i64 k;
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)
650 i64 i, j;
651 unsigned int palent;
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)
667 i64 i, j;
668 de_color clr;
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)
689 i64 i, j;
690 i64 nr;
692 nr = img->height/2;
694 for(j=0; j<nr; j++) {
695 i64 row1, row2;
697 row1 = j;
698 row2 = img->height-1-j;
700 for(i=0; i<img->width; i++) {
701 de_color tmp1, tmp2;
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
715 // real pixels.
716 void de_bitmap_mirror(de_bitmap *img)
718 i64 i, j;
719 i64 nc;
721 de_bitmap_apply_padding(img);
722 nc = img->width/2;
724 for(j=0; j<img->height; j++) {
725 for(i=0; i<nc; i++) {
726 i64 col1, col2;
727 de_color tmp1, tmp2;
729 col1 = 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)
744 i64 i, j;
746 for(j=0; j<img->height; j++) {
747 for(i=0; i<j; i++) {
748 de_color tmp1, tmp2;
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)
764 i64 i, j;
765 de_bitmap *imgtmp = NULL;
767 de_bitmap_apply_padding(img);
769 if(img->width == img->height) {
770 bitmap_transpose_square(img);
771 goto done;
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++) {
783 de_color tmp1;
785 tmp1 = de_bitmap_getpixel(imgtmp, j, i);
786 de_bitmap_setpixel_rgba(img, i, j, tmp1);
790 done:
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)
800 i64 i, j;
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.
812 // Flags supported:
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)
818 i64 i, j;
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)) {
826 clr = src_clr;
828 else {
829 src_a = DE_COLOR_A(src_clr);
830 if(src_a>0) {
831 // TODO: Support partial transparency (of both foreground and
832 // background, ideally)
833 clr = src_clr;
835 else {
836 dst_clr = de_bitmap_getpixel(dstimg, dstxpos+i, dstypos+j);
837 clr = dst_clr;
840 de_bitmap_setpixel_rgba(dstimg, dstxpos+i, dstypos+j, clr);
845 void de_bitmap_apply_mask(de_bitmap *fg, de_bitmap *mask,
846 unsigned int flags)
848 i64 i, j;
849 de_color clr;
850 de_colorsample a;
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);
855 a = DE_COLOR_K(clr);
856 if(flags&DE_BITMAPFLAG_WHITEISTRNS)
857 a = 0xff-a;
858 de_bitmap_setsample(fg, i, j, 3, a);
863 void de_bitmap_remove_alpha(de_bitmap *img)
865 i64 i, j;
866 i64 k;
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.
888 // flags:
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)) {
900 if(flags&0x2) {
901 de_warn(img->c, "Invisible image detected. Ignoring transparency.");
904 else if(isres.has_trns) {
905 return;
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)
917 i64 k;
918 u8 b;
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);