1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (rbmp.c).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 /* Modified version of stb_image's BMP sources. */
28 #include <stddef.h> /* ptrdiff_t on osx */
32 #include <retro_inline.h>
34 #include <formats/image.h>
35 #include <formats/rbmp.h>
37 /* truncate int to byte without warnings */
38 #define RBMP_BYTECAST(x) ((unsigned char) ((x) & 255))
40 #define RBMP_COMPUTE_Y(r, g, b) ((unsigned char) ((((r) * 77) + ((g) * 150) + (29 * (b))) >> 8))
44 unsigned char *img_buffer;
45 unsigned char *img_buffer_end;
46 unsigned char *img_buffer_original;
52 unsigned char buffer_start[128];
58 uint32_t *output_image;
61 static INLINE unsigned char rbmp_get8(rbmp_context *s)
63 if (s->img_buffer < s->img_buffer_end)
64 return *s->img_buffer++;
69 static void rbmp_skip(rbmp_context *s, int n)
73 s->img_buffer = s->img_buffer_end;
80 static int rbmp_get16le(rbmp_context *s)
82 return rbmp_get8(s) + (rbmp_get8(s) << 8);
85 #define RBMP_GET32LE(s) (rbmp_get16le(s) + (rbmp_get16le(s) << 16))
87 static unsigned char *rbmp_convert_format(
95 unsigned char *good = (unsigned char *)malloc(req_comp * x * y);
100 for (j=0; j < (int) y; ++j)
102 unsigned char *src = data + j * x * img_n ;
103 unsigned char *dest = good + j * x * req_comp;
105 switch (((img_n)*8+(req_comp)))
108 for (i = x-1; i >= 0; --i, src += 1, dest += 2)
115 for (i = x-1; i >= 0; --i, src += 1, dest += 3)
116 dest[0]=dest[1]=dest[2]=src[0];
119 for (i = x-1; i >= 0; --i, src += 1, dest += 4)
121 dest[0]=dest[1]=dest[2]=src[0];
126 for (i = x-1; i >= 0; --i, src += 2, dest += 1)
130 for (i = x-1; i >= 0; --i, src += 2, dest += 3)
131 dest[0]=dest[1]=dest[2]=src[0];
134 for (i = x-1; i >= 0; --i, src += 2, dest += 4)
136 dest[0]=dest[1]=dest[2]=src[0];
141 for (i = x-1; i >= 0; --i, src += 3, dest += 4)
150 for (i = x-1; i >= 0; --i, src += 3, dest += 1)
151 dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
154 for (i = x-1; i >= 0; --i, src += 3, dest += 2)
156 dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
161 for (i = x-1; i >= 0; --i, src += 4, dest += 1)
162 dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
165 for (i = x-1; i >= 0; --i, src += 4, dest += 2)
167 dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
172 for (i = x-1; i >= 0; --i, src += 4, dest += 3)
188 /* Microsoft/Windows BMP image */
190 /* returns 0..31 for the highest set bit */
191 static int rbmp_high_bit(unsigned int z)
222 static int rbmp_bitcount(unsigned int a)
224 a = (a & 0x55555555) + ((a >> 1) & 0x55555555); /* max 2 */
225 a = (a & 0x33333333) + ((a >> 2) & 0x33333333); /* max 4 */
226 a = (a + (a >> 4)) & 0x0f0f0f0f; /* max 8 per 4, now 8 bits */
227 a = (a + (a >> 8)); /* max 16 per 8 bits */
228 a = (a + (a >> 16)); /* max 32 per 8 bits */
232 static int rbmp_shiftsigned(int v, int shift, int bits)
252 static unsigned char *rbmp_bmp_load(rbmp_context *s, unsigned *x, unsigned *y,
253 int *comp, int req_comp)
256 int bpp, flip_vertically, pad, target, offset, hsz;
257 int psize=0,i,j,width;
258 unsigned int mr=0,mg=0,mb=0,ma=0;
261 if (rbmp_get8(s) != 'B' || rbmp_get8(s) != 'M')
264 /* discard filesize */
267 /* discard reserved */
271 offset = (uint32_t)RBMP_GET32LE(s);
272 hsz = (uint32_t)RBMP_GET32LE(s);
274 /* BMP type not supported? */
275 if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
280 s->img_x = rbmp_get16le(s);
281 s->img_y = rbmp_get16le(s);
285 s->img_x = (uint32_t)RBMP_GET32LE(s);
286 s->img_y = (uint32_t)RBMP_GET32LE(s);
290 if (rbmp_get16le(s) != 1)
293 bpp = rbmp_get16le(s);
295 /* BMP 1-bit type not supported? */
299 flip_vertically = ((int) s->img_y) > 0;
300 s->img_y = abs((int) s->img_y);
305 psize = (offset - 14 - 24) / 3;
309 int compress = (uint32_t)RBMP_GET32LE(s);
311 /* BMP RLE type not supported? */
312 if (compress == 1 || compress == 2)
324 /* discard colors used */
327 /* discard max important */
331 if (hsz == 40 || hsz == 56)
344 if (bpp == 16 || bpp == 32)
366 mr = (uint32_t)RBMP_GET32LE(s);
367 mg = (uint32_t)RBMP_GET32LE(s);
368 mb = (uint32_t)RBMP_GET32LE(s);
369 /* not documented, but generated by
370 * Photoshop and handled by MS Paint */
372 if (mr == mg && mg == mb)
388 mr = (uint32_t)RBMP_GET32LE(s);
389 mg = (uint32_t)RBMP_GET32LE(s);
390 mb = (uint32_t)RBMP_GET32LE(s);
391 ma = (uint32_t)RBMP_GET32LE(s);
392 /* Discard color space */
395 for (i = 0; i < 12; ++i)
397 /* Discard color space parameters */
403 /* Discard rendering intent */
406 /* Discard offset of profile data */
409 /* Discard size of profile data */
412 /* Discard reserved */
418 psize = (offset - 14 - hsz) >> 2;
420 s->img_n = ma ? 4 : 3;
421 if (req_comp && req_comp >= 3) /* We can directly decode 3 or 4 */
424 target = s->img_n; /* If they want monochrome, we'll post-convert */
426 out = (unsigned char *) malloc(target * s->img_x * s->img_y);
433 unsigned char pal[256][4];
437 if (psize == 0 || psize > 256)
443 for (i = 0; i < psize; ++i)
445 pal[i][2] = rbmp_get8(s);
446 pal[i][1] = rbmp_get8(s);
447 pal[i][0] = rbmp_get8(s);
453 rbmp_skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
455 width = (s->img_x + 1) >> 1;
466 for (j=0; j < (int) s->img_y; ++j)
468 for (i = 0; i < (int) s->img_x; i += 2)
470 int v = rbmp_get8(s);
477 out[z++] = pal[v][0];
478 out[z++] = pal[v][1];
479 out[z++] = pal[v][2];
483 if (i+1 == (int)s->img_x)
486 v = (bpp == 8) ? rbmp_get8(s) : v2;
487 out[z++] = pal[v][0];
488 out[z++] = pal[v][1];
489 out[z++] = pal[v][2];
510 rbmp_skip(s, offset - 14 - hsz);
513 width = 3 * s->img_x;
516 else /* bpp = 32 and pad = 0 */
527 if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
537 if (!mr || !mg || !mb)
543 /* right shift amt to put high bit in position #7 */
544 rshift = rbmp_high_bit(mr)-7;
545 rcount = rbmp_bitcount(mr);
546 gshift = rbmp_high_bit(mg)-7;
547 gcount = rbmp_bitcount(mg);
548 bshift = rbmp_high_bit(mb)-7;
549 bcount = rbmp_bitcount(mb);
550 ashift = rbmp_high_bit(ma)-7;
551 acount = rbmp_bitcount(ma);
554 for (j=0; j < (int) s->img_y; ++j)
560 /* Need to apply alpha channel as well */
563 for (i = 0; i < (int) s->img_x; ++i)
565 out[z+2] = rbmp_get8(s);
566 out[z+1] = rbmp_get8(s);
567 out[z+0] = rbmp_get8(s);
569 out[z++] = rbmp_get8(s);
574 for (i = 0; i < (int) s->img_x; ++i)
576 out[z+2] = rbmp_get8(s);
577 out[z+1] = rbmp_get8(s);
578 out[z+0] = rbmp_get8(s);
586 for (i = 0; i < (int) s->img_x; ++i)
588 out[z+2] = rbmp_get8(s);
589 out[z+1] = rbmp_get8(s);
590 out[z+0] = rbmp_get8(s);
599 /* Need to apply alpha channel as well */
604 for (i = 0; i < (int) s->img_x; ++i)
606 uint32_t v = (uint32_t)rbmp_get16le(s);
607 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
608 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
609 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
610 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount));
615 for (i = 0; i < (int) s->img_x; ++i)
617 uint32_t v = (uint32_t)RBMP_GET32LE(s);
618 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
619 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
620 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
621 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount));
629 for (i = 0; i < (int) s->img_x; ++i)
631 uint32_t v = (uint32_t)rbmp_get16le(s);
632 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
633 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
634 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
635 out[z++] = RBMP_BYTECAST(255);
640 for (i = 0; i < (int) s->img_x; ++i)
642 uint32_t v = (uint32_t)RBMP_GET32LE(s);
643 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
644 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
645 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
646 out[z++] = RBMP_BYTECAST(255);
655 for (i = 0; i < (int) s->img_x; ++i)
657 uint32_t v = (uint32_t)rbmp_get16le(s);
658 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
659 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
660 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
665 for (i = 0; i < (int) s->img_x; ++i)
667 uint32_t v = (uint32_t)RBMP_GET32LE(s);
668 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
669 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
670 out[z++] = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
682 for (j=0; j < (int) s->img_y>>1; ++j)
684 unsigned char *p1 = out + j *s->img_x*target;
685 unsigned char *p2 = out + (s->img_y-1-j)*s->img_x*target;
686 for (i = 0; i < (int) s->img_x*target; ++i)
697 && (req_comp >= 1 && req_comp <= 4)
698 && (req_comp != target))
700 unsigned char *tmp = rbmp_convert_format(out, target, req_comp, s->img_x, s->img_y);
720 static unsigned char *rbmp_load_from_memory(unsigned char const *buffer, int len,
721 unsigned *x, unsigned *y, int *comp, int req_comp)
725 s.img_buffer = (unsigned char*)buffer;
726 s.img_buffer_original = (unsigned char*)buffer;
727 s.img_buffer_end = (unsigned char*)buffer+len;
729 return rbmp_bmp_load(&s,x,y,comp,req_comp);
732 static void rbmp_convert_frame(uint32_t *frame, unsigned width, unsigned height)
734 uint32_t *end = frame + (width * height * sizeof(uint32_t))/4;
738 uint32_t pixel = *frame;
739 *frame = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff);
744 int rbmp_process_image(rbmp_t *rbmp, void **buf_data,
745 size_t size, unsigned *width, unsigned *height)
750 return IMAGE_PROCESS_ERROR;
752 rbmp->output_image = (uint32_t*)rbmp_load_from_memory(rbmp->buff_data,
753 (int)size, width, height, &comp, 4);
754 *buf_data = rbmp->output_image;
756 rbmp_convert_frame(rbmp->output_image, *width, *height);
758 return IMAGE_PROCESS_END;
761 bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data)
766 rbmp->buff_data = (uint8_t*)data;
771 void rbmp_free(rbmp_t *rbmp)
779 rbmp_t *rbmp_alloc(void)
781 rbmp_t *rbmp = (rbmp_t*)calloc(1, sizeof(*rbmp));