grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* Adam7 and narrow PNG
@ 2013-10-02  0:24 Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-02  6:57 ` Melki Christian (consultant)
  0 siblings, 1 reply; 4+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-10-02  0:24 UTC (permalink / raw)
  To: The development of GRUB 2


[-- Attachment #1.1: Type: text/plain, Size: 297 bytes --]

It was reported that GRUB doesn't support Adam7 and paletteed PNGs.
Attached patch would implement both of them but combining them results
in quite complex code since PNG works on bytes even if bpp <= 4 but
adam7 works on pixels. Does anyone have thoughts on adam7 and narrow PNG
usefulness?

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: png.diff --]
[-- Type: text/x-diff; name="png.diff", Size: 23862 bytes --]

=== modified file 'grub-core/video/readers/png.c'
--- grub-core/video/readers/png.c	2013-09-28 01:04:34 +0000
+++ grub-core/video/readers/png.c	2013-09-28 21:51:16 +0000
@@ -31,7 +31,6 @@
 
 enum
   {
-    PNG_COLOR_TYPE_GRAY = 0,
     PNG_COLOR_MASK_PALETTE = 1,
     PNG_COLOR_MASK_COLOR = 2,
     PNG_COLOR_MASK_ALPHA = 4,
@@ -40,8 +39,11 @@
 
 #define PNG_COMPRESSION_BASE	0
 
-#define PNG_INTERLACE_NONE	0
-#define PNG_INTERLACE_ADAM7	1
+enum
+  {
+    PNG_INTERLACE_NONE = 0,
+    PNG_INTERLACE_ADAM7 = 1
+  };
 
 #define PNG_FILTER_TYPE_BASE	0
 
@@ -88,6 +90,28 @@
   int num_values, max_length;
 };
 
+struct interlace_stage
+{
+  int start_x, start_y;
+  int log_step_x, log_step_y;
+};
+
+static struct interlace_stage interleave_none[] =
+  {
+    { 0, 0, 0, 0 }
+  };
+
+static struct interlace_stage interleave_adam7[] =
+  {
+    { 0, 0, 3, 3 },
+    { 4, 0, 3, 3 },
+    { 0, 4, 2, 3 },
+    { 2, 0, 2, 2 },
+    { 0, 2, 1, 2 },
+    { 1, 0, 1, 1 },
+    { 0, 1, 0, 1 }
+  };
+
 struct grub_png_data
 {
   grub_file_t file;
@@ -99,6 +123,8 @@
 
   int image_width, image_height, bpp, is_16bit;
   int raw_bytes, is_gray, is_alpha, is_palette;
+  int row_bytes, row_bytes_i, row_bytes_i2, color_bits;
+  int skip;
   grub_uint8_t *image_data;
 
   int inside_idat, idat_remain;
@@ -119,9 +145,15 @@
   grub_uint8_t slide[WSIZE];
   int wp;
 
-  grub_uint8_t *cur_rgb;
+  grub_uint8_t *cur_rgb, *rgb0;
 
   int cur_column, cur_filter, first_line;
+  int cur_component;
+
+  struct interlace_stage *cur_interleave;
+  int n_interleave;
+
+  int is_adam7;
 };
 
 static grub_uint32_t
@@ -245,6 +277,7 @@
   int color_type;
   int color_bits;
   enum grub_video_blit_format blt;
+  grub_uint8_t interleave;
 
   data->image_width = grub_png_get_dword (data);
   data->image_height = grub_png_get_dword (data);
@@ -253,9 +286,6 @@
     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
 
   color_bits = grub_png_get_byte (data);
-  if ((color_bits != 8) && (color_bits != 16))
-    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-                       "png: bit depth must be 8 or 16");
   data->is_16bit = (color_bits == 16);
 
   color_type = grub_png_get_byte (data);
@@ -283,6 +313,13 @@
       data->bpp = 1;
     }
 
+  if ((color_bits != 8) && (color_bits != 16)
+      && ((color_bits != 4 && color_bits != 2
+	   && color_bits != 1)
+	  || !(data->is_gray || data->is_palette)))
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                       "png: bit depth must be 8 or 16");
+
   if (color_type & PNG_COLOR_MASK_ALPHA)
     data->bpp++;
 
@@ -294,30 +331,29 @@
   if (data->is_16bit)
       data->bpp <<= 1;
 
+  data->color_bits = color_bits;
+  data->row_bytes = data->image_width * data->bpp;
+  if (data->color_bits <= 4)
+    data->row_bytes = (data->image_width * data->color_bits + 7) / 8 + 16;
+
 #ifndef GRUB_CPU_WORDS_BIGENDIAN
   if (data->is_16bit || data->is_gray || data->is_palette)
 #endif
     {
-      data->image_data = grub_malloc (data->image_height *
-                                      data->image_width *  data->bpp);
+      data->image_data = grub_malloc (data->image_height * data->row_bytes);
       if (grub_errno)
         return grub_errno;
 
-      data->cur_rgb = data->image_data;
+      data->rgb0 = data->image_data;
     }
 #ifndef GRUB_CPU_WORDS_BIGENDIAN
   else
     {
       data->image_data = 0;
-      data->cur_rgb = (*data->bitmap)->data;
+      data->rgb0 = (*data->bitmap)->data;
     }
 #endif
 
-  data->raw_bytes = data->image_height * (data->image_width * data->bpp + 1);
-
-  data->cur_column = 0;
-  data->first_line = 1;
-
   if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
 		       "png: compression method not supported");
@@ -326,9 +362,22 @@
     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
 		       "png: filter method not supported");
 
-  if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
-    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-		       "png: interlace method not supported");
+  interleave = grub_png_get_byte (data);
+  switch (interleave)
+    {
+    case PNG_INTERLACE_NONE:
+      data->cur_interleave = interleave_none - 1;
+      data->n_interleave = ARRAY_SIZE (interleave_none);
+      break;
+    case PNG_INTERLACE_ADAM7:
+      data->cur_interleave = interleave_adam7 - 1;
+      data->n_interleave = ARRAY_SIZE (interleave_adam7);
+      data->is_adam7 = 1;
+      break;
+    default:
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+			 "png: interlace method not supported");
+    }
 
   /* Skip crc checksum.  */
   grub_png_get_dword (data);
@@ -567,104 +616,189 @@
 static grub_err_t
 grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n)
 {
-  int row_bytes;
-
-  if (--data->raw_bytes < 0)
+  while (data->raw_bytes == 0 && data->n_interleave)
+    {
+      int rows_i;
+      data->cur_interleave++;
+
+      data->cur_rgb = data->rgb0;
+
+      rows_i = (data->image_width >> data->cur_interleave->log_step_x);
+      if (data->color_bits <= 4)
+	{
+	  data->row_bytes_i = (rows_i * data->color_bits + 7) / 8;	
+	  data->skip = ((1 << data->cur_interleave->log_step_x) - 1);
+	  data->cur_rgb += data->cur_interleave->start_x;
+	}
+      else
+	{
+	  data->row_bytes_i = rows_i * data->bpp;
+
+	  data->skip = ((1 << data->cur_interleave->log_step_x) - 1) * data->bpp;
+	  data->cur_rgb += data->cur_interleave->start_x * data->bpp;
+	}
+
+      data->row_bytes_i2 = data->row_bytes_i
+	+ data->skip * (data->row_bytes_i / data->bpp);
+
+      data->raw_bytes = (data->image_height >> data->cur_interleave->log_step_y)
+	* (data->row_bytes_i + 1);
+
+      data->cur_column = 0;
+      data->cur_filter = 0;
+      data->first_line = 1;
+      data->cur_component = 0;
+      data->cur_rgb += data->cur_interleave->start_y * data->row_bytes;
+      data->n_interleave--;
+    }
+
+  data->raw_bytes--;
+
+  if (data->raw_bytes < 0)
     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflown");
 
   if (data->cur_column == 0)
     {
       if (n >= PNG_FILTER_VALUE_LAST)
-	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid filter value");
+	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid filter value %d", n);
 
       data->cur_filter = n;
+      if (!data->first_line)
+	data->cur_rgb += (1 << data->cur_interleave->log_step_y)
+	  * data->row_bytes - data->row_bytes_i2;
     }
   else
-    *data->cur_rgb++ = n;
+    {
+      *data->cur_rgb++ = n;
+      data->cur_component++;
+      if (data->cur_component == data->bpp)
+	{
+	  data->cur_component = 0;
+	  data->cur_rgb += data->skip;
+	}
+    }
 
   data->cur_column++;
-  row_bytes = data->image_width * data->bpp;
-  if (data->cur_column == row_bytes + 1)
+
+  if (data->cur_column == data->row_bytes_i + 1)
     {
       grub_uint8_t *blank_line = NULL;
-      grub_uint8_t *cur = data->cur_rgb - row_bytes;
+      grub_uint8_t *cur = data->cur_rgb - data->row_bytes_i2;
       grub_uint8_t *left = cur;
       grub_uint8_t *up;
 
       if (data->first_line)
 	{
-	  blank_line = grub_zalloc (row_bytes);
+	  blank_line = grub_zalloc (data->row_bytes);
 	  if (blank_line == NULL)
 	    return grub_errno;
 
 	  up = blank_line;
 	}
       else
-	up = cur - row_bytes;
+	up = cur - (data->row_bytes << data->cur_interleave->log_step_y);
 
       switch (data->cur_filter)
 	{
 	case PNG_FILTER_VALUE_SUB:
 	  {
-	    int i;
+	    int i, j;
 
-	    cur += data->bpp;
-	    for (i = data->bpp; i < row_bytes; i++, cur++, left++)
-	      *cur += *left;
+	    cur += data->bpp + data->skip;
+	    for (i = data->bpp; i < data->row_bytes; )
+	      {
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    *cur += *left;
+		    i++, cur++, left++;
+		  }
+		i += data->skip;
+		cur += data->skip;
+		left += data->skip;
+	      }
 
 	    break;
 	  }
 	case PNG_FILTER_VALUE_UP:
 	  {
-	    int i;
-
-	    for (i = 0; i < row_bytes; i++, cur++, up++)
-	      *cur += *up;
-
+	    int i, j;
+
+	    for (i = 0; i < data->row_bytes; )
+	      {
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    *cur += *up;
+		    i++, cur++, up++;
+		  }
+		i += data->skip;
+		cur += data->skip;
+		up += data->skip;
+	      }
 	    break;
 	  }
 	case PNG_FILTER_VALUE_AVG:
 	  {
-	    int i;
+	    int i, j;
 
 	    for (i = 0; i < data->bpp; i++, cur++, up++)
 	      *cur += *up >> 1;
 
-	    for (; i < row_bytes; i++, cur++, up++, left++)
-	      *cur += ((int) *up + (int) *left) >> 1;
+	    i += data->skip;
+	    cur += data->skip;
+	    up += data->skip;
+
+	    for (; i < data->row_bytes; )
+	      {
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    *cur += ((int) *up + (int) *left) >> 1;
+		    i++, cur++, up++, left++;
+		  }
+		i+= data->skip, cur+= data->skip, up+= data->skip, left+= data->skip;
+	      }
 
 	    break;
 	  }
 	case PNG_FILTER_VALUE_PAETH:
 	  {
-	    int i;
+	    int i, j;
 	    grub_uint8_t *upper_left = up;
 
 	    for (i = 0; i < data->bpp; i++, cur++, up++)
 	      *cur += *up;
 
-	    for (; i < row_bytes; i++, cur++, up++, left++, upper_left++)
+	    i += data->skip;
+	    cur += data->skip;
+	    up += data->skip;
+
+	    for (; i < data->row_bytes; )
 	      {
-		int a, b, c, pa, pb, pc;
-
-                a = *left;
-                b = *up;
-                c = *upper_left;
-
-                pa = b - c;
-                pb = a - c;
-                pc = pa + pb;
-
-                if (pa < 0)
-                  pa = -pa;
-
-                if (pb < 0)
-                  pb = -pb;
-
-                if (pc < 0)
-                  pc = -pc;
-
-                *cur += ((pa <= pb) && (pa <= pc)) ? a : (pb <= pc) ? b : c;
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    int a, b, c, pa, pb, pc;
+
+		    a = *left;
+		    b = *up;
+		    c = *upper_left;
+
+		    pa = b - c;
+		    pb = a - c;
+		    pc = pa + pb;
+
+		    if (pa < 0)
+		      pa = -pa;
+
+		    if (pb < 0)
+		      pb = -pb;
+
+		    if (pc < 0)
+		      pc = -pc;
+
+		    *cur += ((pa <= pb) && (pa <= pc)) ? a : (pb <= pc) ? b : c;
+		    i++, cur++, up++, left++, upper_left++;
+		  }
+		i+=data->skip, cur+=data->skip, up+=data->skip;
+		left+=data->skip, upper_left+=data->skip;
 	      }
 	  }
 	}
@@ -809,6 +943,8 @@
 static const grub_uint8_t png_magic[8] =
   { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0x0a };
 
+#include "png_adam7.c"
+
 static void
 grub_png_convert_image (struct grub_png_data *data)
 {
@@ -836,6 +972,87 @@
 #define B3 2
 #endif
 
+  if (data->color_bits <= 4)
+    {
+      grub_uint8_t palette[16][3];
+      grub_uint8_t *dc;
+      int shift = 8 - data->color_bits;
+      int mask = (1 << data->color_bits) - 1;
+      int j;
+      if (data->is_gray)
+	for (i = 0; i < (1 << data->color_bits); i++)
+	  {
+	    grub_uint8_t col = (0xff * i) / ((1 << data->color_bits) - 1);
+	    palette[i][0] = col;
+	    palette[i][1] = col;
+	    palette[i][2] = col;
+	  }
+      else
+	grub_memcpy (palette, data->palette, 16 * 3);
+      dc = d2;
+      /* Our algorithms work on bytes in case of color depth <= 4.
+	 Usually it's no problem as PNG specs does the same. However
+	 Adam7 always works on pixels, so we need this additional shuffling.
+      */
+      if (data->is_adam7)
+	{
+	  int klen = 16;
+	  if (data->color_bits == 2)
+	    klen = 32;
+	  if (data->color_bits == 1)
+	    klen = 64;
+	  for (j = 0; j < data->image_height; j++)
+	    {
+	      const grub_uint8_t (*remap)[2] = NULL;
+	      int k;
+
+	      if (data->color_bits == 4)
+		remap = adam7_remap_4bit[j%8];
+	      if (data->color_bits == 2)
+		remap = adam7_remap_2bit[j%8];
+	      if (data->color_bits == 1)
+		remap = adam7_remap_1bit[j%8];
+	      d2 = dc;
+	      dc += data->row_bytes;
+	      for (i = 0, k = 0; i < data->image_width;
+		   i++, d1 += 3)
+		{
+		  grub_uint8_t col = (d2[remap[k][0]] >> remap[k][1]) & mask;
+		  d1[R3] = data->palette[col][2];
+		  d1[G3] = data->palette[col][1];
+		  d1[B3] = data->palette[col][0];
+		  k++;
+		  if (k == klen)
+		    {
+		      d2 += 8;
+		      k = 0;
+		    }
+		}
+	    }
+	}
+      else
+	for (j = 0; j < data->image_height; j++)
+	  {
+	    d2 = dc;
+	    dc += data->row_bytes;
+	    for (i = 0; i < data->image_width;
+		 i++, d1 += 3)
+	      {
+		grub_uint8_t col = (d2[0] >> shift) & mask;
+		d1[R3] = data->palette[col][2];
+		d1[G3] = data->palette[col][1];
+		d1[B3] = data->palette[col][0];
+		shift -= data->color_bits;
+		if (shift < 0)
+		  {
+		    d2++;
+		    shift += 8;
+		  }
+	      }
+	  }
+      return;
+    }
+
   if (data->is_palette)
     {
       for (i = 0; i < (data->image_width * data->image_height);

=== added file 'grub-core/video/readers/png_adam7.c'
--- grub-core/video/readers/png_adam7.c	1970-01-01 00:00:00 +0000
+++ grub-core/video/readers/png_adam7.c	2013-09-28 21:10:18 +0000
@@ -0,0 +1,171 @@
+static const grub_uint8_t adam7_remap_4bit[8][16][2] = 
+  {
+    { { 0, 4 }, { 1, 4 }, { 2, 4 }, { 1, 0 }, { 4, 4 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 0, 0 }, { 5, 4 }, { 6, 4 }, { 5, 0 },
+      { 4, 0 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 0, 0 }, { 1, 4 }, { 1, 0 }, { 2, 4 }, { 2, 0 },
+      { 3, 4 }, { 3, 0 }, { 4, 4 }, { 4, 0 }, { 5, 4 }, { 5, 0 },
+      { 6, 4 }, { 6, 0 }, { 7, 4 }, { 7, 0 }, },
+    { { 0, 4 }, { 1, 4 }, { 0, 0 }, { 1, 0 }, { 2, 4 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 4, 4 }, { 5, 4 }, { 4, 0 }, { 5, 0 },
+      { 6, 4 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 0, 0 }, { 1, 4 }, { 1, 0 }, { 2, 4 }, { 2, 0 },
+      { 3, 4 }, { 3, 0 }, { 4, 4 }, { 4, 0 }, { 5, 4 }, { 5, 0 },
+      { 6, 4 }, { 6, 0 }, { 7, 4 }, { 7, 0 }, },
+    { { 0, 4 }, { 1, 4 }, { 2, 4 }, { 1, 0 }, { 0, 0 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 5, 0 },
+      { 4, 0 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 0, 0 }, { 1, 4 }, { 1, 0 }, { 2, 4 }, { 2, 0 },
+      { 3, 4 }, { 3, 0 }, { 4, 4 }, { 4, 0 }, { 5, 4 }, { 5, 0 },
+      { 6, 4 }, { 6, 0 }, { 7, 4 }, { 7, 0 }, },
+    { { 0, 4 }, { 1, 4 }, { 0, 0 }, { 1, 0 }, { 2, 4 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 4, 4 }, { 5, 4 }, { 4, 0 }, { 5, 0 },
+      { 6, 4 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 0, 0 }, { 1, 4 }, { 1, 0 }, { 2, 4 }, { 2, 0 },
+      { 3, 4 }, { 3, 0 }, { 4, 4 }, { 4, 0 }, { 5, 4 }, { 5, 0 },
+      { 6, 4 }, { 6, 0 }, { 7, 4 }, { 7, 0 }, },
+  };
+
+static const grub_uint8_t adam7_remap_2bit[8][32][2] = 
+  {
+    { { 0, 6 }, { 1, 6 }, { 2, 6 }, { 1, 4 }, { 4, 6 }, { 1, 2 },
+      { 2, 4 }, { 1, 0 }, { 0, 4 }, { 3, 6 }, { 2, 2 }, { 3, 4 },
+      { 4, 4 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 0, 2 }, { 5, 6 },
+      { 6, 6 }, { 5, 4 }, { 4, 2 }, { 5, 2 }, { 6, 4 }, { 5, 0 },
+      { 0, 0 }, { 7, 6 }, { 6, 2 }, { 7, 4 }, { 4, 0 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 0, 4 }, { 0, 2 }, { 0, 0 }, { 1, 6 }, { 1, 4 },
+      { 1, 2 }, { 1, 0 }, { 2, 6 }, { 2, 4 }, { 2, 2 }, { 2, 0 },
+      { 3, 6 }, { 3, 4 }, { 3, 2 }, { 3, 0 }, { 4, 6 }, { 4, 4 },
+      { 4, 2 }, { 4, 0 }, { 5, 6 }, { 5, 4 }, { 5, 2 }, { 5, 0 },
+      { 6, 6 }, { 6, 4 }, { 6, 2 }, { 6, 0 }, { 7, 6 }, { 7, 4 },
+      { 7, 2 }, { 7, 0 }, },
+    { { 0, 6 }, { 1, 6 }, { 0, 4 }, { 1, 4 }, { 0, 2 }, { 1, 2 },
+      { 0, 0 }, { 1, 0 }, { 2, 6 }, { 3, 6 }, { 2, 4 }, { 3, 4 },
+      { 2, 2 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 4, 6 }, { 5, 6 },
+      { 4, 4 }, { 5, 4 }, { 4, 2 }, { 5, 2 }, { 4, 0 }, { 5, 0 },
+      { 6, 6 }, { 7, 6 }, { 6, 4 }, { 7, 4 }, { 6, 2 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 0, 4 }, { 0, 2 }, { 0, 0 }, { 1, 6 }, { 1, 4 },
+      { 1, 2 }, { 1, 0 }, { 2, 6 }, { 2, 4 }, { 2, 2 }, { 2, 0 },
+      { 3, 6 }, { 3, 4 }, { 3, 2 }, { 3, 0 }, { 4, 6 }, { 4, 4 },
+      { 4, 2 }, { 4, 0 }, { 5, 6 }, { 5, 4 }, { 5, 2 }, { 5, 0 },
+      { 6, 6 }, { 6, 4 }, { 6, 2 }, { 6, 0 }, { 7, 6 }, { 7, 4 },
+      { 7, 2 }, { 7, 0 }, },
+    { { 0, 6 }, { 1, 6 }, { 2, 6 }, { 1, 4 }, { 0, 4 }, { 1, 2 },
+      { 2, 4 }, { 1, 0 }, { 0, 2 }, { 3, 6 }, { 2, 2 }, { 3, 4 },
+      { 0, 0 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 4, 6 }, { 5, 6 },
+      { 6, 6 }, { 5, 4 }, { 4, 4 }, { 5, 2 }, { 6, 4 }, { 5, 0 },
+      { 4, 2 }, { 7, 6 }, { 6, 2 }, { 7, 4 }, { 4, 0 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 0, 4 }, { 0, 2 }, { 0, 0 }, { 1, 6 }, { 1, 4 },
+      { 1, 2 }, { 1, 0 }, { 2, 6 }, { 2, 4 }, { 2, 2 }, { 2, 0 },
+      { 3, 6 }, { 3, 4 }, { 3, 2 }, { 3, 0 }, { 4, 6 }, { 4, 4 },
+      { 4, 2 }, { 4, 0 }, { 5, 6 }, { 5, 4 }, { 5, 2 }, { 5, 0 },
+      { 6, 6 }, { 6, 4 }, { 6, 2 }, { 6, 0 }, { 7, 6 }, { 7, 4 },
+      { 7, 2 }, { 7, 0 }, },
+    { { 0, 6 }, { 1, 6 }, { 0, 4 }, { 1, 4 }, { 0, 2 }, { 1, 2 },
+      { 0, 0 }, { 1, 0 }, { 2, 6 }, { 3, 6 }, { 2, 4 }, { 3, 4 },
+      { 2, 2 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 4, 6 }, { 5, 6 },
+      { 4, 4 }, { 5, 4 }, { 4, 2 }, { 5, 2 }, { 4, 0 }, { 5, 0 },
+      { 6, 6 }, { 7, 6 }, { 6, 4 }, { 7, 4 }, { 6, 2 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 0, 4 }, { 0, 2 }, { 0, 0 }, { 1, 6 }, { 1, 4 },
+      { 1, 2 }, { 1, 0 }, { 2, 6 }, { 2, 4 }, { 2, 2 }, { 2, 0 },
+      { 3, 6 }, { 3, 4 }, { 3, 2 }, { 3, 0 }, { 4, 6 }, { 4, 4 },
+      { 4, 2 }, { 4, 0 }, { 5, 6 }, { 5, 4 }, { 5, 2 }, { 5, 0 },
+      { 6, 6 }, { 6, 4 }, { 6, 2 }, { 6, 0 }, { 7, 6 }, { 7, 4 },
+      { 7, 2 }, { 7, 0 }, },
+  };
+
+static const grub_uint8_t adam7_remap_1bit[8][64][2] = 
+  {
+    { { 0, 7 }, { 1, 7 }, { 2, 7 }, { 1, 6 }, { 4, 7 }, { 1, 5 },
+      { 2, 6 }, { 1, 4 }, { 0, 6 }, { 1, 3 }, { 2, 5 }, { 1, 2 },
+      { 4, 6 }, { 1, 1 }, { 2, 4 }, { 1, 0 }, { 0, 5 }, { 3, 7 },
+      { 2, 3 }, { 3, 6 }, { 4, 5 }, { 3, 5 }, { 2, 2 }, { 3, 4 },
+      { 0, 4 }, { 3, 3 }, { 2, 1 }, { 3, 2 }, { 4, 4 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 0, 3 }, { 5, 7 }, { 6, 7 }, { 5, 6 },
+      { 4, 3 }, { 5, 5 }, { 6, 6 }, { 5, 4 }, { 0, 2 }, { 5, 3 },
+      { 6, 5 }, { 5, 2 }, { 4, 2 }, { 5, 1 }, { 6, 4 }, { 5, 0 },
+      { 0, 1 }, { 7, 7 }, { 6, 3 }, { 7, 6 }, { 4, 1 }, { 7, 5 },
+      { 6, 2 }, { 7, 4 }, { 0, 0 }, { 7, 3 }, { 6, 1 }, { 7, 2 },
+      { 4, 0 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 0, 6 }, { 0, 5 }, { 0, 4 }, { 0, 3 }, { 0, 2 },
+      { 0, 1 }, { 0, 0 }, { 1, 7 }, { 1, 6 }, { 1, 5 }, { 1, 4 },
+      { 1, 3 }, { 1, 2 }, { 1, 1 }, { 1, 0 }, { 2, 7 }, { 2, 6 },
+      { 2, 5 }, { 2, 4 }, { 2, 3 }, { 2, 2 }, { 2, 1 }, { 2, 0 },
+      { 3, 7 }, { 3, 6 }, { 3, 5 }, { 3, 4 }, { 3, 3 }, { 3, 2 },
+      { 3, 1 }, { 3, 0 }, { 4, 7 }, { 4, 6 }, { 4, 5 }, { 4, 4 },
+      { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, { 5, 7 }, { 5, 6 },
+      { 5, 5 }, { 5, 4 }, { 5, 3 }, { 5, 2 }, { 5, 1 }, { 5, 0 },
+      { 6, 7 }, { 6, 6 }, { 6, 5 }, { 6, 4 }, { 6, 3 }, { 6, 2 },
+      { 6, 1 }, { 6, 0 }, { 7, 7 }, { 7, 6 }, { 7, 5 }, { 7, 4 },
+      { 7, 3 }, { 7, 2 }, { 7, 1 }, { 7, 0 }, },
+    { { 0, 7 }, { 1, 7 }, { 0, 6 }, { 1, 6 }, { 0, 5 }, { 1, 5 },
+      { 0, 4 }, { 1, 4 }, { 0, 3 }, { 1, 3 }, { 0, 2 }, { 1, 2 },
+      { 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 }, { 2, 7 }, { 3, 7 },
+      { 2, 6 }, { 3, 6 }, { 2, 5 }, { 3, 5 }, { 2, 4 }, { 3, 4 },
+      { 2, 3 }, { 3, 3 }, { 2, 2 }, { 3, 2 }, { 2, 1 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 4, 7 }, { 5, 7 }, { 4, 6 }, { 5, 6 },
+      { 4, 5 }, { 5, 5 }, { 4, 4 }, { 5, 4 }, { 4, 3 }, { 5, 3 },
+      { 4, 2 }, { 5, 2 }, { 4, 1 }, { 5, 1 }, { 4, 0 }, { 5, 0 },
+      { 6, 7 }, { 7, 7 }, { 6, 6 }, { 7, 6 }, { 6, 5 }, { 7, 5 },
+      { 6, 4 }, { 7, 4 }, { 6, 3 }, { 7, 3 }, { 6, 2 }, { 7, 2 },
+      { 6, 1 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 0, 6 }, { 0, 5 }, { 0, 4 }, { 0, 3 }, { 0, 2 },
+      { 0, 1 }, { 0, 0 }, { 1, 7 }, { 1, 6 }, { 1, 5 }, { 1, 4 },
+      { 1, 3 }, { 1, 2 }, { 1, 1 }, { 1, 0 }, { 2, 7 }, { 2, 6 },
+      { 2, 5 }, { 2, 4 }, { 2, 3 }, { 2, 2 }, { 2, 1 }, { 2, 0 },
+      { 3, 7 }, { 3, 6 }, { 3, 5 }, { 3, 4 }, { 3, 3 }, { 3, 2 },
+      { 3, 1 }, { 3, 0 }, { 4, 7 }, { 4, 6 }, { 4, 5 }, { 4, 4 },
+      { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, { 5, 7 }, { 5, 6 },
+      { 5, 5 }, { 5, 4 }, { 5, 3 }, { 5, 2 }, { 5, 1 }, { 5, 0 },
+      { 6, 7 }, { 6, 6 }, { 6, 5 }, { 6, 4 }, { 6, 3 }, { 6, 2 },
+      { 6, 1 }, { 6, 0 }, { 7, 7 }, { 7, 6 }, { 7, 5 }, { 7, 4 },
+      { 7, 3 }, { 7, 2 }, { 7, 1 }, { 7, 0 }, },
+    { { 0, 7 }, { 1, 7 }, { 2, 7 }, { 1, 6 }, { 0, 6 }, { 1, 5 },
+      { 2, 6 }, { 1, 4 }, { 0, 5 }, { 1, 3 }, { 2, 5 }, { 1, 2 },
+      { 0, 4 }, { 1, 1 }, { 2, 4 }, { 1, 0 }, { 0, 3 }, { 3, 7 },
+      { 2, 3 }, { 3, 6 }, { 0, 2 }, { 3, 5 }, { 2, 2 }, { 3, 4 },
+      { 0, 1 }, { 3, 3 }, { 2, 1 }, { 3, 2 }, { 0, 0 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 4, 7 }, { 5, 7 }, { 6, 7 }, { 5, 6 },
+      { 4, 6 }, { 5, 5 }, { 6, 6 }, { 5, 4 }, { 4, 5 }, { 5, 3 },
+      { 6, 5 }, { 5, 2 }, { 4, 4 }, { 5, 1 }, { 6, 4 }, { 5, 0 },
+      { 4, 3 }, { 7, 7 }, { 6, 3 }, { 7, 6 }, { 4, 2 }, { 7, 5 },
+      { 6, 2 }, { 7, 4 }, { 4, 1 }, { 7, 3 }, { 6, 1 }, { 7, 2 },
+      { 4, 0 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 0, 6 }, { 0, 5 }, { 0, 4 }, { 0, 3 }, { 0, 2 },
+      { 0, 1 }, { 0, 0 }, { 1, 7 }, { 1, 6 }, { 1, 5 }, { 1, 4 },
+      { 1, 3 }, { 1, 2 }, { 1, 1 }, { 1, 0 }, { 2, 7 }, { 2, 6 },
+      { 2, 5 }, { 2, 4 }, { 2, 3 }, { 2, 2 }, { 2, 1 }, { 2, 0 },
+      { 3, 7 }, { 3, 6 }, { 3, 5 }, { 3, 4 }, { 3, 3 }, { 3, 2 },
+      { 3, 1 }, { 3, 0 }, { 4, 7 }, { 4, 6 }, { 4, 5 }, { 4, 4 },
+      { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, { 5, 7 }, { 5, 6 },
+      { 5, 5 }, { 5, 4 }, { 5, 3 }, { 5, 2 }, { 5, 1 }, { 5, 0 },
+      { 6, 7 }, { 6, 6 }, { 6, 5 }, { 6, 4 }, { 6, 3 }, { 6, 2 },
+      { 6, 1 }, { 6, 0 }, { 7, 7 }, { 7, 6 }, { 7, 5 }, { 7, 4 },
+      { 7, 3 }, { 7, 2 }, { 7, 1 }, { 7, 0 }, },
+    { { 0, 7 }, { 1, 7 }, { 0, 6 }, { 1, 6 }, { 0, 5 }, { 1, 5 },
+      { 0, 4 }, { 1, 4 }, { 0, 3 }, { 1, 3 }, { 0, 2 }, { 1, 2 },
+      { 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 }, { 2, 7 }, { 3, 7 },
+      { 2, 6 }, { 3, 6 }, { 2, 5 }, { 3, 5 }, { 2, 4 }, { 3, 4 },
+      { 2, 3 }, { 3, 3 }, { 2, 2 }, { 3, 2 }, { 2, 1 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 4, 7 }, { 5, 7 }, { 4, 6 }, { 5, 6 },
+      { 4, 5 }, { 5, 5 }, { 4, 4 }, { 5, 4 }, { 4, 3 }, { 5, 3 },
+      { 4, 2 }, { 5, 2 }, { 4, 1 }, { 5, 1 }, { 4, 0 }, { 5, 0 },
+      { 6, 7 }, { 7, 7 }, { 6, 6 }, { 7, 6 }, { 6, 5 }, { 7, 5 },
+      { 6, 4 }, { 7, 4 }, { 6, 3 }, { 7, 3 }, { 6, 2 }, { 7, 2 },
+      { 6, 1 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 0, 6 }, { 0, 5 }, { 0, 4 }, { 0, 3 }, { 0, 2 },
+      { 0, 1 }, { 0, 0 }, { 1, 7 }, { 1, 6 }, { 1, 5 }, { 1, 4 },
+      { 1, 3 }, { 1, 2 }, { 1, 1 }, { 1, 0 }, { 2, 7 }, { 2, 6 },
+      { 2, 5 }, { 2, 4 }, { 2, 3 }, { 2, 2 }, { 2, 1 }, { 2, 0 },
+      { 3, 7 }, { 3, 6 }, { 3, 5 }, { 3, 4 }, { 3, 3 }, { 3, 2 },
+      { 3, 1 }, { 3, 0 }, { 4, 7 }, { 4, 6 }, { 4, 5 }, { 4, 4 },
+      { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, { 5, 7 }, { 5, 6 },
+      { 5, 5 }, { 5, 4 }, { 5, 3 }, { 5, 2 }, { 5, 1 }, { 5, 0 },
+      { 6, 7 }, { 6, 6 }, { 6, 5 }, { 6, 4 }, { 6, 3 }, { 6, 2 },
+      { 6, 1 }, { 6, 0 }, { 7, 7 }, { 7, 6 }, { 7, 5 }, { 7, 4 },
+      { 7, 3 }, { 7, 2 }, { 7, 1 }, { 7, 0 }, },
+  };


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: Adam7 and narrow PNG
  2013-10-02  0:24 Adam7 and narrow PNG Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-10-02  6:57 ` Melki Christian (consultant)
  2013-10-02  9:28   ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 4+ messages in thread
