Browse Source

Rplaced image read function (Closes: #3158)

Patch was created by Nicola Viganò. Thanks.

Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>

git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/slim/trunk@215 7c53e7cc-98ea-0310-8f1f-a0b24da60408
iwamatsu 11 years ago
parent
commit
3a491ca0ea
2 changed files with 240 additions and 8 deletions
  1. 235 7
      image.cpp
  2. 5 1
      image.h

+ 235 - 7
image.cpp

@@ -24,11 +24,8 @@ using namespace std;
 #include "image.h"
 
 extern "C" {
-    int
-    read_png(const char *filename, int *width, int *height, unsigned char **rgb,
-             unsigned char **alpha);
-    int
-    read_jpeg(const char *filename, int *width, int *height, unsigned char **rgb);
+    #include <jpeglib.h>
+    #include <png.h>
 }
 
 Image::Image() : width(0), height(0), area(0),
@@ -73,10 +70,10 @@ Image::Read(const char *filename) {
     fclose(file);
 
     if ((ubuf[0] == 0x89) && !strncmp("PNG", buf+1, 3)) {
-        success = read_png(filename, &width, &height, &rgb_data, &png_alpha);
+        success = readPng(filename, &width, &height, &rgb_data, &png_alpha);
     }
     else if ((ubuf[0] == 0xff) && (ubuf[1] == 0xd8)){
-        success = read_jpeg(filename, &width, &height, &rgb_data);
+        success = readJpeg(filename, &width, &height, &rgb_data);
     } else {
         fprintf(stderr, "Unknown image format\n");
         success = 0;
@@ -666,3 +663,234 @@ Image::createPixmap(Display* dpy, int scr, Window win) {
     return(tmp);
 }
 
+int
+Image::readJpeg(const char *filename, int *width, int *height,
+                unsigned char **rgb)
+{
+    int ret = 0;
+    struct jpeg_decompress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    unsigned char *ptr = NULL;
+
+    FILE *infile = fopen(filename, "rb");
+    if (infile == NULL) {
+        logStream << APPNAME << "Cannot fopen file: " << filename << endl;
+        return ret;
+    }
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_decompress(&cinfo);
+    jpeg_stdio_src(&cinfo, infile);
+    jpeg_read_header(&cinfo, TRUE);
+    jpeg_start_decompress(&cinfo);
+
+    /* Prevent against integer overflow */
+    if(cinfo.output_width >= MAX_DIMENSION
+       || cinfo.output_height >= MAX_DIMENSION)
+    {
+        logStream << APPNAME << "Unreasonable dimension found in file: "
+                  << filename << endl;
+        goto close_file;
+    }
+
+    *width = cinfo.output_width;
+    *height = cinfo.output_height;
+
+    rgb[0] = (unsigned char*)
+                malloc(3 * cinfo.output_width * cinfo.output_height);
+    if (rgb[0] == NULL) {
+        logStream << APPNAME << ": Can't allocate memory for JPEG file."
+                  << endl;
+        goto close_file;
+    }
+
+    if (cinfo.output_components == 3) {
+        ptr = rgb[0];
+        while (cinfo.output_scanline < cinfo.output_height) {
+            jpeg_read_scanlines(&cinfo, &ptr, 1);
+            ptr += 3 * cinfo.output_width;
+        }
+    } else if (cinfo.output_components == 1) {
+        ptr = (unsigned char*) malloc(cinfo.output_width);
+        if (ptr == NULL) {
+            logStream << APPNAME << ": Can't allocate memory for JPEG file."
+                      << endl;
+            goto rgb_free;
+        }
+
+        unsigned int ipos = 0;
+        while (cinfo.output_scanline < cinfo.output_height) {
+            jpeg_read_scanlines(&cinfo, &ptr, 1);
+
+            for (unsigned int i = 0; i < cinfo.output_width; i++) {
+                memset(rgb[0] + ipos, ptr[i], 3);
+                ipos += 3;
+            }
+        }
+
+        free(ptr);
+    }
+
+    jpeg_finish_decompress(&cinfo);
+
+    ret = 1;
+    goto close_file;
+
+rgb_free:
+    free(rgb[0]);
+
+close_file:
+    jpeg_destroy_decompress(&cinfo);
+    fclose(infile);
+
+    return(ret);
+}
+
+int
+Image::readPng(const char *filename, int *width, int *height,
+               unsigned char **rgb, unsigned char **alpha)
+{
+    int ret = 0;
+
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_bytepp row_pointers;
+
+    unsigned char *ptr = NULL;
+    png_uint_32 w, h;
+    int bit_depth, color_type, interlace_type;
+    int i;
+
+    FILE *infile = fopen(filename, "rb");
+    if (infile == NULL) {
+        logStream << APPNAME << "Can not fopen file: " << filename << endl;
+        return ret;
+    }
+
+    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+                                     (png_voidp) NULL,
+                                     (png_error_ptr) NULL,
+                                     (png_error_ptr) NULL);
+    if (!png_ptr) {
+        goto file_close;
+    }
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_read_struct(&png_ptr, (png_infopp) NULL,
+                                (png_infopp) NULL);
+    }
+
+    if (setjmp(png_ptr->jmpbuf)) {
+        goto png_destroy;
+    }
+
+    png_init_io(png_ptr, infile);
+    png_read_info(png_ptr, info_ptr);
+
+    png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
+                 &interlace_type, (int *) NULL, (int *) NULL);
+
+    /* Prevent against integer overflow */
+    if(w >= MAX_DIMENSION || h >= MAX_DIMENSION) {
+        logStream << APPNAME << "Unreasonable dimension found in file: "
+                  << filename << endl;
+        goto png_destroy;
+    }
+
+    *width = (int) w;
+    *height = (int) h;
+
+    if (color_type == PNG_COLOR_TYPE_RGB_ALPHA
+        || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+    {
+        alpha[0] = (unsigned char *) malloc(*width * *height);
+        if (alpha[0] == NULL) {
+            logStream << APPNAME
+                    << ": Can't allocate memory for alpha channel in PNG file."
+                    << endl;
+            goto png_destroy;
+        }
+    }
+
+    /* Change a paletted/grayscale image to RGB */
+    if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
+    {
+        png_set_expand(png_ptr);
+    }
+
+    /* Change a grayscale image to RGB */
+    if (color_type == PNG_COLOR_TYPE_GRAY
+        || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+    {
+        png_set_gray_to_rgb(png_ptr);
+    }
+
+    /* If the PNG file has 16 bits per channel, strip them down to 8 */
+    if (bit_depth == 16) {
+      png_set_strip_16(png_ptr);
+    }
+
+    /* use 1 byte per pixel */
+    png_set_packing(png_ptr);
+
+    row_pointers = (png_byte **) malloc(*height * sizeof(png_bytep));
+    if (row_pointers == NULL) {
+        logStream << APPNAME << ": Can't allocate memory for PNG file." << endl;
+        goto png_destroy;
+    }
+
+    for (i = 0; i < *height; i++) {
+        row_pointers[i] = (png_byte*) malloc(4 * *width);
+        if (row_pointers == NULL) {
+            logStream << APPNAME << ": Can't allocate memory for PNG file."
+                      << endl;
+            goto rows_free;
+        }
+    }
+
+    png_read_image(png_ptr, row_pointers);
+
+    rgb[0] = (unsigned char *) malloc(3 * (*width) * (*height));
+    if (rgb[0] == NULL) {
+        logStream << APPNAME << ": Can't allocate memory for PNG file." << endl;
+        goto rows_free;
+    }
+
+    if (alpha[0] == NULL) {
+        ptr = rgb[0];
+        for (i = 0; i < *height; i++) {
+            memcpy(ptr, row_pointers[i], 3 * (*width));
+            ptr += 3 * (*width);
+        }
+    } else {
+        ptr = rgb[0];
+        for (i = 0; i < *height; i++) {
+            unsigned int ipos = 0;
+            for (int j = 0; j < *width; j++) {
+                *ptr++ = row_pointers[i][ipos++];
+                *ptr++ = row_pointers[i][ipos++];
+                *ptr++ = row_pointers[i][ipos++];
+                alpha[0][i * (*width) + j] = row_pointers[i][ipos++];
+            }
+        }
+    }
+
+    ret = 1; /* data reading is OK */
+
+rows_free:
+    for (i = 0; i < *height; i++) {
+        if (row_pointers[i] != NULL ) {
+            free(row_pointers[i]);
+        }
+    }
+
+    free(row_pointers);
+
+png_destroy:
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+
+file_close:
+    fclose(infile);
+    return(ret);
+}

+ 5 - 1
image.h

@@ -63,13 +63,17 @@ public:
 
     Pixmap createPixmap(Display* dpy, int scr, Window win);
 
-
 private:
     int width, height, area;
     unsigned char *rgb_data;
     unsigned char *png_alpha;
 
     int quality_;
+
+    int readJpeg(const char *filename, int *width, int *height,
+        unsigned char **rgb);
+    int readPng(const char *filename, int *width, int *height,
+        unsigned char **rgb, unsigned char **alpha);
 };
 
 #endif