Esempio n. 1
0
int res_create_surface_png(const char* name, gr_surface* pSurface) {
    GGLSurface* surface = NULL;
    int result = 0;
    unsigned char header[8];
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;

    FILE* fp = fopen(name, "rb");
    if (fp == NULL) {
        char resPath[256];

        snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
        resPath[sizeof(resPath)-1] = '\0';
        fp = fopen(resPath, "rb");
        if (fp == NULL)
        {
            result = -1;
            goto exit;
        }
    }

    size_t bytesRead = fread(header, 1, sizeof(header), fp);
    if (bytesRead != sizeof(header)) {
        result = -2;
        goto exit;
    }

    if (png_sig_cmp(header, 0, sizeof(header))) {
        result = -3;
        goto exit;
    }

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        result = -4;
        goto exit;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        result = -5;
        goto exit;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        result = -6;
        goto exit;
    }

    png_set_packing(png_ptr);

    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, sizeof(header));
    png_read_info(png_ptr, info_ptr);

    size_t width = info_ptr->width;
    size_t height = info_ptr->height;
    size_t stride = 4 * width;
    size_t pixelSize = stride * height;

    int color_type = info_ptr->color_type;
    int bit_depth = info_ptr->bit_depth;
    int channels = info_ptr->channels;
    if (!(bit_depth == 8 &&
          ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
           (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
           (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
        return -7;
        goto exit;
    }

    surface = malloc(sizeof(GGLSurface) + pixelSize);
    if (surface == NULL) {
        result = -8;
        goto exit;
    }
    unsigned char* pData = (unsigned char*) (surface + 1);
    surface->version = sizeof(GGLSurface);
    surface->width = width;
    surface->height = height;
    surface->stride = width; /* Yes, pixels, not bytes */
    surface->data = pData;
    surface->format = (channels == 3) ?
            GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
    }

    int y;
    if (channels < 4) {
        for (y = 0; y < (int) height; ++y) {
            unsigned char* pRow = pData + y * stride;
            png_read_row(png_ptr, pRow, NULL);

            int x;
            for(x = width - 1; x >= 0; x--) {
                int sx = x * 3;
                int dx = x * 4;
                unsigned char r = pRow[sx];
                unsigned char g = pRow[sx + 1];
                unsigned char b = pRow[sx + 2];
                unsigned char a = 0xff;
                pRow[dx    ] = r; // r
                pRow[dx + 1] = g; // g
                pRow[dx + 2] = b; // b
                pRow[dx + 3] = a;
            }
        }
    } else {
        for (y = 0; y < (int) height; ++y) {
            unsigned char* pRow = pData + y * stride;
            png_read_row(png_ptr, pRow, NULL);
        }
    }

    *pSurface = (gr_surface) surface;

exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    if (fp != NULL) {
        fclose(fp);
    }
    if (result < 0) {
        if (surface) {
            free(surface);
        }
    }
    return result;
}
Esempio n. 2
0
    //-------------------------------------------------------------------------------
    Status Image::loadAsPNG(BYTE* data) {
        png_byte header[8];
        png_structp pngPtr = NULL;
        png_infop infoPtr = NULL;
        png_bytep* rowPtrs = NULL;
        png_int_32 rowSize;
        bool transparency;

        ///////////////////////////////////////////////:
        // Check the header signature
        memcpy(header, data, sizeof(header));
        if (png_sig_cmp(header, 0, 8) != 0) goto ERROR;

        pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                        NULL,
                                        png_error_fn,           // error callback
                                        png_warning_fn);        // warning callback
        if (!pngPtr) goto ERROR;

        infoPtr = png_create_info_struct(pngPtr);
        if (!infoPtr) goto ERROR;

        if (setjmp(png_jmpbuf(pngPtr))) goto ERROR;

        ////////////////////////////////////////////////////////////////////////
        // Create the read structure and set the read function from a memory pointer
        ByteBuffer bb;
        bb.offset = 8; //sig
        bb.data = data;
        png_set_read_fn(pngPtr, &bb, memoryReadCallback);

        //tell libpng we already read the signature
        png_set_sig_bytes(pngPtr, 8);

        png_read_info(pngPtr, infoPtr);

        png_int_32 depth, colorType;
        png_uint_32 width, height;
        png_get_IHDR(pngPtr, infoPtr, &width, &height,
                     &depth, &colorType, NULL, NULL, NULL);
        mWidth = width;
        mHeight = height;

        // Creates a full alpha channel if transparency is encoded as
        // an array of palette entries or a single transparent color.
        transparency = false;
        if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) {
            png_set_tRNS_to_alpha(pngPtr);
            transparency = true;
        }
        // Expands PNG with less than 8bits per channel to 8bits.
        if (depth < 8) {
            png_set_packing(pngPtr);
        }
            // Shrinks PNG with 16bits per color channel down to 8bits.
        else if (depth == 16){
            png_set_strip_16(pngPtr);
        }
        // Indicates that image needs conversion to RGBA if needed.
        switch (colorType){
            case PNG_COLOR_TYPE_PALETTE:
                png_set_palette_to_rgb(pngPtr);
                if (transparency) {
                    mFormat = GL_RGBA;
                    mBytesPerPixel = 4;
                } else {
                    mFormat = GL_RGB;
                    mBytesPerPixel = 3;
                }
                break;
            case PNG_COLOR_TYPE_RGB:
                if (transparency) {
                    mFormat = GL_RGBA;
                    mBytesPerPixel = 4;
                } else {
                    mFormat = GL_RGB;
                    mBytesPerPixel = 3;
                }
                break;
            case PNG_COLOR_TYPE_RGBA:
                if (transparency) {
                    mFormat = GL_RGBA;
                    mBytesPerPixel = 4;
                } else {
                    mFormat = GL_RGB;
                    mBytesPerPixel = 3;
                }
                break;
            case PNG_COLOR_TYPE_GRAY:
                png_set_expand_gray_1_2_4_to_8(pngPtr);
                mFormat = transparency  ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
                if (transparency) {
                    mFormat = GL_LUMINANCE_ALPHA;
                    mBytesPerPixel = 2;
                } else {
                    mFormat = GL_LUMINANCE;
                    mBytesPerPixel = 1;
                }
                break;
            case PNG_COLOR_TYPE_GA:
                png_set_expand_gray_1_2_4_to_8(pngPtr);
                if (transparency) {
                    mFormat = GL_LUMINANCE_ALPHA;
                    mBytesPerPixel = 2;
                } else {
                    mFormat = GL_LUMINANCE;
                    mBytesPerPixel = 1;
                }
                break;
            default:
                assert(false);
                break;
        }
        png_read_update_info(pngPtr, infoPtr);

        rowSize = png_get_rowbytes(pngPtr, infoPtr);
        if(rowSize <= 0) goto ERROR;
        mPixels = new BYTE[rowSize * height];
        if(!mPixels) goto ERROR;
        rowPtrs = new png_bytep[height];
        if(!rowPtrs) goto ERROR;

        for(U32 i = 0; i < height; ++i){
            rowPtrs[height - (i + 1)] = mPixels + i * rowSize;
        }
        png_read_image(pngPtr, rowPtrs);

        png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
        delete[] rowPtrs;
        return STATUS_OK;

        ERROR:
        Log::error(TAG, "Error while reading PNG data");
        delete[] rowPtrs; delete[] mPixels;
        if(pngPtr != NULL){
            png_infop* infoPtrP = infoPtr != NULL ? &infoPtr : NULL;
            png_destroy_read_struct(&pngPtr, infoPtrP, NULL);
        }
        return throwException(TAG, ExceptionType::INVALID_FILE, "unknown error while reading PNG data");
    }