From: Melki Christian (consultant) @ 2013-10-02  6:57 UTC (permalink / raw)
  To: The development of GNU GRUB

Limited usefullness. I've used a lot of PNG's in GRUB lately and can't think of a reason why I would use either.
Maybe paletted 8-bit (if-that’s what you meant?) to save space.. but adam7? It's still going to be loaded as a bitmap.
If I had some web png's and was to lazy to pass them through a converter...
That beeing said, the work is done and unless it adds rediculous ammount of code size or execution time I'd be fine with the support.

> -----Original Message-----
> From: grub-devel-bounces+christian.melki=saabgroup.com@gnu.org
> [mailto:grub-devel-bounces+christian.melki=saabgroup.com@gnu.org] On
> Behalf Of Vladimir 'f-coder/phcoder' Serbinenko
> Sent: den 2 oktober 2013 02:25
> To: The development of GRUB 2
> Subject: Adam7 and narrow PNG
> 
> It was reported that GRUB doesn't support Adam7 and paletteed PNGs.
> Attached patch would implement both of them but combining them results
> in quite complex code since PNG works on bytes even if bpp <= 4 but
> adam7 works on pixels. Does anyone have thoughts on adam7 and narrow
> PNG usefulness?

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Adam7 and narrow PNG
  2013-10-02  6:57 ` Melki Christian (consultant)
@ 2013-10-02  9:28   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-02 12:05     ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 4+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-10-02  9:28 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 1761 bytes --]

On 02.10.2013 08:57, Melki Christian (consultant) wrote:
> Limited usefullness. I've used a lot of PNG's in GRUB lately and can't think of a reason why I would use either.
> Maybe paletted 8-bit (if-that’s what you meant?) to save space..
8-bit palette is an easy one. The tricky one is 4-/2-/1-bit palettes
(16-/4-/2-color) since then PNG packs several pixels in a single byte.
Usefulness of it to compress image is debatable since although it saves
space by itself, it messes with filter and huffman.
> but adam7? It's still going to be loaded as a bitmap.
> If I had some web png's and was to lazy to pass them through a converter...
The compatibility is the idea. Or if editor used by artist defaults to
adam7 and doesn't have an option (at least not easily accessible one) to
change this behaviour
> That beeing said, the work is done and unless it adds rediculous ammount of code size or execution time I'd be fine with the support.
> 
>> -----Original Message-----
>> From: grub-devel-bounces+christian.melki=saabgroup.com@gnu.org
>> [mailto:grub-devel-bounces+christian.melki=saabgroup.com@gnu.org] On
>> Behalf Of Vladimir 'f-coder/phcoder' Serbinenko
>> Sent: den 2 oktober 2013 02:25
>> To: The development of GRUB 2
>> Subject: Adam7 and narrow PNG
>>
>> It was reported that GRUB doesn't support Adam7 and paletteed PNGs.
>> Attached patch would implement both of them but combining them results
>> in quite complex code since PNG works on bytes even if bpp <= 4 but
>> adam7 works on pixels. Does anyone have thoughts on adam7 and narrow
>> PNG usefulness?
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Adam7 and narrow PNG
  2013-10-02  9:28   ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-10-02 12:05     ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 0 replies; 4+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-10-02 12:05 UTC (permalink / raw)
  To: The development of GNU GRUB


[-- Attachment #1.1: Type: text/plain, Size: 1247 bytes --]

On 02.10.2013 11:28, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> On 02.10.2013 08:57, Melki Christian (consultant) wrote:
>> Limited usefullness. I've used a lot of PNG's in GRUB lately and can't think of a reason why I would use either.
>> Maybe paletted 8-bit (if-that’s what you meant?) to save space..
> 8-bit palette is an easy one. The tricky one is 4-/2-/1-bit palettes
> (16-/4-/2-color) since then PNG packs several pixels in a single byte.
> Usefulness of it to compress image is debatable since although it saves
> space by itself, it messes with filter and huffman.
Narrow PNG part is easy, small, doesn't affect performance of other
supported types and surely useful, so I committed this part.
>> but adam7? It's still going to be loaded as a bitmap.
>> If I had some web png's and was to lazy to pass them through a converter...
> The compatibility is the idea. Or if editor used by artist defaults to
> adam7 and doesn't have an option (at least not easily accessible one) to
> change this behaviour
Remaining (adam7) attached. However this increases pnd.mod by 27% (from
8776 to 11192). I don't know of performance of adam7 compared to normal
png. Complexity involved is not easy either. Any more opinions?

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: adam7.diff --]
[-- Type: text/x-diff; name="adam7.diff", Size: 18923 bytes --]

=== modified file 'grub-core/video/readers/png.c'
--- grub-core/video/readers/png.c	2013-10-02 11:22:56 +0000
+++ grub-core/video/readers/png.c	2013-10-02 11:54:07 +0000
@@ -31,7 +31,6 @@
 
 enum
   {
-    PNG_COLOR_TYPE_GRAY = 0,
     PNG_COLOR_MASK_PALETTE = 1,
     PNG_COLOR_MASK_COLOR = 2,
     PNG_COLOR_MASK_ALPHA = 4,
@@ -40,8 +39,11 @@
 
 #define PNG_COMPRESSION_BASE	0
 
-#define PNG_INTERLACE_NONE	0
-#define PNG_INTERLACE_ADAM7	1
+enum
+  {
+    PNG_INTERLACE_NONE = 0,
+    PNG_INTERLACE_ADAM7 = 1
+  };
 
 #define PNG_FILTER_TYPE_BASE	0
 
@@ -88,6 +90,28 @@
   int num_values, max_length;
 };
 
+struct interlace_stage
+{
+  int start_x, start_y;
+  int log_step_x, log_step_y;
+};
+
+static struct interlace_stage interleave_none[] =
+  {
+    { 0, 0, 0, 0 }
+  };
+
+static struct interlace_stage interleave_adam7[] =
+  {
+    { 0, 0, 3, 3 },
+    { 4, 0, 3, 3 },
+    { 0, 4, 2, 3 },
+    { 2, 0, 2, 2 },
+    { 0, 2, 1, 2 },
+    { 1, 0, 1, 1 },
+    { 0, 1, 0, 1 }
+  };
+
 struct grub_png_data
 {
   grub_file_t file;
@@ -99,7 +123,8 @@
 
   int image_width, image_height, bpp, is_16bit;
   int raw_bytes, is_gray, is_alpha, is_palette;
-  int row_bytes, color_bits;
+  int row_bytes, row_bytes_i, row_bytes_i2, color_bits;
+  int skip;
   grub_uint8_t *image_data;
 
   int inside_idat, idat_remain;
@@ -120,9 +145,15 @@
   grub_uint8_t slide[WSIZE];
   int wp;
 
-  grub_uint8_t *cur_rgb;
+  grub_uint8_t *cur_rgb, *rgb0;
 
   int cur_column, cur_filter, first_line;
+  int cur_component;
+
+  struct interlace_stage *cur_interleave;
+  int n_interleave;
+
+  int is_adam7;
 };
 
 static grub_uint32_t
@@ -246,6 +277,7 @@
   int color_type;
   int color_bits;
   enum grub_video_blit_format blt;
+  grub_uint8_t interleave;
 
   data->image_width = grub_png_get_dword (data);
   data->image_height = grub_png_get_dword (data);
@@ -283,7 +315,8 @@
     }
 
   if ((color_bits != 8) && (color_bits != 16)
-      && (color_bits != 4
+      && ((color_bits != 4 && color_bits != 2
+	   && color_bits != 1)
 	  || !(data->is_gray || data->is_palette)))
     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
                        "png: bit depth must be 8 or 16");
@@ -304,6 +337,9 @@
   if (data->color_bits <= 4)
     data->row_bytes = (data->image_width * data->color_bits + 7) / 8;
 
+  if (data->is_adam7 && data->color_bits <= 4)
+    data->row_bytes += 16;
+
 #ifndef GRUB_CPU_WORDS_BIGENDIAN
   if (data->is_16bit || data->is_gray || data->is_palette)
 #endif
@@ -312,21 +348,16 @@
       if (grub_errno)
         return grub_errno;
 
-      data->cur_rgb = data->image_data;
+      data->rgb0 = data->image_data;
     }
 #ifndef GRUB_CPU_WORDS_BIGENDIAN
   else
     {
       data->image_data = 0;
-      data->cur_rgb = (*data->bitmap)->data;
+      data->rgb0 = (*data->bitmap)->data;
     }
 #endif
 
-  data->raw_bytes = data->image_height * (data->row_bytes + 1);
-
-  data->cur_column = 0;
-  data->first_line = 1;
-
   if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
 		       "png: compression method not supported");
@@ -335,9 +366,22 @@
     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
 		       "png: filter method not supported");
 
-  if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
-    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-		       "png: interlace method not supported");
+  interleave = grub_png_get_byte (data);
+  switch (interleave)
+    {
+    case PNG_INTERLACE_NONE:
+      data->cur_interleave = interleave_none - 1;
+      data->n_interleave = ARRAY_SIZE (interleave_none);
+      break;
+    case PNG_INTERLACE_ADAM7:
+      data->cur_interleave = interleave_adam7 - 1;
+      data->n_interleave = ARRAY_SIZE (interleave_adam7);
+      data->is_adam7 = 1;
+      break;
+    default:
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+			 "png: interlace method not supported");
+    }
 
   /* Skip crc checksum.  */
   grub_png_get_dword (data);
@@ -576,24 +620,85 @@
 static grub_err_t
 grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n)
 {
-  if (--data->raw_bytes < 0)
+  while (data->raw_bytes == 0 && data->n_interleave)
+    {
+      int rows_i, cols_i;
+      data->cur_interleave++;
+
+      data->cur_rgb = data->rgb0;
+
+      if (data->image_width <= data->cur_interleave->start_x)
+	rows_i = 0;
+      else
+	rows_i = ((data->image_width - data->cur_interleave->start_x - 1)
+		  >> data->cur_interleave->log_step_x) + 1;
+
+      if (data->image_height <= data->cur_interleave->start_y)
+	cols_i = 0;
+      else
+	cols_i = ((data->image_height - data->cur_interleave->start_y - 1)
+		  >> data->cur_interleave->log_step_y) + 1;
+      if (data->color_bits <= 4)
+	{
+	  data->row_bytes_i = (rows_i * data->color_bits + 7) / 8;	
+	  data->skip = ((1 << data->cur_interleave->log_step_x) - 1);
+	  data->cur_rgb += data->cur_interleave->start_x;
+	}
+      else
+	{
+	  data->row_bytes_i = rows_i * data->bpp;
+
+	  data->skip = ((1 << data->cur_interleave->log_step_x) - 1) * data->bpp;
+	  data->cur_rgb += data->cur_interleave->start_x * data->bpp;
+	}
+
+      data->row_bytes_i2 = data->row_bytes_i
+	+ data->skip * (data->row_bytes_i / data->bpp);
+
+      data->raw_bytes = cols_i * (data->row_bytes_i + 1);
+
+      data->cur_column = 0;
+      data->cur_filter = 0;
+      data->first_line = 1;
+      data->cur_component = 0;
+      data->cur_rgb += data->cur_interleave->start_y * data->row_bytes;
+      data->n_interleave--;
+      grub_printf ("{%d}",n);
+    }
+
+  data->raw_bytes--;
+
+  if (data->raw_bytes < 0)
     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflown");
 
   if (data->cur_column == 0)
     {
+      grub_printf ("<%d>",n);
       if (n >= PNG_FILTER_VALUE_LAST)
-	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid filter value");
+	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid filter value %d", n);
 
       data->cur_filter = n;
+      if (!data->first_line)
+	data->cur_rgb += (1 << data->cur_interleave->log_step_y)
+	  * data->row_bytes - data->row_bytes_i2;
     }
   else
-    *data->cur_rgb++ = n;
+    {
+      *data->cur_rgb++ = n;
+      data->cur_component++;
+      if (data->cur_component == data->bpp)
+	{
+	  data->cur_component = 0;
+	  data->cur_rgb += data->skip;
+	}
+    }
 
   data->cur_column++;
-  if (data->cur_column == data->row_bytes + 1)
+
+  if (data->cur_column == data->row_bytes_i + 1)
     {
       grub_uint8_t *blank_line = NULL;
-      grub_uint8_t *cur = data->cur_rgb - data->row_bytes;
+      grub_uint8_t *cur = data->cur_rgb - data->row_bytes_i2;
       grub_uint8_t *left = cur;
       grub_uint8_t *up;
 
@@ -606,71 +711,109 @@
 	  up = blank_line;
 	}
       else
-	up = cur - data->row_bytes;
+	up = cur - (data->row_bytes << data->cur_interleave->log_step_y);
 
       switch (data->cur_filter)
 	{
 	case PNG_FILTER_VALUE_SUB:
 	  {
-	    int i;
+	    int i, j;
 
-	    cur += data->bpp;
-	    for (i = data->bpp; i < data->row_bytes; i++, cur++, left++)
-	      *cur += *left;
+	    cur += data->bpp + data->skip;
+	    for (i = data->bpp; i < data->row_bytes; )
+	      {
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    *cur += *left;
+		    i++, cur++, left++;
+		  }
+		i += data->skip;
+		cur += data->skip;
+		left += data->skip;
+	      }
 
 	    break;
 	  }
 	case PNG_FILTER_VALUE_UP:
 	  {
-	    int i;
-
-	    for (i = 0; i < data->row_bytes; i++, cur++, up++)
-	      *cur += *up;
-
+	    int i, j;
+
+	    for (i = 0; i < data->row_bytes; )
+	      {
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    *cur += *up;
+		    i++, cur++, up++;
+		  }
+		i += data->skip;
+		cur += data->skip;
+		up += data->skip;
+	      }
 	    break;
 	  }
 	case PNG_FILTER_VALUE_AVG:
 	  {
-	    int i;
+	    int i, j;
 
 	    for (i = 0; i < data->bpp; i++, cur++, up++)
 	      *cur += *up >> 1;
 
-	    for (; i < data->row_bytes; i++, cur++, up++, left++)
-	      *cur += ((int) *up + (int) *left) >> 1;
+	    i += data->skip;
+	    cur += data->skip;
+	    up += data->skip;
+
+	    for (; i < data->row_bytes; )
+	      {
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    *cur += ((int) *up + (int) *left) >> 1;
+		    i++, cur++, up++, left++;
+		  }
+		i+= data->skip, cur+= data->skip, up+= data->skip, left+= data->skip;
+	      }
 
 	    break;
 	  }
 	case PNG_FILTER_VALUE_PAETH:
 	  {
-	    int i;
+	    int i, j;
 	    grub_uint8_t *upper_left = up;
 
 	    for (i = 0; i < data->bpp; i++, cur++, up++)
 	      *cur += *up;
 
-	    for (; i < data->row_bytes; i++, cur++, up++, left++, upper_left++)
+	    i += data->skip;
+	    cur += data->skip;
+	    up += data->skip;
+
+	    for (; i < data->row_bytes; )
 	      {
-		int a, b, c, pa, pb, pc;
-
-                a = *left;
-                b = *up;
-                c = *upper_left;
-
-                pa = b - c;
-                pb = a - c;
-                pc = pa + pb;
-
-                if (pa < 0)
-                  pa = -pa;
-
-                if (pb < 0)
-                  pb = -pb;
-
-                if (pc < 0)
-                  pc = -pc;
-
-                *cur += ((pa <= pb) && (pa <= pc)) ? a : (pb <= pc) ? b : c;
+		for (j = 0; j < data->bpp; j++)
+		  {
+		    int a, b, c, pa, pb, pc;
+
+		    a = *left;
+		    b = *up;
+		    c = *upper_left;
+
+		    pa = b - c;
+		    pb = a - c;
+		    pc = pa + pb;
+
+		    if (pa < 0)
+		      pa = -pa;
+
+		    if (pb < 0)
+		      pb = -pb;
+
+		    if (pc < 0)
+		      pc = -pc;
+
+		    *cur += ((pa <= pb) && (pa <= pc)) ? a : (pb <= pc) ? b : c;
+		    i++, cur++, up++, left++, upper_left++;
+		  }
+		i+=data->skip, cur+=data->skip, up+=data->skip;
+		left+=data->skip, upper_left+=data->skip;
 	      }
 	  }
 	}
@@ -815,6 +958,8 @@
 static const grub_uint8_t png_magic[8] =
   { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0x0a };
 
+#include "png_adam7.c"
+
 static void
 grub_png_convert_image (struct grub_png_data *data)
 {
@@ -845,7 +990,7 @@
   if (data->color_bits <= 4)
     {
       grub_uint8_t palette[16][3];
-      grub_uint8_t *d1c, *d2c;
+      grub_uint8_t *dc;
       int shift;
       int mask = (1 << data->color_bits) - 1;
       int j;
@@ -859,28 +1004,88 @@
 	  }
       else
 	grub_memcpy (palette, data->palette, 16 * 3);
-      d1c = d1;
-      d2c = d2;
-      for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3,
-	   d2c += data->row_bytes)
+      dc = d2;
+      /* Our algorithms work on bytes in case of color depth <= 4.
+	 Usually it's no problem as PNG specs does the same. However
+	 Adam7 always works on pixels, so we need this additional shuffling.
+      */
+      if (data->is_adam7)
 	{
-	  d1 = d1c;
-	  d2 = d2c;
-	  shift = 8 - data->color_bits;
-	  for (i = 0; i < data->image_width; i++, d1 += 3)
-	    {
-	      grub_uint8_t col = (d2[0] >> shift) & mask;
-	      d1[R3] = data->palette[col][2];
-	      d1[G3] = data->palette[col][1];
-	      d1[B3] = data->palette[col][0];
-	      shift -= data->color_bits;
-	      if (shift < 0)
-		{
-		  d2++;
-		  shift += 8;
-		}
-	    }
+	  int klen = 16;
+	  if (data->color_bits == 2)
+	    klen = 32;
+	  if (data->color_bits == 1)
+	    klen = 64;
+	  for (j = 0; j < data->image_height; j++,
+	       dc += data->row_bytes)
+	    if (j & 1)
+	      {
+		d2 = dc;
+		shift = 8 - data->color_bits;
+		for (i = 0; i < data->image_width;
+		     i++, d1 += 3)
+		  {
+		    grub_uint8_t col = (d2[0] >> shift) & mask;
+		    d1[R3] = data->palette[col][2];
+		    d1[G3] = data->palette[col][1];
+		    d1[B3] = data->palette[col][0];
+		    shift -= data->color_bits;
+		    if (shift < 0)
+		      {
+			d2++;
+			shift += 8;
+		      }
+		  }
+	      }
+	    else
+	      {
+		const grub_uint8_t (*remap)[2] = NULL;
+		int k;
+
+		if (data->color_bits == 4)
+		  remap = adam7_remap_4bit[(j & 7) >> 1];
+		if (data->color_bits == 2)
+		  remap = adam7_remap_2bit[(j & 7) >> 1];
+		if (data->color_bits == 1)
+		  remap = adam7_remap_1bit[(j & 7) >> 1];
+		d2 = dc;
+		for (i = 0, k = 0; i < data->image_width;
+		     i++, d1 += 3)
+		  {
+		    grub_uint8_t col = (d2[remap[k][0]] >> remap[k][1]) & mask;
+		    d1[R3] = data->palette[col][2];
+		    d1[G3] = data->palette[col][1];
+		    d1[B3] = data->palette[col][0];
+		    k++;
+		    if (k == klen)
+		      {
+			d2 += 8;
+			k = 0;
+		      }
+		  }
+	      }
 	}
+      else
+	for (j = 0; j < data->image_height; j++)
+	  {
+	    d2 = dc;
+	    dc += data->row_bytes;
+	    shift = 8 - data->color_bits;
+	    for (i = 0; i < data->image_width;
+		 i++, d1 += 3)
+	      {
+		grub_uint8_t col = (d2[0] >> shift) & mask;
+		d1[R3] = data->palette[col][2];
+		d1[G3] = data->palette[col][1];
+		d1[B3] = data->palette[col][0];
+		shift -= data->color_bits;
+		if (shift < 0)
+		  {
+		    d2++;
+		    shift += 8;
+		  }
+	      }
+	  }
       return;
     }
 

=== added file 'grub-core/video/readers/png_adam7.c'
--- grub-core/video/readers/png_adam7.c	1970-01-01 00:00:00 +0000
+++ grub-core/video/readers/png_adam7.c	2013-10-02 09:39:56 +0000
@@ -0,0 +1,91 @@
+static const grub_uint8_t adam7_remap_4bit[4][16][2] = 
+  {
+    { { 0, 4 }, { 1, 4 }, { 2, 4 }, { 1, 0 }, { 4, 4 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 0, 0 }, { 5, 4 }, { 6, 4 }, { 5, 0 },
+      { 4, 0 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 1, 4 }, { 0, 0 }, { 1, 0 }, { 2, 4 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 4, 4 }, { 5, 4 }, { 4, 0 }, { 5, 0 },
+      { 6, 4 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 1, 4 }, { 2, 4 }, { 1, 0 }, { 0, 0 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 5, 0 },
+      { 4, 0 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 4 }, { 1, 4 }, { 0, 0 }, { 1, 0 }, { 2, 4 }, { 3, 4 },
+      { 2, 0 }, { 3, 0 }, { 4, 4 }, { 5, 4 }, { 4, 0 }, { 5, 0 },
+      { 6, 4 }, { 7, 4 }, { 6, 0 }, { 7, 0 }, },
+  };
+
+static const grub_uint8_t adam7_remap_2bit[4][32][2] = 
+  {
+    { { 0, 6 }, { 1, 6 }, { 2, 6 }, { 1, 4 }, { 4, 6 }, { 1, 2 },
+      { 2, 4 }, { 1, 0 }, { 0, 4 }, { 3, 6 }, { 2, 2 }, { 3, 4 },
+      { 4, 4 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 0, 2 }, { 5, 6 },
+      { 6, 6 }, { 5, 4 }, { 4, 2 }, { 5, 2 }, { 6, 4 }, { 5, 0 },
+      { 0, 0 }, { 7, 6 }, { 6, 2 }, { 7, 4 }, { 4, 0 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 1, 6 }, { 0, 4 }, { 1, 4 }, { 0, 2 }, { 1, 2 },
+      { 0, 0 }, { 1, 0 }, { 2, 6 }, { 3, 6 }, { 2, 4 }, { 3, 4 },
+      { 2, 2 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 4, 6 }, { 5, 6 },
+      { 4, 4 }, { 5, 4 }, { 4, 2 }, { 5, 2 }, { 4, 0 }, { 5, 0 },
+      { 6, 6 }, { 7, 6 }, { 6, 4 }, { 7, 4 }, { 6, 2 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 1, 6 }, { 2, 6 }, { 1, 4 }, { 0, 4 }, { 1, 2 },
+      { 2, 4 }, { 1, 0 }, { 0, 2 }, { 3, 6 }, { 2, 2 }, { 3, 4 },
+      { 0, 0 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 4, 6 }, { 5, 6 },
+      { 6, 6 }, { 5, 4 }, { 4, 4 }, { 5, 2 }, { 6, 4 }, { 5, 0 },
+      { 4, 2 }, { 7, 6 }, { 6, 2 }, { 7, 4 }, { 4, 0 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+    { { 0, 6 }, { 1, 6 }, { 0, 4 }, { 1, 4 }, { 0, 2 }, { 1, 2 },
+      { 0, 0 }, { 1, 0 }, { 2, 6 }, { 3, 6 }, { 2, 4 }, { 3, 4 },
+      { 2, 2 }, { 3, 2 }, { 2, 0 }, { 3, 0 }, { 4, 6 }, { 5, 6 },
+      { 4, 4 }, { 5, 4 }, { 4, 2 }, { 5, 2 }, { 4, 0 }, { 5, 0 },
+      { 6, 6 }, { 7, 6 }, { 6, 4 }, { 7, 4 }, { 6, 2 }, { 7, 2 },
+      { 6, 0 }, { 7, 0 }, },
+  };
+
+static const grub_uint8_t adam7_remap_1bit[4][64][2] = 
+  {
+    { { 0, 7 }, { 1, 7 }, { 2, 7 }, { 1, 6 }, { 4, 7 }, { 1, 5 },
+      { 2, 6 }, { 1, 4 }, { 0, 6 }, { 1, 3 }, { 2, 5 }, { 1, 2 },
+      { 4, 6 }, { 1, 1 }, { 2, 4 }, { 1, 0 }, { 0, 5 }, { 3, 7 },
+      { 2, 3 }, { 3, 6 }, { 4, 5 }, { 3, 5 }, { 2, 2 }, { 3, 4 },
+      { 0, 4 }, { 3, 3 }, { 2, 1 }, { 3, 2 }, { 4, 4 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 0, 3 }, { 5, 7 }, { 6, 7 }, { 5, 6 },
+      { 4, 3 }, { 5, 5 }, { 6, 6 }, { 5, 4 }, { 0, 2 }, { 5, 3 },
+      { 6, 5 }, { 5, 2 }, { 4, 2 }, { 5, 1 }, { 6, 4 }, { 5, 0 },
+      { 0, 1 }, { 7, 7 }, { 6, 3 }, { 7, 6 }, { 4, 1 }, { 7, 5 },
+      { 6, 2 }, { 7, 4 }, { 0, 0 }, { 7, 3 }, { 6, 1 }, { 7, 2 },
+      { 4, 0 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 1, 7 }, { 0, 6 }, { 1, 6 }, { 0, 5 }, { 1, 5 },
+      { 0, 4 }, { 1, 4 }, { 0, 3 }, { 1, 3 }, { 0, 2 }, { 1, 2 },
+      { 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 }, { 2, 7 }, { 3, 7 },
+      { 2, 6 }, { 3, 6 }, { 2, 5 }, { 3, 5 }, { 2, 4 }, { 3, 4 },
+      { 2, 3 }, { 3, 3 }, { 2, 2 }, { 3, 2 }, { 2, 1 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 4, 7 }, { 5, 7 }, { 4, 6 }, { 5, 6 },
+      { 4, 5 }, { 5, 5 }, { 4, 4 }, { 5, 4 }, { 4, 3 }, { 5, 3 },
+      { 4, 2 }, { 5, 2 }, { 4, 1 }, { 5, 1 }, { 4, 0 }, { 5, 0 },
+      { 6, 7 }, { 7, 7 }, { 6, 6 }, { 7, 6 }, { 6, 5 }, { 7, 5 },
+      { 6, 4 }, { 7, 4 }, { 6, 3 }, { 7, 3 }, { 6, 2 }, { 7, 2 },
+      { 6, 1 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 1, 7 }, { 2, 7 }, { 1, 6 }, { 0, 6 }, { 1, 5 },
+      { 2, 6 }, { 1, 4 }, { 0, 5 }, { 1, 3 }, { 2, 5 }, { 1, 2 },
+      { 0, 4 }, { 1, 1 }, { 2, 4 }, { 1, 0 }, { 0, 3 }, { 3, 7 },
+      { 2, 3 }, { 3, 6 }, { 0, 2 }, { 3, 5 }, { 2, 2 }, { 3, 4 },
+      { 0, 1 }, { 3, 3 }, { 2, 1 }, { 3, 2 }, { 0, 0 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 4, 7 }, { 5, 7 }, { 6, 7 }, { 5, 6 },
+      { 4, 6 }, { 5, 5 }, { 6, 6 }, { 5, 4 }, { 4, 5 }, { 5, 3 },
+      { 6, 5 }, { 5, 2 }, { 4, 4 }, { 5, 1 }, { 6, 4 }, { 5, 0 },
+      { 4, 3 }, { 7, 7 }, { 6, 3 }, { 7, 6 }, { 4, 2 }, { 7, 5 },
+      { 6, 2 }, { 7, 4 }, { 4, 1 }, { 7, 3 }, { 6, 1 }, { 7, 2 },
+      { 4, 0 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+    { { 0, 7 }, { 1, 7 }, { 0, 6 }, { 1, 6 }, { 0, 5 }, { 1, 5 },
+      { 0, 4 }, { 1, 4 }, { 0, 3 }, { 1, 3 }, { 0, 2 }, { 1, 2 },
+      { 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 }, { 2, 7 }, { 3, 7 },
+      { 2, 6 }, { 3, 6 }, { 2, 5 }, { 3, 5 }, { 2, 4 }, { 3, 4 },
+      { 2, 3 }, { 3, 3 }, { 2, 2 }, { 3, 2 }, { 2, 1 }, { 3, 1 },
+      { 2, 0 }, { 3, 0 }, { 4, 7 }, { 5, 7 }, { 4, 6 }, { 5, 6 },
+      { 4, 5 }, { 5, 5 }, { 4, 4 }, { 5, 4 }, { 4, 3 }, { 5, 3 },
+      { 4, 2 }, { 5, 2 }, { 4, 1 }, { 5, 1 }, { 4, 0 }, { 5, 0 },
+      { 6, 7 }, { 7, 7 }, { 6, 6 }, { 7, 6 }, { 6, 5 }, { 7, 5 },
+      { 6, 4 }, { 7, 4 }, { 6, 3 }, { 7, 3 }, { 6, 2 }, { 7, 2 },
+      { 6, 1 }, { 7, 1 }, { 6, 0 }, { 7, 0 }, },
+  };


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-10-02 12:05 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-02  0:24 Adam7 and narrow PNG Vladimir 'φ-coder/phcoder' Serbinenko
2013-10-02  6:57 ` Melki Christian (consultant)
2013-10-02  9:28   ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-10-02 12:05     ` Vladimir 'φ-coder/phcoder' Serbinenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).