]> git.cworth.org Git - apitrace/blobdiff - image/image_png.cpp
image: Allow to read PNG from a C++ stream.
[apitrace] / image / image_png.cpp
index dba07d45ea14e4864d451b4896ea2723544a74b8..324cfe9814ee53ccbc8842fed32b0ca245b56329 100644 (file)
@@ -123,19 +123,34 @@ no_png:
 }
 
 
+bool
+Image::writePNG(const char *filename) const
+{
+    std::ofstream os(filename, std::ofstream::binary);
+    if (!os) {
+        return false;
+    }
+    return writePNG(os);
+}
+
+
+static void
+pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+    std::istream *os = (std::istream *) png_get_io_ptr(png_ptr);
+    os->read((char *)data, length);
+}
+
+
 Image *
-readPNG(const char *filename)
+readPNG(std::istream &is)
 {
-    FILE *fp;
     png_structp png_ptr;
     png_infop info_ptr;
     png_infop end_info;
+    unsigned channels;
     Image *image;
 
-    fp = fopen(filename, "rb");
-    if (!fp)
-        goto no_fp;
-
     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
     if (!png_ptr)
         goto no_png;
@@ -157,7 +172,7 @@ readPNG(const char *filename)
         goto no_png;
     }
 
-    png_init_io(png_ptr, fp);
+    png_set_read_fn(png_ptr, &is, pngReadCallback);
 
     png_read_info(png_ptr, info_ptr);
 
@@ -169,10 +184,6 @@ readPNG(const char *filename)
                  &bit_depth, &color_type, &interlace_type,
                  &compression_type, &filter_method);
 
-    image = new Image(width, height);
-    if (!image)
-        goto no_image;
-
     /* Convert to RGBA8 */
     if (color_type == PNG_COLOR_TYPE_PALETTE)
         png_set_palette_to_rgb(png_ptr);
@@ -183,24 +194,37 @@ readPNG(const char *filename)
     if (bit_depth == 16)
         png_set_strip_16(png_ptr);
 
+    channels = png_get_channels(png_ptr, info_ptr);
+    image = new Image(width, height, channels);
+    if (!image)
+        goto no_image;
+
+    assert(png_get_rowbytes(png_ptr, info_ptr) == width*channels);
     for (unsigned y = 0; y < height; ++y) {
-        png_bytep row = (png_bytep)(image->pixels + y*width*4);
+        png_bytep row = (png_bytep)(image->pixels + y*width*channels);
         png_read_row(png_ptr, row, NULL);
     }
 
     png_read_end(png_ptr, info_ptr);
     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-    fclose(fp);
+
     return image;
 
 no_image:
     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 no_png:
-    fclose(fp);
-no_fp:
     return NULL;
 }
 
+Image *
+readPNG(const char *filename)
+{
+    std::ifstream is(filename, std::ifstream::binary);
+    if (!is) {
+        return NULL;
+    }
+    return readPNG(filename);
+}
 
 
 } /* namespace image */