Esempio n. 3
0
/* This routine is based in part on the Chapter 13 demo code in "PNG: The
 *  Definitive Guide" (http://www.cdrom.com/pub/png/pngbook.html).
 */
BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile)
{
  png_byte sig[8];
  png_structp png_ptr;
  png_infop info_ptr;
	png_uint_32 width, height, rowbytes, w, h;
  int bit_depth, color_type, interlace_type;
  int num_palette, num_trans;
  png_colorp palette;
  png_color_16p trans_gray_rgb;
  png_color_16p trans_color_rgb;
  png_bytep trans;
  png_bytep image_data = NULL;
  png_bytepp row_pointers = NULL;
  gdImagePtr im = NULL;
  int i, j, *open = NULL;
  volatile int transparent = -1;
  volatile int palette_allocated = FALSE;

  /* Make sure the signature can't match by dumb luck -- TBB */
  /* GRR: isn't sizeof(infile) equal to the size of the pointer? */
	memset (sig, 0, sizeof (sig));

  /* first do a quick check that the file really is a PNG image; could
   * have used slightly more general png_sig_cmp() function instead */
  if (gdGetBuf (sig, 8, infile) < 8) {
	return NULL;
  }

	if (!png_check_sig (sig, 8)) { /* bad signature */
    	return NULL;		/* bad signature */
	}

#ifndef PNG_SETJMP_NOT_SUPPORTED
  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct, gdPngErrorHandler, NULL);
#else
  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
  if (png_ptr == NULL) {
      fprintf (stderr, "gd-png error: cannot allocate libpng main struct\n");
      return NULL;
    }

  info_ptr = png_create_info_struct (png_ptr);
  if (info_ptr == NULL) {
      fprintf (stderr, "gd-png error: cannot allocate libpng info struct\n");
      png_destroy_read_struct (&png_ptr, NULL, NULL);

      return NULL;
    }

  /* we could create a second info struct here (end_info), but it's only
   * useful if we want to keep pre- and post-IDAT chunk info separated
   * (mainly for PNG-aware image editors and converters) 
	*/

  /* setjmp() must be called in every non-callback function that calls a
   * PNG-reading libpng function */
#ifndef PNG_SETJMP_NOT_SUPPORTED
  if (setjmp (gdPngJmpbufStruct.jmpbuf)) {
      fprintf (stderr, "gd-png error: setjmp returns error condition 1\n");
      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

      return NULL;
    }
#endif

  png_set_sig_bytes (png_ptr, 8);	/* we already read the 8 signature bytes */

  png_set_read_fn (png_ptr, (void *) infile, gdPngReadData);
  png_read_info (png_ptr, info_ptr);	/* read all PNG info up to image data */

  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
  if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
      im = gdImageCreateTrueColor ((int) width, (int) height);
    } else {
      im = gdImageCreate ((int) width, (int) height);
    }
  if (im == NULL) {
      fprintf (stderr, "gd-png error: cannot allocate gdImage struct\n");
      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
      gdFree (image_data);
      gdFree (row_pointers);

      return NULL;
    }

  if (bit_depth == 16) {
    png_set_strip_16 (png_ptr);
  } else if (bit_depth < 8) {
    png_set_packing (png_ptr);	/* expand to 1 byte per pixel */
	}

	/* setjmp() must be called in every non-callback function that calls a
	 * PNG-reading libpng function
	 */
