#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
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;
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;
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)
{
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
{
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 *
}
#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;
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)
{
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)
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
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;
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)
- {
- 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)
+ /* 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)
{
- /* 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)
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. */
- {
- 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];
- }
- }
- else
- /* 8-bit gray with 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[3] = d2[0];
+ d1[2] = d2[0];
}
+ break;
}
- 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
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;