]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
* grub-core/video/readers/png.c: Support paletted images and clean up
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 28 Sep 2013 01:04:34 +0000 (03:04 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 28 Sep 2013 01:04:34 +0000 (03:04 +0200)
greyscale support.

ChangeLog
grub-core/video/readers/png.c

index 583e6319f55bceb051d76e296ca4bdf088413c25..d1a9717fd4909aaf17c14a9a3fd25595476be8da 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-09-28  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       * grub-core/video/readers/png.c: Support paletted images and clean up
+       greyscale support.
+
 2013-09-28  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/term/terminfo.c (grub_terminfo_readkey): Fix
index edc9eb25686d67139cc76c0cc287409a5c5fe44a..624233a9775b4d45ae5761798f4217bed6ea14af 100644 (file)
@@ -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)
-       {
-         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)
@@ -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.  */
-       {
-         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
@@ -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;