#ifndef PNG_SETJMP_NOT_SUPPORTED
	if (setjmp(gdPngJmpbufStruct.jmpbuf)) {
		fprintf(stderr, "gd-png error: setjmp returns error condition 2");
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		gdFree(image_data);
		gdFree(row_pointers);
		if (im) {
			gdImageDestroy(im);
		}
		return NULL;
	}
#endif

  switch (color_type) {
    case PNG_COLOR_TYPE_PALETTE:
      png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette);
#ifdef DEBUG
      fprintf (stderr, "gd-png color_type is palette, colors: %d\n", num_palette);
#endif /* DEBUG */
      if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
				/* gd 2.0: we support this rather thoroughly now. Grab the
				 * first fully transparent entry, if any, as the value of
				 * the simple-transparency index, mostly for backwards
				 * binary compatibility. The alpha channel is where it's
				 * really at these days.
				 */
	  int firstZero = 1;
	  png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL);
	  for (i = 0; i < num_trans; ++i) {
	      im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
	      if ((trans[i] == 0) && (firstZero)) {
		  /* 2.0.5: long-forgotten patch from Wez Furlong */
		  transparent = i;
		  firstZero = 0;
		}
	    }
	}
      break;

    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_GRAY_ALPHA:
      /* create a fake palette and check for single-shade transparency */
      if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) {
	  fprintf (stderr, "gd-png error: cannot allocate gray palette\n");
	  png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
	  return NULL;
	}
      palette_allocated = TRUE;
      if (bit_depth < 8) {
	  num_palette = 1 << bit_depth;
	  for (i = 0; i < 256; ++i) {
	      j = (255 * i) / (num_palette - 1);
	      palette[i].red = palette[i].green = palette[i].blue = j;
	    }
	} else {
	  num_palette = 256;
	  for (i = 0; i < 256; ++i) {
	      palette[i].red = palette[i].green = palette[i].blue = i;
	    }
	}
      if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
	  png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
	  if (bit_depth == 16) {	/* png_set_strip_16() not yet in effect */
	    transparent = trans_gray_rgb->gray >> 8;
	 } else {
	    transparent = trans_gray_rgb->gray;
	}
	  /* Note slight error in 16-bit case:  up to 256 16-bit shades
	   * may get mapped to a single 8-bit shade, and only one of them
	   * is supposed to be transparent.  IOW, both opaque pixels and
	   * transparent pixels will be mapped into the transparent entry.
	   * There is no particularly good way around this in the case
	   * that all 256 8-bit shades are used, but one could write some
	   * custom 16-bit code to handle the case where there are gdFree
	   * palette entries.  This error will be extremely rare in
	   * general, though.  (Quite possibly there is only one such
	   * image in existence.) */
	}
