From fa31ee9c2c999772910cb8bea57f70e02854c418 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 28 Sep 2013 03:04:34 +0200 Subject: [PATCH] * grub-core/video/readers/png.c: Support paletted images and clean up greyscale support. --- ChangeLog | 5 + grub-core/video/readers/png.c | 224 ++++++++++++++++++---------------- 2 files changed, 126 insertions(+), 103 deletions(-) diff --git a/ChangeLog b/ChangeLog index 583e6319f..d1a9717fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-09-28 Vladimir Serbinenko + + * grub-core/video/readers/png.c: Support paletted images and clean up + greyscale support. + 2013-09-28 Vladimir Serbinenko * grub-core/term/terminfo.c (grub_terminfo_readkey): Fix diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c index edc9eb256..624233a97 100644 --- a/grub-core/video/readers/png.c +++ b/grub-core/video/readers/png.c @@ -52,9 +52,13 @@ enum #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 -#define PNG_CHUNK_IHDR 0x49484452 -#define PNG_CHUNK_IDAT 0x49444154 -#define PNG_CHUNK_IEND 0x49454e44 +enum + { + PNG_CHUNK_IHDR = 0x49484452, + PNG_CHUNK_IDAT = 0x49444154, + PNG_CHUNK_IEND = 0x49454e44, + PNG_CHUNK_PLTE = 0x504c5445 + }; #define Z_DEFLATED 8 #define Z_FLAG_DICT 32 @@ -94,7 +98,7 @@ struct grub_png_data grub_uint32_t next_offset; int image_width, image_height, bpp, is_16bit; - int raw_bytes, is_gray, is_alpha; + int raw_bytes, is_gray, is_alpha, is_palette; grub_uint8_t *image_data; int inside_idat, idat_remain; @@ -107,6 +111,8 @@ struct grub_png_data int dist_maxval[DEFLATE_HUFF_LEN]; int dist_offset[DEFLATE_HUFF_LEN]; + grub_uint8_t palette[256][3]; + struct huff_table code_table; struct huff_table dist_table; @@ -213,6 +219,26 @@ grub_png_get_bits (struct grub_png_data *data, int num) return code; } +static grub_err_t +grub_png_decode_image_palette (struct grub_png_data *data, + unsigned len) +{ + unsigned i = 0, j; + + if (len == 0 || len % 3 != 0) + return GRUB_ERR_NONE; + + for (i = 0; 3 * i < len && i < 256; i++) + for (j = 0; j < 3; j++) + data->palette[i][j] = grub_png_get_byte (data); + for (i *= 3; i < len; i++) + grub_png_get_byte (data); + + grub_png_get_dword (data); + + return GRUB_ERR_NONE; +} + static grub_err_t grub_png_decode_image_header (struct grub_png_data *data) { @@ -233,14 +259,23 @@ grub_png_decode_image_header (struct grub_png_data *data) data->is_16bit = (color_bits == 16); color_type = grub_png_get_byte (data); - if (color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) + /* According to PNG spec, no other types are valid. */ + if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) + && (color_type != PNG_COLOR_TYPE_PALETTE)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: color type not supported"); + if (color_type == PNG_COLOR_TYPE_PALETTE) + data->is_palette = 1; + if (data->is_16bit && data->is_palette) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: color type not supported"); if (color_type & PNG_COLOR_MASK_ALPHA) blt = GRUB_VIDEO_BLIT_FORMAT_RGBA_8888; else blt = GRUB_VIDEO_BLIT_FORMAT_RGB_888; - if (color_type & PNG_COLOR_MASK_COLOR) + if (data->is_palette) + data->bpp = 1; + else if (color_type & PNG_COLOR_MASK_COLOR) data->bpp = 3; else { @@ -260,7 +295,7 @@ grub_png_decode_image_header (struct grub_png_data *data) data->bpp <<= 1; #ifndef GRUB_CPU_WORDS_BIGENDIAN - if (data->is_16bit || !(color_type & PNG_COLOR_MASK_COLOR)) + if (data->is_16bit || data->is_gray || data->is_palette) #endif { data->image_data = grub_malloc (data->image_height * @@ -278,7 +313,7 @@ grub_png_decode_image_header (struct grub_png_data *data) } #endif - data->raw_bytes = data->image_height * (data->image_width * data->bpp + 1) + data->raw_bytes = data->image_height * (data->image_width * data->bpp + 1); data->cur_column = 0; data->first_line = 1; @@ -783,15 +818,35 @@ grub_png_convert_image (struct grub_png_data *data) d1 = (*data->bitmap)->data; d2 = data->image_data + data->is_16bit; - /* Only copy the upper 8 bit. */ #ifndef GRUB_CPU_WORDS_BIGENDIAN - if (!data->is_gray) +#define R4 3 +#define G4 2 +#define B4 1 +#define A4 0 +#define R3 2 +#define G3 1 +#define B3 0 +#else +#define R4 0 +#define G4 1 +#define B4 2 +#define A4 3 +#define R3 0 +#define G3 1 +#define B3 2 +#endif + + if (data->is_palette) { - for (i = 0; i < (data->image_width * data->image_height * data->bpp >> 1); - i++, d1++, d2 += 2) - *d1 = *d2; + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 3, d2++) + { + d1[R3] = data->palette[d2[0]][2]; + d1[G3] = data->palette[d2[0]][1]; + d1[B3] = data->palette[d2[0]][0]; + } } - else + else if (data->is_gray) { switch (data->bpp) { @@ -800,10 +855,10 @@ grub_png_convert_image (struct grub_png_data *data) for (i = 0; i < (data->image_width * data->image_height); i++, d1 += 4, d2 += 4) { - d1[3] = d2[3]; - d1[1] = d2[3]; - d1[2] = d2[3]; - d1[0] = d2[1]; + d1[R4] = d2[3]; + d1[G4] = d2[3]; + d1[B4] = d2[3]; + d1[A4] = d2[1]; } case 2: if (data->is_16bit) @@ -812,9 +867,9 @@ grub_png_convert_image (struct grub_png_data *data) for (i = 0; i < (data->image_width * data->image_height); i++, d1 += 4, d2 += 2) { - d1[0] = d2[1]; - d1[1] = d2[1]; - d1[2] = d2[1]; + d1[R3] = d2[1]; + d1[G3] = d2[1]; + d1[B3] = d2[1]; } } else @@ -823,10 +878,10 @@ grub_png_convert_image (struct grub_png_data *data) for (i = 0; i < (data->image_width * data->image_height); i++, d1 += 4, d2 += 2) { - d1[3] = d2[1]; - d1[1] = d2[1]; - d1[2] = d2[1]; - d1[0] = d2[0]; + d1[R4] = d2[1]; + d1[G4] = d2[1]; + d1[B4] = d2[1]; + d1[A4] = d2[0]; } } break; @@ -835,52 +890,45 @@ grub_png_convert_image (struct grub_png_data *data) for (i = 0; i < (data->image_width * data->image_height); i++, d1 += 3, d2++) { - d1[0] = d2[0]; - d1[1] = d2[0]; - d1[2] = d2[0]; + d1[R3] = d2[0]; + d1[G3] = d2[0]; + d1[B3] = d2[0]; } break; } } -#else - switch (data->bpp) + else { - /* 16-bit with alpha. */ - case 8: - for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 4, d2+=8) + /* Only copy the upper 8 bit. */ +#ifndef GRUB_CPU_WORDS_BIGENDIAN + for (i = 0; i < (data->image_width * data->image_height * data->bpp >> 1); + i++, d1++, d2 += 2) + *d1 = *d2; +#else + switch (data->bpp) { - d1[0] = d2[7]; - d1[1] = d2[5]; - d1[2] = d2[3]; - d1[3] = d2[1]; - } - break; - /* 16-bit without alpha. */ - case 6: - for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 3, d2+=6) - { - d1[0] = d2[5]; - d1[1] = d2[3]; - d1[2] = d2[1]; - } - break; - case 4: - if (data->is_16bit) - { - /* 16-bit gray with alpha. */ + /* 16-bit with alpha. */ + case 8: for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 4, d2 += 4) + i++, d1 += 4, d2+=8) { - d1[0] = d2[3]; - d1[1] = d2[3]; + d1[0] = d2[7]; + d1[1] = d2[5]; d1[2] = d2[3]; d1[3] = d2[1]; } - } - else - { + break; + /* 16-bit without alpha. */ + case 6: + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 3, d2+=6) + { + d1[0] = d2[5]; + d1[1] = d2[3]; + d1[2] = d2[1]; + } + break; + case 4: /* 8-bit with alpha. */ for (i = 0; i < (data->image_width * data->image_height); i++, d1 += 4, d2 += 4) @@ -890,55 +938,21 @@ grub_png_convert_image (struct grub_png_data *data) d1[2] = d2[1]; d1[3] = d2[0]; } - } - break; - /* 8-bit without alpha. */ - case 3: - for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 3, d2 += 3) - { - d1[0] = d2[2]; - d1[1] = d2[1]; - d1[2] = d2[0]; - } - break; - case 2: - if (data->is_16bit) - /* 16-bit gray without alpha. */ - { + break; + /* 8-bit without alpha. */ + case 3: for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 4, d2 += 2) + i++, d1 += 3, d2 += 3) { - d1[0] = d2[1]; + d1[0] = d2[2]; d1[1] = d2[1]; - d1[2] = d2[1]; + d1[2] = d2[0]; } + break; } - else - /* 8-bit gray with alpha. */ - { - for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 4, d2 += 2) - { - d1[0] = d2[1]; - d1[1] = d2[1]; - d1[2] = d2[1]; - d1[3] = d2[0]; - } - } - break; - /* 8-bit gray without alpha. */ - case 1: - for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 3, d2++) - { - d1[0] = d2[0]; - d1[1] = d2[0]; - d1[2] = d2[0]; - } - break; - } #endif + } + } static grub_err_t @@ -966,6 +980,10 @@ grub_png_decode_png (struct grub_png_data *data) grub_png_decode_image_header (data); break; + case PNG_CHUNK_PLTE: + grub_png_decode_image_palette (data, len); + break; + case PNG_CHUNK_IDAT: data->inside_idat = 1; data->idat_remain = len;