浏览代码

rewrite HDR rle logic

Sean Barrett 10 年之前
父节点
当前提交
22fa9a467a
共有 2 个文件被更改,包括 54 次插入45 次删除
  1. 40 45
      stb_image_write.h
  2. 14 0
      tests/image_test.c

+ 40 - 45
stb_image_write.h

@@ -1,4 +1,4 @@
-/* stb_image_write - v0.96 - public domain - http://nothings.org/stb/stb_image_write.h
+/* stb_image_write - v0.97 - public domain - http://nothings.org/stb/stb_image_write.h
    writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
                             no warranty implied; use at your own risk
 
@@ -229,18 +229,18 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
    }
 }
 
-void stbiw__write_rle_data(FILE *f, int length, unsigned char databyte)
+void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
 {
-   unsigned char lengthbyte = 0x80 | (unsigned char)(length & 0x7f);
-   assert(length <= 0x7f);
+   unsigned char lengthbyte = (unsigned char) (length+128);
+   assert(length+128 <= 255);
    fwrite(&lengthbyte, 1, 1, f);
    fwrite(&databyte, 1, 1, f);
 }
 
-void stbiw__write_nonrle_data(FILE *f, int length, unsigned char *data)
+void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
 {
    unsigned char lengthbyte = (unsigned char )(length & 0xff);
-   assert(length <= 0x7f);
+   assert(length <= 128); // inconsistent with spec but consistent with official code
    fwrite(&lengthbyte, 1, 1, f);
    fwrite(data, length, 1, f);
 }
@@ -272,6 +272,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
          fwrite(rgbe, 4, 1, f);
       }
    } else {
+      int c,r;
       /* encode into scratch buffer */
       for (x=0; x < width; x++) {
          switch(comp) {
@@ -294,50 +295,42 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
       fwrite(scanlineheader, 4, 1, f);
 
       /* RLE each component separately */
-      for (x=0; x < 4; x++) {
-         unsigned char *comp = &scratch[width*x];
+      for (c=0; c < 4; c++) {
+         unsigned char *comp = &scratch[width*c];
          int runstart = 0, head = 0, rlerun = 0;
 
-         while (head < width) {
-            head++;
-
-            if (head - runstart == 127 && rlerun == 1) {
-               // max length RLE run
-               stbiw__write_rle_data(f, head - runstart, comp[runstart]);
-               rlerun = 0;
-               runstart = head;
-            } else if (head - runstart == 128 && rlerun == 0) {
-               // max length non-RLE run
-               stbiw__write_nonrle_data(f, head - runstart, comp+runstart);
-               rlerun = 0;
-               runstart = head;
-            } else if (comp[head] != comp[head-1] && rlerun == 1) {
-               // end of RLE run
-               stbiw__write_rle_data(f, head - runstart, comp[runstart]);
-               rlerun = 0;
-               runstart = head;
-            } else {
-               // continue accumulating RLE run
-               if (rlerun == 1) continue;
-
-               // see if we can start an RLE run, at least 3 bytes same
-               if (rlerun == 0 && head - runstart >= 2
-                    && comp[head] == comp[head-1]
-                    && comp[head] == comp[head-2]) {
-                  // found a run. Flush non-run (if there is anything) and then start an RLE run
-                  if (head - runstart > 2) {
-                     stbiw__write_nonrle_data(f, head-2 - runstart, comp+runstart);
-                  }
-
-                  rlerun = 1;
-                  runstart = head-2;
+         x = 0;
+         while (x < width) {
+            // find first run
+            r = x;
+            while (r+2 < width) {
+               if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
+                  break;
+               ++r;
+            }
+            if (r+2 >= width)
+               r = width;
+            // dump up to first run
+            while (x < r) {
+               int len = r-x;
+               if (len > 128) len = 128;
+               stbiw__write_dump_data(f, len, &comp[x]);
+               x += len;
+            }
+            // if there's a run, output it
+            if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
+               // find next byte after run
+               while (r < width && comp[r] == comp[x])
+                  ++r; 
+               // output run up to r
+               while (x < r) {
+                  int len = r-x;
+                  if (len > 127) len = 127;
+                  stbiw__write_run_data(f, len, comp[x]);
+                  x += len;
                }
             }
          }
-
-         // flush remaining sequence (if any)
-         if      (rlerun == 1)         stbiw__write_rle_data(f, head - runstart, comp[runstart]);
-         else if (head - runstart > 0) stbiw__write_nonrle_data(f, head - runstart, comp+runstart);
       }
    }
 }
@@ -686,6 +679,8 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
 
 /* Revision history
 
+      0.97 (2015-01-18)
+             fixed HDR asserts, rewrote HDR rle logic
       0.96 (2015-01-17)
              add HDR output
              fix monochrome BMP

+ 14 - 0
tests/image_test.c

@@ -51,10 +51,24 @@ void test_ycbcr(void)
 }
 #endif
 
+float hdr_data[200][200][3];
+
 int main(int argc, char **argv)
 {
    int w,h;
    //test_ycbcr();
+
+   #if 0
+   // test hdr asserts
+   for (h=0; h < 100; h += 2)
+      for (w=0; w < 200; ++w)
+         hdr_data[h][w][0] = (float) rand(),
+         hdr_data[h][w][1] = (float) rand(),
+         hdr_data[h][w][2] = (float) rand();
+
+   stbi_write_hdr("output/test.hdr", 200,200,3,hdr_data[0][0]);
+   #endif
+
    if (argc > 1) {
       int i, n;