Esempio n. 4
0
Py::Object
_png_module::read_png(const Py::Tuple& args) {

  args.verify_length(1);
  std::string fname = Py::String(args[0]);

  png_byte header[8];	// 8 is the maximum size that can be checked

  FILE *fp = fopen(fname.c_str(), "rb");
  if (!fp)
    throw Py::RuntimeError(Printf("_image_module::readpng could not open PNG file %s for reading", fname.c_str()).str());

  if (fread(header, 1, 8, fp) != 8)
    throw Py::RuntimeError("_image_module::readpng: error reading PNG header");
  if (png_sig_cmp(header, 0, 8))
    throw Py::RuntimeError("_image_module::readpng: file not recognized as a PNG file");


  /* initialize stuff */
  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    throw Py::RuntimeError("_image_module::readpng:  png_create_read_struct failed");

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    throw Py::RuntimeError("_image_module::readpng:  png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    throw Py::RuntimeError("_image_module::readpng:  error during init_io");

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);
  png_read_info(png_ptr, info_ptr);

  png_uint_32 width = info_ptr->width;
  png_uint_32 height = info_ptr->height;

  int bit_depth = info_ptr->bit_depth;

  // Unpack 1, 2, and 4-bit images
  if (bit_depth < 8)
    png_set_packing(png_ptr);

  // If sig bits are set, shift data
  png_color_8p sig_bit;
  if ((info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) && png_get_sBIT(png_ptr, info_ptr, &sig_bit))
    png_set_shift(png_ptr, sig_bit);

  // Convert big endian to little
  if (bit_depth == 16)
    png_set_swap(png_ptr);

  // Convert palletes to full RGB
  if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png_ptr);

  // If there's an alpha channel convert gray to RGB
  if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png_ptr);

  png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  /* read file */
  if (setjmp(png_jmpbuf(png_ptr)))
    throw Py::RuntimeError("_image_module::readpng: error during read_image");

  png_bytep *row_pointers = new png_bytep[height];
  png_uint_32 row;

  for (row = 0; row < height; row++)
    row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)];

  png_read_image(png_ptr, row_pointers);

  npy_intp dimensions[3];
  dimensions[0] = height;  //numrows
  dimensions[1] = width;   //numcols
  if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
    dimensions[2] = 4;     //RGBA images
  else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
    dimensions[2] = 3;     //RGB images
  else
    dimensions[2] = 1;     //Greyscale images
  //For gray, return an x by y array, not an x by y by 1
  int num_dims  = (info_ptr->color_type & PNG_COLOR_MASK_COLOR) ? 3 : 2;

  double max_value = (1 << ((bit_depth < 8) ? 8 : bit_depth)) - 1;
  PyArrayObject *A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, PyArray_FLOAT);

  if (A == NULL) {
    throw Py::MemoryError("Could not allocate image array");
  }

  for (png_uint_32 y = 0; y < height; y++) {
    png_byte* row = row_pointers[y];
	for (png_uint_32 x = 0; x < width; x++) {
	  size_t offset = y*A->strides[0] + x*A->strides[1];
	  if (bit_depth == 16) {
	    png_uint_16* ptr = &reinterpret_cast<png_uint_16*> (row)[x * dimensions[2]];
		for (png_uint_32 p = 0; p < dimensions[2]; p++)
	      *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
	  } else {
	    png_byte* ptr = &(row[x * dimensions[2]]);
	    for (png_uint_32 p = 0; p < dimensions[2]; p++)
		{
	      *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
	    }
	  }
    }
  }

  //free the png memory
  png_read_end(png_ptr, info_ptr);
  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
  fclose(fp);
  for (row = 0; row < height; row++)
    delete [] row_pointers[row];
  delete [] row_pointers;
  return Py::asObject((PyObject*)A);
}
Esempio n. 5
0
static PyObject *_read_png(PyObject *filein, bool float_result)
{
    png_byte header[8]; // 8 is the maximum size that can be checked
    FILE *fp = NULL;
    mpl_off_t offset = 0;
    bool close_file = false;
    bool close_dup_file = false;
    PyObject *py_file = NULL;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    int num_dims;
    std::vector<png_bytep> row_pointers;
    png_uint_32 width = 0;
    png_uint_32 height = 0;
    int bit_depth;
    PyObject *result = NULL;

    // TODO: Remove direct calls to Numpy API here

    if (PyBytes_Check(filein) || PyUnicode_Check(filein)) {
        if ((py_file = mpl_PyFile_OpenFile(filein, (char *)"rb")) == NULL) {
            goto exit;
        }
        close_file = true;
    } else {
        py_file = filein;
    }

    if ((fp = mpl_PyFile_Dup(py_file, (char *)"rb", &offset))) {
        close_dup_file = true;
    } else {
        PyErr_Clear();
        PyObject *read_method = PyObject_GetAttrString(py_file, "read");
        if (!(read_method && PyCallable_Check(read_method))) {
            Py_XDECREF(read_method);
            PyErr_SetString(PyExc_TypeError,
                            "Object does not appear to be a 8-bit string path or "
                            "a Python file-like object");
            goto exit;
        }
        Py_XDECREF(read_method);
    }

    if (fp) {
        if (fread(header, 1, 8, fp) != 8) {
            PyErr_SetString(PyExc_IOError, "error reading PNG header");
            goto exit;
        }
    } else {
        _read_png_data(py_file, header, 8);
    }

    if (png_sig_cmp(header, 0, 8)) {
        PyErr_SetString(PyExc_ValueError, "invalid PNG header");
        goto exit;
    }

    /* initialize stuff */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (!png_ptr) {
        PyErr_SetString(PyExc_RuntimeError, "png_create_read_struct failed");
        goto exit;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        PyErr_SetString(PyExc_RuntimeError, "png_create_info_struct failed");
        goto exit;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        PyErr_SetString(PyExc_RuntimeError, "Error setting jump");
        goto exit;
    }

    if (fp) {
        png_init_io(png_ptr, fp);
    } else {
        png_set_read_fn(png_ptr, (void *)py_file, &read_png_data);
    }
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);

    bit_depth = png_get_bit_depth(png_ptr, info_ptr);

    // Unpack 1, 2, and 4-bit images
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }

    // If sig bits are set, shift data
    png_color_8p sig_bit;
    if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) &&
        png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
        png_set_shift(png_ptr, sig_bit);
    }

    // Convert big endian to little
    if (bit_depth == 16) {
        png_set_swap(png_ptr);
    }

    // Convert palletes to full RGB
    if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
        bit_depth = 8;
    }

    // If there's an alpha channel convert gray to RGB
    if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }

    png_set_interlace_handling(png_ptr);
    png_read_update_info(png_ptr, info_ptr);

    row_pointers.resize(height);
    for (png_uint_32 row = 0; row < height; row++) {
        row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
    }

    png_read_image(png_ptr, &row_pointers[0]);

    npy_intp dimensions[3];
    dimensions[0] = height; // numrows
    dimensions[1] = width; // numcols
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) {
        dimensions[2] = 4; // RGBA images
    } else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) {
        dimensions[2] = 3; // RGB images
    } else {
        dimensions[2] = 1; // Greyscale images
    }

    if (float_result) {
        double max_value = (1 << bit_depth) - 1;

        numpy::array_view<float, 3> A(dimensions);

        for (png_uint_32 y = 0; y < height; y++) {
            png_byte *row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++) {
                if (bit_depth == 16) {
                    png_uint_16 *ptr = &reinterpret_cast<png_uint_16 *>(row)[x * dimensions[2]];
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) {
                        A(y, x, p) = (float)(ptr[p]) / max_value;
                    }
                } else {
                    png_byte *ptr = &(row[x * dimensions[2]]);
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) {
                        A(y, x, p) = (float)(ptr[p]) / max_value;
                    }
                }
            }
        }

        result = A.pyobj();
    } else if (bit_depth == 16) {
        numpy::array_view<png_uint_16, 3> A(dimensions);

        for (png_uint_32 y = 0; y < height; y++) {
            png_byte *row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++) {
                png_uint_16 *ptr = &reinterpret_cast<png_uint_16 *>(row)[x * dimensions[2]];
                for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) {
                    A(y, x, p) = ptr[p];
                }
            }
        }

        result = A.pyobj();
    } else if (bit_depth == 8) {
        numpy::array_view<png_byte, 3> A(dimensions);

        for (png_uint_32 y = 0; y < height; y++) {
            png_byte *row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++) {
                png_byte *ptr = &(row[x * dimensions[2]]);
                for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) {
                    A(y, x, p) = ptr[p];
                }
            }
        }

        result = A.pyobj();
    } else {
        PyErr_SetString(PyExc_RuntimeError, "image has unknown bit depth");
        goto exit;
    }

    // free the png memory
    png_read_end(png_ptr, info_ptr);

    // For gray, return an x by y array, not an x by y by 1
    num_dims = (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) ? 3 : 2;

    if (num_dims == 2) {
        PyArray_Dims dims = {dimensions, 2};
        PyObject *reshaped = PyArray_Newshape((PyArrayObject *)result, &dims, NPY_CORDER);
        Py_DECREF(result);
        result = reshaped;
    }

exit:
    if (png_ptr && info_ptr) {
#ifndef png_infopp_NULL
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
#else
        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
#endif
    }

    if (close_dup_file) {
        mpl_PyFile_DupClose(py_file, fp, offset);
    }

    if (close_file) {
        mpl_PyFile_CloseFile(py_file);
        Py_DECREF(py_file);
    }

    for (png_uint_32 row = 0; row < height; row++) {
        delete[] row_pointers[row];
    }

    if (PyErr_Occurred()) {
        Py_XDECREF(result);
        return NULL;
    } else {
        return result;
    }
}
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const {
	struct s_my_png my_png;
	my_png.p = (char*)stringData.data();
	my_png.size = stringData.length();

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	unsigned int *row = NULL;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			(png_voidp)&my_png, mypng_error_func, mypng_warning_func);
	if ( !png_ptr )
		return;

	if (setjmp( png_ptr->jmpbuf )) {
		data.init(0, 0);
		if (png_ptr)
		{
			png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
		}
		if ( row )
			delete row;
		return;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		mypng_error_func(png_ptr, "cannot create png info struct");
	png_set_read_fn(png_ptr,
			(voidp)&my_png, mypng_read_func);
	png_read_info( png_ptr, info_ptr );


	png_uint_32 width, height;
	int bit_depth, color_type, interlace_type;
	png_get_IHDR(png_ptr, info_ptr, &width, &height,
			&bit_depth, &color_type, &interlace_type,
			NULL, NULL);

	data.init(width, height);

	row = new unsigned int[ width ];

	// SET TRANSFORMS
	if (color_type & PNG_COLOR_MASK_PALETTE)
		png_set_palette_to_rgb(png_ptr);

	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_gray_1_2_4_to_8(png_ptr);

	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png_ptr);

	if (bit_depth == 16) png_set_strip_16(png_ptr);


	if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_invert_alpha(png_ptr);
	} else {
		png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff};
		png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0);

		png_set_strip_alpha(png_ptr);
	}

	if (bit_depth < 8)
		png_set_packing(png_ptr);

	//if (color_type == PNG_COLOR_TYPE_RGB)
	//png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);

	//if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	//    png_set_swap_alpha(png_ptr);

	if (! (color_type == PNG_COLOR_TYPE_GRAY ||
			color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
		png_set_rgb_to_gray(png_ptr, 1, -1, -1);

	int number_passes = png_set_interlace_handling(png_ptr);
	//if (color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
	//    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

	//if (color_type == PNG_COLOR_TYPE_RGB ||
	//    color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	png_set_bgr(png_ptr);


	ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0);
	register int dalgo = myDitherAlgo.value();
	char *c;	
	for(int pass = 0; pass < number_passes; pass++) {
		for(unsigned int y = 0; y < height; y++) {

			png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1);

			c = ((ZLEwlImageData&)data).getImageData() + width * y;


			if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
				unsigned char *s = (unsigned char*)row;
				if(dalgo == 1)
					for(unsigned int i = 0; i < width; i++)
						*c++ = Dither2BitColor(*(++s)++, i, y);
				else
					for(unsigned int i = 0; i < width; i++)
						*c++ = *(++s)++;
			} else if(dalgo == 1) {
				unsigned char *s = (unsigned char*)row;
				for(unsigned int i = 0; i < width; i++)
					*c++ = Dither2BitColor(*s++, i, y);
			} else 
				memcpy(c, (char*)row, width);
		}
	}

	png_read_end(png_ptr, info_ptr);

	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
}
Esempio n. 7
0
BOOL CImage::LoadBitmapFromPNGFile(LPTSTR szFileName)
{
    BOOL bStatus = FALSE;

    FILE *fp = NULL;
    const int number = 8;
    png_byte header[number];
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_infop end_info = NULL;
    png_uint_32 rowbytes = 0;
    png_uint_32 width = 0;
    png_uint_32 height = 0;
    png_bytep row = NULL;
    int y = 0;
    BITMAPINFO* pBMI = NULL;
    HDC hDC = NULL;

    _TFOPEN_S(fp, szFileName, _T("rb"));
    if (!fp)
    {
        return FALSE;
    }

    fread(header, 1, number, fp);
    if(png_sig_cmp(header, 0, number))
    {
        goto cleanup;
    }

    png_ptr = png_create_read_struct
              (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        goto cleanup;

    if (setjmp(png_ptr->jmpbuf))
        goto cleanup;

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
        goto cleanup;

    end_info = png_create_info_struct(png_ptr);
    if (!end_info)
        goto cleanup;

    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, number);

    // Read PNG information
    png_read_info(png_ptr, info_ptr);

    // Get count of bytes per row
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    row = new png_byte[rowbytes];

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);

    if(info_ptr->channels==3)
    {
        png_set_strip_16(png_ptr);
        png_set_packing(png_ptr);
        png_set_bgr(png_ptr);
    }

    hDC = GetDC(NULL);

    {
        CAutoLock lock(&m_csLock);
        if(m_bLoadCancelled)
            goto cleanup;
        m_hBitmap = CreateCompatibleBitmap(hDC, width, height);
    }

    pBMI = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFO)+256*4];
    memset(pBMI, 0, sizeof(BITMAPINFO)+256*4);
    pBMI->bmiHeader.biSize = sizeof(BITMAPINFO);
    pBMI->bmiHeader.biBitCount = 8*info_ptr->channels;
    pBMI->bmiHeader.biWidth = width;
    pBMI->bmiHeader.biHeight = height;
    pBMI->bmiHeader.biPlanes = 1;
    pBMI->bmiHeader.biCompression = BI_RGB;
    pBMI->bmiHeader.biSizeImage = rowbytes*height;

    if( info_ptr->channels == 1 )
    {
        RGBQUAD* palette = pBMI->bmiColors;

        int i;
        for( i = 0; i < 256; i++ )
        {
            palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
            palette[i].rgbReserved = 0;
        }

        palette[256].rgbBlue = palette[256].rgbGreen = palette[256].rgbRed = 255;
    }

    for(y=height-1; y>=0; y--)
    {
        png_read_rows(png_ptr, &row, png_bytepp_NULL, 1);

        {
            CAutoLock lock(&m_csLock);
            int n = SetDIBits(hDC, m_hBitmap, y, 1, row, pBMI, DIB_RGB_COLORS);
            if(n==0)
                goto cleanup;
        }
    }

    /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
    png_read_end(png_ptr, info_ptr);

    bStatus = TRUE;

cleanup:

    if(fp!=NULL)
    {
        fclose(fp);
    }

    if(png_ptr)
    {
        png_destroy_read_struct(&png_ptr,
                                (png_infopp)&info_ptr, (png_infopp)&end_info);
    }

    if(row)
    {
        delete [] row;
    }

    if(pBMI)
    {
        delete [] pBMI;
    }

    if(!bStatus)
    {
        Destroy();
    }

    return bStatus;
}
Esempio n. 8
0
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
                           int transforms,
                           voidp params)
{
   int row;

#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
   /* invert the alpha channel from opacity to transparency */
   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
       png_set_invert_alpha(png_ptr);
#endif

   /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk).
    */
   png_read_info(png_ptr, info_ptr);

   /* -------------- image transformations start here ------------------- */

#if defined(PNG_READ_16_TO_8_SUPPORTED)
   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   if (transforms & PNG_TRANSFORM_STRIP_16)
       png_set_strip_16(png_ptr);
#endif

#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
   /* Strip alpha bytes from the input data without combining with the
    * background (not recommended).
    */
   if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
       png_set_strip_alpha(png_ptr);
#endif

#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   if (transforms & PNG_TRANSFORM_PACKING)
       png_set_packing(png_ptr);
#endif

#if defined(PNG_READ_PACKSWAP_SUPPORTED)
   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing). */
   if (transforms & PNG_TRANSFORM_PACKSWAP)
       png_set_packswap(png_ptr);
#endif

#if defined(PNG_READ_EXPAND_SUPPORTED)
   /* Expand paletted colors into true RGB triplets
    * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
    * Expand paletted or RGB images with transparency to full alpha
    * channels so the data will be available as RGBA quartets.
    */
   if (transforms & PNG_TRANSFORM_EXPAND)
       if ((png_ptr->bit_depth < 8) ||
           (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
           (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
         png_set_expand(png_ptr);
#endif

   /* We don't handle background color or gamma transformation or dithering. */

#if defined(PNG_READ_INVERT_SUPPORTED)
   /* invert monochrome files to have 0 as white and 1 as black */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
       png_set_invert_mono(png_ptr);
#endif

#if defined(PNG_READ_SHIFT_SUPPORTED)
   /* If you want to shift the pixel values from the range [0,255] or
    * [0,65535] to the original [0,7] or [0,31], or whatever range the
    * colors were originally in:
    */
   if ((transforms & PNG_TRANSFORM_SHIFT)
       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit;

      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
      png_set_shift(png_ptr, sig_bit);
   }
#endif

#if defined(PNG_READ_BGR_SUPPORTED)
   /* flip the RGB pixels to BGR (or RGBA to BGRA) */
   if (transforms & PNG_TRANSFORM_BGR)
       png_set_bgr(png_ptr);
#endif

#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#if defined(PNG_READ_SWAP_SUPPORTED)
   /* swap bytes of 16 bit files to least significant byte first */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
       png_set_swap(png_ptr);
#endif

   /* We don't handle adding filler bytes */

   /* Optional call to gamma correct and add the background to the palette
    * and update info structure.  REQUIRED if you are expecting libpng to
    * update the palette for you (i.e., you selected such a transform above).
    */
   png_read_update_info(png_ptr, info_ptr);

   /* -------------- image transformations end here ------------------- */

#ifdef PNG_FREE_ME_SUPPORTED
   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
#endif
   if(info_ptr->row_pointers == NULL)
   {
      info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
         info_ptr->height * sizeof(png_bytep));
#ifdef PNG_FREE_ME_SUPPORTED
      info_ptr->free_me |= PNG_FREE_ROWS;
#endif
      for (row = 0; row < (int)info_ptr->height; row++)
      {
         info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
            png_get_rowbytes(png_ptr, info_ptr));
      }
   }

   png_read_image(png_ptr, info_ptr->row_pointers);
   info_ptr->valid |= PNG_INFO_IDAT;

   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
   png_read_end(png_ptr, info_ptr);

   if(transforms == 0 || params == NULL)
      /* quiet compiler warnings */ return;

}
Esempio n. 9
0
/*---------------------------------------------------------------------------
   Loads a PNG file.

   Image  : Image will be returned there.
   Path   : Path to image file, relative to the current working directory.
   Gamma  : Display gamma to apply on textures, 2.2 is typical.
  ---------------------------------------------------------------------------*/
void PNG::Load(Texture &Image, const std::string &Path, float Gamma)
   {
   Destroy();

   //Important - set class to reading mode
   Mode = PNG::ModeRead;

   #if defined (WINDOWS)
      if (fopen_s(&File, Path.c_str(), "rb") != 0)
         {throw dexception("Failed to open file: %s.", Path.c_str());}
   #else
      File = fopen(Path.c_str(), "rb");
      if (File == nullptr) {throw dexception("Failed to open file: %s.", Path.c_str());}
   #endif

   uint8 Header[PNG::HeaderSize];
   if (fread((png_bytep)Header, 1, PNG::HeaderSize, File) == 0)
      {throw dexception("fread( ) failed.");}

   if (!png_check_sig(Header, PNG::HeaderSize))
      {throw dexception("Not a valid PNG file.");}

   PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
   if (PngPtr == nullptr) {throw dexception("png_create_read_struct( ) failed.");}

   InfoPtr = png_create_info_struct(PngPtr);
   if (InfoPtr == nullptr) {throw dexception("png_create_info_struct( ) failed.");}

   if (setjmp(png_jmpbuf(PngPtr)))
      {throw dexception("setjmp( ) failed.");}

   //Read into structures
   png_init_io(PngPtr, File);
   png_set_sig_bytes(PngPtr, PNG::HeaderSize);
   png_read_info(PngPtr, InfoPtr);

   //Determine image attributes
   vector2<png_uint_32> Res;
   int BitDepth, ColourType;
   png_get_IHDR(PngPtr, InfoPtr, &Res.U, &Res.V, &BitDepth, &ColourType, nullptr, nullptr, nullptr);

   Texture::TexType Type = Texture::TypeRGB;
   switch (ColourType)
      {
      case PNG_COLOR_TYPE_GRAY :
         if (BitDepth < 8)
            {
            Type = Texture::TypeLum;
            png_set_expand_gray_1_2_4_to_8(PngPtr);
            }
         else if (BitDepth == 16)
            {
            Type = Texture::TypeDepth;
            }
         break;

      case PNG_COLOR_TYPE_GRAY_ALPHA :
         Type = Texture::TypeRGBA;
         png_set_gray_to_rgb(PngPtr);
         break;

      case PNG_COLOR_TYPE_PALETTE :
         Type = Texture::TypeRGB;
         png_set_palette_to_rgb(PngPtr);
         break;

      case PNG_COLOR_TYPE_RGB :
         Type = Texture::TypeRGB;
         png_set_strip_alpha(PngPtr); //If libpng reports RGB, make sure we completely strip alpha
         break;

      case PNG_COLOR_TYPE_RGB_ALPHA :
         Type = Texture::TypeRGBA;
         break;

      default : throw dexception("Unknown colour type.");
      }

   //Convert palette alpha into a separate alpha channel
   if (png_get_valid(PngPtr, InfoPtr, PNG_INFO_tRNS))
      {
      png_set_tRNS_to_alpha(PngPtr);
      if (ColourType == PNG_COLOR_TYPE_PALETTE) {Type = Texture::TypeRGBA;}
      }

   //Force 8 bit per channel
   if (BitDepth >= 16)
      {
      if (Type != Texture::TypeDepth) {png_set_strip_16(PngPtr);}
      }
   else if (BitDepth < 8)
      {
      png_set_packing(PngPtr);
      }

   //Specify display and file gamma (assume 0.45455 for missing file gamma)
   double FileGamma;
   if (!png_get_gAMA(PngPtr, InfoPtr, &FileGamma)) {FileGamma = 0.45455;}
   png_set_gamma(PngPtr, Gamma, FileGamma);

   //Swap byte order for int16 values on big endian machines
   if ((BitDepth >= 16) && !Math::MachineLittleEndian())
      {png_set_swap(PngPtr);}

   //Apply the above transformation settings
   png_read_update_info(PngPtr, InfoPtr);

   //Allocate image
   Image.Create(cast_vector2(uint, Res), Type);

   if (Image.GetBytesPerLine() < (usize)png_get_rowbytes(PngPtr, InfoPtr))
      {throw dexception("Incorrect scan line size for allocated image.");}

   //Populate row pointer array
   Rows.Create((usize)Res.V);
   for (uiter I = 0; I < (usize)Res.V; I++)
      {
      Rows[I] = Image.Address(0, I);
      }

   //Decode
   png_read_image(PngPtr, Rows.Pointer());
   png_read_end(PngPtr, InfoPtr);

   //Clean up
   Destroy();
   }
Esempio n. 10
0
bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream,
        png_structp *png_ptrp, png_infop *info_ptrp)
{
    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, sk_error_fn, NULL);
    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    if (png_ptr == NULL) {
        return false;
    }
    *png_ptrp = png_ptr;

    /* Allocate/initialize the memory for image information. */
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return false;
    }
    *info_ptrp = info_ptr;

    /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
    png_set_seek_fn(png_ptr, sk_seek_fn);
    /* where user_io_ptr is a structure you want available to the callbacks */
    /* If we have already read some of the signature */
    // png_set_sig_bytes(png_ptr, 0 /* sig_read */ );

    // hookup our peeker so we can see any user-chunks the caller may be interested in
    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
    if (this->getPeeker()) {
        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
    }

    /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk). */
    png_read_info(png_ptr, info_ptr);
    png_uint_32 origWidth, origHeight;
    int bit_depth, color_type, interlace_type;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
            &color_type, &interlace_type, int_p_NULL, int_p_NULL);

    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
    if (bit_depth == 16) {
        png_set_strip_16(png_ptr);
    }
    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
     * byte into separate bytes (useful for paletted and grayscale images). */
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }
    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_gray_1_2_4_to_8(png_ptr);
    }

    /* Make a grayscale image into RGB. */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }
    return true;
}
Esempio n. 11
0
bool  PngEncoder::write(const Mat& img)
{
	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	png_infop info_ptr = 0;
	FILE* f = 0;
	int y, width = img.cols_, height = img.rows_;
	int depth = img.depth(), channels = img.channels();
	bool result = false;

	uchar** buffer = NULL;
	if (depth != MCV_8U && depth != MCV_16U)
		return false;

	if (png_ptr){
		info_ptr = png_create_info_struct(png_ptr);

		if (info_ptr){
			if (setjmp(png_jmpbuf(png_ptr)) == 0){
			
					f = fopen(filename_.c_str(), "wb");
					if (f)
						png_init_io(png_ptr, f);
			
				int compression_level = 5; // Invalid value to allow setting 0-9 as valid
				int compression_strategy = Z_RLE; // Default strategy
				bool isBilevel = false;

				if ( f)	{
					if (compression_level >= 0){
						png_set_compression_level(png_ptr, compression_level);
					}
					else{
						png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
						png_set_compression_level(png_ptr, Z_BEST_SPEED);
					}
					png_set_compression_strategy(png_ptr, compression_strategy);

					png_set_IHDR(png_ptr, info_ptr, width, height, depth == MCV_8U ? isBilevel ? 1 : 8 : 16,
						channels == 1 ? PNG_COLOR_TYPE_GRAY :
						channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
						PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
						PNG_FILTER_TYPE_DEFAULT);

					png_write_info(png_ptr, info_ptr);

					if (isBilevel)
						png_set_packing(png_ptr);

					
					buffer = new uchar*[height];
					
					for (y = 0; y < height; y++)
						buffer[y] = img.data_ + y*img.cols_*img.elemSize();

					png_write_image(png_ptr, buffer);
					png_write_end(png_ptr, info_ptr);

					result = true;
				}
			}
		}
	}

	png_destroy_write_struct(&png_ptr, &info_ptr);
	if (f) fclose(f);

	delete[] buffer;
	return result;
return false;
}
Esempio n. 12
0
bool8 S9xDoScreenshot (int width, int height)
{
	Settings.TakeScreenshot = FALSE;

#ifdef HAVE_LIBPNG
	FILE		*fp;
	png_structp	png_ptr;
	png_infop	info_ptr;
	png_color_8	sig_bit;
	int			imgwidth, imgheight;
	const char	*fname;

	fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR);

	fp = fopen(fname, "wb");
	if (!fp)
	{
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
	{
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fp);
		remove(fname);
		S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
		return (FALSE);
	}

	imgwidth  = width;
	imgheight = height;

	if (Settings.StretchScreenshots == 1)
	{
		if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED)
			imgheight = height << 1;
	}
	else
	if (Settings.StretchScreenshots == 2)
	{
		if (width  <= SNES_WIDTH)
			imgwidth  = width  << 1;
		if (height <= SNES_HEIGHT_EXTENDED)
			imgheight = height << 1;
	}

	png_init_io(png_ptr, fp);

	png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	sig_bit.red   = 5;
	sig_bit.green = 5;
	sig_bit.blue  = 5;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
	png_set_shift(png_ptr, &sig_bit);

	png_write_info(png_ptr, info_ptr);

	png_set_packing(png_ptr);

	png_byte	*row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
	uint16		*screen = GFX.Screen;

	for (int y = 0; y < height; y++, screen += GFX.RealPPL)
	{
		png_byte	*rowpix = row_pointer;

		for (int x = 0; x < width; x++)
		{
			uint32	r, g, b;

			DECOMPOSE_PIXEL(screen[x], r, g, b);

			*(rowpix++) = r;
			*(rowpix++) = g;
			*(rowpix++) = b;

			if (imgwidth != width)
			{
				*(rowpix++) = r;
				*(rowpix++) = g;
				*(rowpix++) = b;
			}
		}

		png_write_row(png_ptr, row_pointer);
		if (imgheight != height)
			png_write_row(png_ptr, row_pointer);
	}

	delete [] row_pointer;

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);

	fclose(fp);

	fprintf(stderr, "%s saved.\n", fname);

	const char	*base = S9xBasename(fname);
	sprintf(String, "Saved screenshot %s", base);
	S9xMessage(S9X_INFO, 0, String);

	return (TRUE);
#else
	fprintf(stderr, "Screenshot support not available (libpng was not found at build time).\n");
	return (FALSE);
#endif
}