Exemple #1
0
    void set_shift(byte gray_bits, byte alpha_bits = 0) const
    {
        TRACE_IO_TRANSFORM("png_set_shift: gray_bits=%d, alpha_bits=%d\n",
                           gray_bits, alpha_bits);

        if (get_color_type() != color_type_gray
                || get_color_type() != color_type_gray_alpha)
        {
            throw error("set_shift: expected Gray or Gray+Alpha"
                        " color type");
        }
        color_info bits;
        bits.gray = gray_bits;
        bits.alpha = alpha_bits;
        png_set_shift(m_png, & bits);
    }
Exemple #2
0
    void set_shift(byte red_bits, byte green_bits, byte blue_bits,
                   byte alpha_bits = 0) const
    {
        TRACE_IO_TRANSFORM("png_set_shift: red_bits=%d, green_bits=%d,"
                           " blue_bits=%d, alpha_bits=%d\n",
                           red_bits, green_bits, blue_bits, alpha_bits);

        if (get_color_type() != color_type_rgb
                || get_color_type() != color_type_rgb_alpha)
        {
            throw error("set_shift: expected RGB or RGBA color type");
        }
        color_info bits;
        bits.red = red_bits;
        bits.green = green_bits;
        bits.blue = blue_bits;
        bits.alpha = alpha_bits;
        png_set_shift(m_png, & bits);
    }
Exemple #3
0
/* Read a PNG file (header) into a VIPS (header).
 */
static int
png2vips( Read *read, int header_only )
{
	int bands, bpp, type;

	if( setjmp( read->pPng->jmpbuf ) ) 
		return( -1 );

	png_init_io( read->pPng, read->fp );
	png_read_info( read->pPng, read->pInfo );

	/* png_get_channels() gives us 1 band for palette images ... so look
	 * at colour_type for output bands.
	 */
	switch( read->pInfo->color_type ) {
	case PNG_COLOR_TYPE_PALETTE: 
		bands = 3; 

		/* Don't know if this is really correct. If there are
		 * transparent pixels, assume we're going to output RGBA.
		 */
		if( read->pInfo->num_trans )
			bands = 4; 

		break;

	case PNG_COLOR_TYPE_GRAY: bands = 1; break;
	case PNG_COLOR_TYPE_GRAY_ALPHA: bands = 2; break;
	case PNG_COLOR_TYPE_RGB: bands = 3; break;
	case PNG_COLOR_TYPE_RGB_ALPHA: bands = 4; break;

	default:
		im_error( "im_png2vips", "%s", _( "unsupported color type" ) );
		return( -1 );
	}

	/* 8 or 16 bit.
	 */
	bpp = read->pInfo->bit_depth > 8 ? 2 : 1;

	if( bpp > 1 ) {
		if( bands < 3 )
			type = IM_TYPE_GREY16;
		else
			type = IM_TYPE_RGB16;
	}
	else {
		if( bands < 3 )
			type = IM_TYPE_B_W;
		else
			type = IM_TYPE_sRGB;
	}

	/* Expand palette images.
	 */
	if( read->pInfo->color_type == PNG_COLOR_TYPE_PALETTE )
	        png_set_expand( read->pPng );

	/* Expand <8 bit images to full bytes.
	 */
	if( read->pInfo->bit_depth < 8 ) {
		png_set_packing( read->pPng );
	        png_set_shift( read->pPng, &(read->pInfo->sig_bit) );
	}

	/* If we're an INTEL byte order machine and this is 16bits, we need
	 * to swap bytes.
	 */
	if( read->pInfo->bit_depth > 8 && !im_amiMSBfirst() )
		png_set_swap( read->pPng );

	/* Set VIPS header.
	 */
	im_initdesc( read->out,
		 read->pInfo->width, read->pInfo->height, bands,
		 bpp == 1 ? IM_BBITS_BYTE : IM_BBITS_SHORT, 
		 bpp == 1 ? IM_BANDFMT_UCHAR : IM_BANDFMT_USHORT,
		 IM_CODING_NONE, type, 1.0, 1.0, 0, 0 );

	if( !header_only ) {
		if( png_set_interlace_handling( read->pPng ) > 1 ) {
			if( png2vips_interlace( read ) )
				return( -1 );
		}
		else {
			if( png2vips_noninterlace( read ) )
				return( -1 );
		}
	}

	return( 0 );
}
Exemple #4
0
/* write a png file */
GF_EXPORT
GF_Err gf_img_png_enc(char *data, u32 width, u32 height, s32 stride, u32 pixel_format, char *dst, u32 *dst_size)
{
	GFpng udta;
	png_color_8 sig_bit;
	png_int_32 k;
	png_bytep *row_pointers;
	png_structp png_ptr;
	png_infop info_ptr;
	u32 type, nb_comp;

	type = 0;
	nb_comp = 0;
	switch (pixel_format) {
	case GF_PIXEL_GREYSCALE:
		nb_comp = 1;
		type = PNG_COLOR_TYPE_GRAY;
		break;
	case GF_PIXEL_ALPHAGREY:
		nb_comp = 1;
		type = PNG_COLOR_TYPE_GRAY_ALPHA;
		break;
	case GF_PIXEL_RGB_24:
	case GF_PIXEL_BGR_24:
	case GF_PIXEL_RGB_32:
	case GF_PIXEL_BGR_32:
		nb_comp = 3;
		type = PNG_COLOR_TYPE_RGB;
		break;
	case GF_PIXEL_RGBA:
	case GF_PIXEL_ARGB:
		nb_comp = 4;
		type = PNG_COLOR_TYPE_RGB_ALPHA;
		break;
	default:
		return GF_NOT_SUPPORTED;
	}
	if (*dst_size < width*height*nb_comp) return GF_BUFFER_TOO_SMALL;


	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	//      png_voidp user_error_ptr, user_error_fn, user_warning_fn);

	if (png_ptr == NULL) return GF_IO_ERR;

	/* Allocate/initialize the image information data.  REQUIRED */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, NULL);
		return GF_IO_ERR;
	}

	/* Set error handling.  REQUIRED if you aren't supplying your own
    * error handling functions in the png_create_write_struct() call.
    */
	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return GF_NON_COMPLIANT_BITSTREAM;
	}

	udta.buffer = dst;
	udta.pos = 0;
	png_set_write_fn(png_ptr, &udta, gf_png_write, gf_png_flush);

	png_set_IHDR(png_ptr, info_ptr, width, height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	/* otherwise, if we are dealing with a color image then */
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.gray = 8;
	sig_bit.alpha = 8;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);

#if 0
	/* Optionally write comments into the image */
	text_ptr[0].key = "Title";
	text_ptr[0].text = "Mona Lisa";
	text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
	text_ptr[1].key = "Author";
	text_ptr[1].text = "Leonardo DaVinci";
	text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
	text_ptr[2].key = "Description";
	text_ptr[2].text = "<long text>";
	text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
#ifdef PNG_iTXt_SUPPORTED
	text_ptr[0].lang = NULL;
	text_ptr[1].lang = NULL;
	text_ptr[2].lang = NULL;
#endif
	png_set_text(png_ptr, info_ptr, text_ptr, 3);
#endif

	png_write_info(png_ptr, info_ptr);

	/* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
	png_set_shift(png_ptr, &sig_bit);

	/* pack pixels into bytes */
	png_set_packing(png_ptr);

	if (pixel_format==GF_PIXEL_ARGB) {
//		png_set_swap_alpha(png_ptr);
		png_set_bgr(png_ptr);
	}
	switch (pixel_format) {
	case GF_PIXEL_RGB_32:
		png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
		png_set_bgr(png_ptr);
		break;
	case GF_PIXEL_BGR_32:
	   png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
		break;
	case GF_PIXEL_BGR_24:
		png_set_bgr(png_ptr);
		break;
	}
	row_pointers = gf_malloc(sizeof(png_bytep)*height);
	for (k = 0; k < (s32)height; k++)
		row_pointers[k] = data + k*stride;

	png_write_image(png_ptr, row_pointers);
	png_write_end(png_ptr, info_ptr);
	gf_free(row_pointers);
	/* clean up after the write, and free any memory allocated */
	png_destroy_write_struct(&png_ptr, &info_ptr);

	*dst_size = udta.pos;
	return GF_OK;
}
Exemple #5
0
int
png_load(char *filename)
{
	int i,j,k;
	FILE *fd;
	u_char header[NUMBER];
	png_structp png_ptr;
	png_infop info_ptr,end_info;
	png_uint_32 width,height;
	int bit_depth,color_type,interlace_type;
	int compression_type,filter_type;
	int channels,rowbytes;
	double gamma;
	png_colorp palette;
	int num_palette;
	png_bytep *row_pointers;
	char c;
	int res=0;

	fd=fopen(filename,"rb");
	
	if(fd==NULL) {
		VGLEnd();
		perror("fopen");
		exit(1);
	}
	fread(header,1,NUMBER,fd);
	if(!png_check_sig(header,NUMBER)) {
		fprintf(stderr,"Not a PNG file.\n");
		return(-1);
	}
	png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,
		NULL,NULL);
	info_ptr=png_create_info_struct(png_ptr);
	end_info=png_create_info_struct(png_ptr);
	if(!png_ptr || !info_ptr || !end_info) {
		VGLEnd();
		fprintf(stderr,"failed to allocate needed structs!\n");
		png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
		return(-1);
	}
	png_set_sig_bytes(png_ptr,NUMBER);
	png_init_io(png_ptr,fd);
	png_read_info(png_ptr,info_ptr);
	png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,
		&color_type,&interlace_type,&compression_type,&filter_type);
	png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
	channels=png_get_channels(png_ptr,info_ptr);
	rowbytes=png_get_rowbytes(png_ptr,info_ptr);
	if(bit_depth==16)
		png_set_strip_16(png_ptr);
	if(color_type & PNG_COLOR_MASK_ALPHA) 
		png_set_strip_alpha(png_ptr);
	if(png_get_gAMA(png_ptr,info_ptr,&gamma))
		png_set_gamma(png_ptr,screen_gamma,gamma);
	else
	png_set_gamma(png_ptr,screen_gamma,0.45);
	if(res==0) {
		/* Dither */
		if(color_type & PNG_COLOR_MASK_COLOR) {
			if(png_get_valid(png_ptr,info_ptr,PNG_INFO_PLTE)) {
				png_uint_16p histogram;
				png_get_hIST(png_ptr,info_ptr,&histogram);
				png_set_dither(png_ptr,palette,num_palette,max_screen_colors,histogram,0);
			} else {
				png_color std_color_cube[16]={
					{0x00,0x00,0x00},
					{0x02,0x02,0x02},
					{0x04,0x04,0x04},
					{0x06,0x06,0x06},
					{0x08,0x08,0x08},
					{0x0a,0x0a,0x0a},
					{0x0c,0x0c,0x0c},
					{0x0e,0x0e,0x0e},
					{0x10,0x10,0x10},
					{0x12,0x12,0x12},
					{0x14,0x14,0x14},
					{0x16,0x16,0x16},
					{0x18,0x18,0x18},
					{0x1a,0x1a,0x1a},
					{0x1d,0x1d,0x1d},
					{0xff,0xff,0xff},
				};
				png_set_dither(png_ptr,std_color_cube,max_screen_colors,max_screen_colors,NULL,0);
			}
		}
	}
	png_set_packing(png_ptr);
	if(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);
	}
	png_read_update_info(png_ptr,info_ptr);
	png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,
		&color_type,&interlace_type,&compression_type,&filter_type);
	png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
	channels=png_get_channels(png_ptr,info_ptr);
	rowbytes=png_get_rowbytes(png_ptr,info_ptr);
	row_pointers=malloc(height*sizeof(png_bytep));
	for(i=0;i<height;i++) {
		row_pointers[i]=malloc(rowbytes);
	}
	png_read_image(png_ptr,row_pointers);
	png_read_end(png_ptr,end_info);
	png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
	fclose(fd);
	/* Set palette */
	if(res) k=2;
	else k=2;
	for(i=0;i<256;i++) {
	 	pal_red[i]=255;
	 	pal_green[i]=255;
	 	pal_blue[i]=255;
	}
	for(i=0;i<num_palette;i++) {
	 	pal_red[i]=(palette+i)->red>>k;
	 	pal_green[i]=(palette+i)->green>>k;
	 	pal_blue[i]=(palette+i)->blue>>k;
	}
	pal_colors=num_palette;
	if(pic.Bitmap!=NULL) free(pic.Bitmap);
	pic.Bitmap=(byte *)calloc(rowbytes*height,sizeof(byte));
	pic.Type=MEMBUF;
	pic.Xsize=rowbytes;
	pic.Ysize=height;
	for(i=0;i<rowbytes;i++) {
		for(j=0;j<height;j++) {
			VGLSetXY(&pic,
			i,j,row_pointers[j][i]);
		}
	}
	a.zoom=1;
	a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2;
	a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2;
	a.rotate=0;
	return(0);
}
Exemple #6
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;
    }
}
bool PNGImageFileType::write(const Image        *OSG_PNG_ARG(pImage  ), 
                                   std::ostream &OSG_PNG_ARG(os      ),
                             const std::string  &OSG_PNG_ARG(mimetype))
{
#ifdef OSG_WITH_PNG

    png_structp png_ptr;
    png_infop info_ptr;

    if(pImage->getDimension() < 1 || pImage->getDimension() > 2)
    {
        FWARNING(("PNGImageFileType::write: invalid dimension %d!\n",
                  pImage->getDimension()));

        return false;
    }
    
    /* 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 check that
    * the library version is compatible with the one used at compile time,
    * in case we are using dynamically linked libraries.  REQUIRED.
     */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                      0, &errorOutput, &warningOutput);

    if(png_ptr == NULL)
        return false;

    /* Allocate/initialize the image information data.  REQUIRED */
    info_ptr = png_create_info_struct(png_ptr);

    if(info_ptr == NULL)
    {
        png_destroy_write_struct(&png_ptr,  NULL);
        return false;
    }
    
    /* set up the output handlers */
    png_set_write_fn(png_ptr, &os, &osWriteFunc, &osFlushFunc);

    /* This is the hard way */

    /* Set the image information here.  Width and height are up to 2^31,
    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
    */

    Int32 ctype;
    switch(pImage->getPixelFormat())
    {
        case Image::OSG_L_PF:       
            ctype = PNG_COLOR_TYPE_GRAY;        
            break;
            
        case Image::OSG_LA_PF:      
            ctype = PNG_COLOR_TYPE_GRAY_ALPHA;          
            break;
            
#if defined(GL_BGR) || defined(GL_BGR_EXT)
        case Image::OSG_BGR_PF:
#endif
        case Image::OSG_RGB_PF:     
            ctype = PNG_COLOR_TYPE_RGB;                 
            break;
            
#if defined(GL_BGRA) || defined(GL_BGRA_EXT)
        case Image::OSG_BGRA_PF:
#endif
        case Image::OSG_RGBA_PF:    
            ctype = PNG_COLOR_TYPE_RGB_ALPHA;           
            break;
            
        default:
            FWARNING(("PNGImageFileType::write: unknown pixel format %d!\n",
                      pImage->getPixelFormat()));
            png_destroy_write_struct(&png_ptr,  NULL);
            return false;
            
    }
    
    Int32 bit_depth;
    switch(pImage->getDataType()) 
    {
        case Image::OSG_UINT8_IMAGEDATA:
            bit_depth = 8;
            break;
        case Image::OSG_UINT16_IMAGEDATA:
            bit_depth = 16;
            break;
        default:
            FWARNING (("Invalid pixeldepth, cannot store data\n"));
            return false;
    };

    png_set_IHDR(png_ptr, info_ptr, pImage->getWidth(), pImage->getHeight(),
                 bit_depth,ctype,      
                 PNG_INTERLACE_NONE, 
                 PNG_COMPRESSION_TYPE_BASE, 
                 PNG_FILTER_TYPE_BASE);

    // set resolution png supports only meter per pixel,
    // so we do a conversion from dpi with some rounding.
    png_uint_32 res_x = png_uint_32(pImage->getResX());
    png_uint_32 res_y = png_uint_32(pImage->getResY());
    if(pImage->getResUnit() == Image::OSG_RESUNIT_INCH)
    {
        res_x = png_uint_32((pImage->getResX() * 39.37007874f) < 0.0f ?
                            (pImage->getResX() * 39.37007874f) - 0.5f :
                            (pImage->getResX() * 39.37007874f) + 0.5f);
        res_y = png_uint_32((pImage->getResY() * 39.37007874f) < 0.0f ?
                            (pImage->getResY() * 39.37007874f) - 0.5f :
                            (pImage->getResY() * 39.37007874f) + 0.5f);
    }

    png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
                 PNG_RESOLUTION_METER);

#if 0
    /* optional significant bit chunk */
    /* if we are dealing with a grayscale image then */
    sig_bit.gray = true_bit_depth;
    /* otherwise, if we are dealing with a color image then */
    sig_bit.red = true_red_bit_depth;
    sig_bit.green = true_green_bit_depth;
    sig_bit.blue = true_blue_bit_depth;
    /* if the image has an alpha channel then */
    sig_bit.alpha = true_alpha_bit_depth;
    png_set_sBIT(png_ptr, info_ptr, sig_bit);


    /* Optional gamma chunk is strongly suggested if you have any guess
    * as to the correct gamma of the image.
    */
    png_set_gAMA(png_ptr, info_ptr, gamma);

    /* Optionally write comments into the image */
    text_ptr[0].key = "Title";
    text_ptr[0].text = "Mona Lisa";
    text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
    text_ptr[1].key = "Author";
    text_ptr[1].text = "Leonardo DaVinci";
    text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
    text_ptr[2].key = "Description";
    text_ptr[2].text = "<long text>";
    text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
#ifdef PNG_iTXt_SUPPORTED
    text_ptr[0].lang = NULL;
    text_ptr[1].lang = NULL;
    text_ptr[2].lang = NULL;
#endif
    png_set_text(png_ptr, info_ptr, text_ptr, 3);
#endif
    /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
    /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
    * on read and must be written in accordance with the sRGB profile */

    /* Write the file header information.  REQUIRED */
    png_write_info(png_ptr, info_ptr);

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth == 16) 
      png_set_swap(png_ptr);
#endif

#if 0
    /* invert monochrome pixels */
    png_set_invert_mono(png_ptr);

    /* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
    png_set_shift(png_ptr, &sig_bit);

    /* pack pixels into bytes */
    png_set_packing(png_ptr);

    /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
    * RGB (4 channels -> 3 channels). The second parameter is not used.
    */
    png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

    /* swap bytes of 16-bit files to most significant byte first */
    png_set_swap(png_ptr);

    /* swap bits of 1, 2, 4 bit packed pixel formats */
    png_set_packswap(png_ptr);
#endif

    if(pImage->getPixelFormat() == Image::OSG_BGR_PF ||
       pImage->getPixelFormat() == Image::OSG_BGRA_PF )
    {
        /* flip BGR pixels to RGB */
        png_set_bgr(png_ptr);
        
        /* swap location of alpha bytes from ARGB to RGBA */
        png_set_swap_alpha(png_ptr);
    }
    
    /* The easiest way to write the image (you may have a different memory
     * layout, however, so choose what fits your needs best).  You need to
     * use the first method if you aren't handling interlacing yourself.
     */
    png_bytep *row_pointers = new png_bytep [pImage->getHeight()];
    
    for(Int32 k = 0; k < pImage->getHeight(); k++)
    {
        row_pointers[k] = 
            (const_cast<UInt8 *>(pImage->getData())) + 
            (pImage->getHeight() - 1 - k) * 
            pImage->getWidth() * pImage->getBpp();
    }
    
    /* write out the entire image data in one call */
    png_write_image(png_ptr, row_pointers);

    /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);
    
    /* clean up after the write, and free any memory allocated */
    png_destroy_write_struct(&png_ptr, &info_ptr);

    delete [] row_pointers;

    /* that's it */
    return true;

#else
    SWARNING << getMimeType() 
             << " write is not compiled into the current binary " 
             << endLog;

    return false;
#endif
}
errCode genTextures(const char *rootDir, const sFileList *files, sTex ***dynarrTextures){
	static const size_t BUFFLEN = 1024;

	int numTexs=0;
	int idxFile = files->num;
	sTex *refTex;

	if(idxFile <= 0 || rootDir == NULL || rootDir[0] == '\0' || dynarrTextures == NULL)
		return PROBLEM;

	size_t lenRootDir = strlen(rootDir);
	char filePath[BUFFLEN];
	FILE *handFile;
	png_byte header[PNGHEAD_SIZE];

	strncpy(filePath, rootDir, 1024);
	if(lenRootDir>0 && filePath[lenRootDir-1]!='/'){
		filePath[lenRootDir] = '/';
		lenRootDir += 1;
	}

	while(idxFile > 0){
		--idxFile;

		strncpy(&filePath[lenRootDir], files->dynarrFiles[idxFile], 1024 - lenRootDir);

		handFile = fopen(filePath, "rb");

		if(handFile == NULL){
			WARN("Can't open file %s", filePath);
			continue;
		}

		if(	fread(header, sizeof(png_byte), PNGHEAD_SIZE, handFile) == PNGHEAD_SIZE
			&& png_sig_cmp(header, 0, PNGHEAD_SIZE) == 0
		){
			XTRA_LOG("File %s opened as PNG", filePath);

		}else{
			WARN("File %s isn't a PNG", filePath);
			fclose(handFile);
			continue;
		}

		++numTexs;
		(*dynarrTextures) = (sTex**)realloc_chk((*dynarrTextures), (numTexs+1) * sizeof(sTex*));
		(*dynarrTextures)[numTexs]=NULL;

		refTex = (*dynarrTextures)[numTexs-1] = (sTex*)malloc_chk(sizeof(sTex));
		memset(refTex, 0, sizeof(sTex));

		refTex->pngptrData = png_create_read_struct(
			PNG_LIBPNG_VER_STRING, NULL, NULL, &myPNGWarnFoo
		);

		if(refTex->pngptrData == NULL){
			WARN("Unable to create png struct");
			fclose(handFile);
			continue;
		}

		if(setjmp(png_jmpbuf(refTex->pngptrData)) != 0){ 	/** jumps here on errors. */
			cleanupPNGImg(
				refTex->pngptrData,
				&refTex->dynarrRows
			);
			png_destroy_read_struct(
				&(refTex->pngptrData),
				&(refTex->pngptrInfo),
				NULL
			);
			refTex->h = refTex->w = 0;

		}else{
			refTex->pngptrInfo = png_create_info_struct(
				refTex->pngptrData
			);

			if(refTex->pngptrInfo == NULL){
				WARN("Unable to create png info struct");
				fclose(handFile);
				continue;
			}

			/** setup PNG decode */
			png_init_io(refTex->pngptrData, handFile);
			png_set_sig_bytes(refTex->pngptrData, PNGHEAD_SIZE);
			png_read_info(refTex->pngptrData, refTex->pngptrInfo);

			png_byte colorCurrent = png_get_color_type(
				refTex->pngptrData, refTex->pngptrInfo
			);

			png_set_filler(refTex->pngptrData, 0, PNG_FILLER_AFTER);
			png_set_packing(refTex->pngptrData);	/** if < 8 bits */

			{
				png_color_8p sig_bit;
				if (png_get_sBIT(refTex->pngptrData, refTex->pngptrInfo, &sig_bit))
					png_set_shift(refTex->pngptrData, sig_bit);
			}

			switch(colorCurrent){
				case PNG_COLOR_TYPE_RGB_ALPHA:
					/** already good */
				break;
				case PNG_COLOR_TYPE_RGB:
					png_set_tRNS_to_alpha(refTex->pngptrData);
				break;
				case PNG_COLOR_TYPE_PALETTE:
					png_set_palette_to_rgb( refTex->pngptrData );
					png_set_tRNS_to_alpha(refTex->pngptrData);
				break;
				case PNG_COLOR_TYPE_GRAY:
					png_set_expand_gray_1_2_4_to_8( refTex->pngptrData );
					png_set_tRNS_to_alpha(refTex->pngptrData);
				break;
				default:
					WARN("unsupported colour");
				break;
			}

			png_read_update_info(refTex->pngptrData, refTex->pngptrInfo);

			colorCurrent = png_get_color_type(
				refTex->pngptrData, refTex->pngptrInfo
			);

			if(colorCurrent != PNG_COLOR_TYPE_RGB_ALPHA){
				printf("<warning> %s didn't convert to the right colour type\n", files->dynarrFiles[idxFile]);
				png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL);
				fclose(handFile);
				continue;
			}

			refTex->colorType = colorCurrent;

			const int numPasses = png_set_interlace_handling( refTex->pngptrData );

			/** setup other data */
			copyString(&refTex->name, files->dynarrFiles[idxFile]);

			/** setup texture */
			unsigned int row;
			const png_uint_32 sizeRow = png_get_rowbytes( refTex->pngptrData, refTex->pngptrInfo );

			refTex->w = png_get_image_width(
				refTex->pngptrData, refTex->pngptrInfo
			);
			refTex->h = png_get_image_height(
				refTex->pngptrData, refTex->pngptrInfo
			);

			if(sizeRow/refTex->w != DEFAULT_BYTE_PP){
				WARN("%s didn't convert to the right bit depth", refTex->name);
				png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL);
				fclose(handFile);
				continue;
			}

			refTex->dynarrRows = calloc_chk((refTex->h +1), sizeof(png_byte*));
			refTex->dynarrRows[refTex->h] = NULL;

			for(row = 0; row < refTex->h; ++row)
				refTex->dynarrRows[row] = png_malloc(refTex->pngptrData, sizeRow);

			unsigned int pass;
			for(pass=0; pass < numPasses; ++pass){
				for(row = 0; row < refTex->h; ++row){
					png_read_rows(
						refTex->pngptrData,
						&refTex->dynarrRows[row],
						NULL,
						1
					);
				}
			}

			png_read_end(refTex->pngptrData, refTex->pngptrInfo);
		}

		fclose(handFile);
	}
	return NOPROB;
}
Exemple #9
0
bool KPWriteImage::write2PNG(const QString& destPath)
{
    FILE* file = fopen(QFile::encodeName(destPath), "wb");
    if (!file)
    {
        kDebug( 51000 ) << "Failed to open PNG file for writing" << endl;
        return false;
    }

    uchar       *data       = 0;
    int          bitsDepth  = d->sixteenBit ? 16 : 8;
    png_color_8  sig_bit;
    png_bytep    row_ptr;
    png_structp  png_ptr    = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop    info_ptr   = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, file);

    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)      // Intel
        png_set_bgr(png_ptr);
    else                                                    // PPC
        png_set_swap_alpha(png_ptr);

    if (d->hasAlpha)
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 8 * sizeof(uchar)];
        else
            data = new uchar[d->width * 4 * sizeof(uchar)];
    }
    else
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB,        PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 6 * sizeof(uchar)];
        else
            data = new uchar[d->width * 3 * sizeof(uchar)];
    }

    sig_bit.red   = bitsDepth;
    sig_bit.green = bitsDepth;
    sig_bit.blue  = bitsDepth;
    sig_bit.alpha = bitsDepth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_compression_level(png_ptr, 9);

    // Write ICC profil.
    if (!d->iccProfile.isEmpty())
    {
        png_set_iCCP(png_ptr, info_ptr, (png_charp)"icc", PNG_COMPRESSION_TYPE_BASE,
                     d->iccProfile.data(), d->iccProfile.size());
    }

    // Write Software info.
    QString libpngver(PNG_HEADER_VERSION_STRING);
    libpngver.replace('\n', ' ');
    QString soft = d->kipipluginsVer;
    soft.append(QString(" (%1)").arg(libpngver));
    png_text text;
    text.key  = (png_charp)"Software";
    text.text = soft.toAscii().data();
    text.compression = PNG_TEXT_COMPRESSION_zTXt;
    png_set_text(png_ptr, info_ptr, &(text), 1);

    // Store Exif data.
    QByteArray ba = d->metadata.getExif(true);
    writeRawProfile(png_ptr, info_ptr, (png_charp)"exif", ba.data(), (png_uint_32) ba.size());

    // Store Iptc data.
    QByteArray ba2 = d->metadata.getIptc();
    writeRawProfile(png_ptr, info_ptr, (png_charp)"iptc", ba2.data(), (png_uint_32) ba2.size());

    // Store Xmp data.
    QByteArray ba3 = d->metadata.getXmp();
    writeRawProfile(png_ptr, info_ptr, (png_charp)("xmp"), ba3.data(), (png_uint_32) ba3.size());

    png_write_info(png_ptr, info_ptr);
    png_set_shift(png_ptr, &sig_bit);
    png_set_packing(png_ptr);

    uchar* ptr = (uchar*)d->data.data();
    uint   x, y, j;

    for (y = 0; y < d->height; y++)
    {
        if (cancel())
        {
            delete [] data;
            fclose(file);
            png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
            png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
            return false;
        }

        j = 0;

        for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth())
        {
            if (d->sixteenBit)
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                    data[j++] = ptr[x+7];  // Alpha
                    data[j++] = ptr[x+6];
                }
                else
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                }
            }
            else
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                    data[j++] = ptr[x+3];  // Alpha
                }
                else
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                }
            }
        }

        row_ptr = (png_bytep) data;

        png_write_rows(png_ptr, &row_ptr, 1);
        ptr += (d->width * bytesDepth());
    }

    delete [] data;

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
    png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
    fclose(file);

    return true;
}
Exemple #10
0
Py::Object
_png_module::read_png(const Py::Tuple& args)
{

    args.verify_length(1);
    png_byte header[8];   // 8 is the maximum size that can be checked
    FILE* fp = NULL;
    bool close_file = false;

    Py::Object py_fileobj = Py::Object(args[0]);
#if PY_MAJOR_VERSION >= 3
    int fd = PyObject_AsFileDescriptor(py_fileobj.ptr());
    PyErr_Clear();
#endif

    if (py_fileobj.isString())
    {
        std::string fileName = Py::String(py_fileobj);
        const char *file_name = fileName.c_str();
        if ((fp = fopen(file_name, "rb")) == NULL)
        {
            throw Py::RuntimeError(
                Printf("Could not open file %s for reading", file_name).str());
        }
        close_file = true;
    }
#if PY_MAJOR_VERSION >= 3
    else if (fd != -1) {
        fp = fdopen(fd, "r");
    }
#else
    else if (PyFile_CheckExact(py_fileobj.ptr()))
    {
        fp = PyFile_AsFile(py_fileobj.ptr());
    }
#endif
    else
    {
        PyObject* read_method = PyObject_GetAttrString(py_fileobj.ptr(), "read");
        if (!(read_method && PyCallable_Check(read_method)))
        {
            Py_XDECREF(read_method);
            throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object");
        }
        Py_XDECREF(read_method);
    }

    if (fp)
    {
        if (fread(header, 1, 8, fp) != 8)
        {
            throw Py::RuntimeError(
                "_image_module::readpng: error reading PNG header");
        }
    }
    else
    {
        _read_png_data(py_fileobj.ptr(), header, 8);
    }
    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");
    }

    if (fp)
    {
        png_init_io(png_ptr, fp);
    }
    else
    {
        png_set_read_fn(png_ptr, (void*)py_fileobj.ptr(), &read_png_data);
    }
    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 < (png_uint_32)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 < (png_uint_32)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);
#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_file)
    {
        fclose(fp);
    }
    for (row = 0; row < height; row++)
    {
        delete [] row_pointers[row];
    }
    delete [] row_pointers;
    return Py::asObject((PyObject*)A);
}
Exemple #11
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
}
void write_png_file(const char* file_name, int32 width, int32 height, uint8 * data)
{
	if (CommandLineParser::Instance()->GetVerbose())
		printf("* Writing PNG file (%d x %d): %s\n", width, height, file_name);
	
	png_byte color_type = PNG_COLOR_TYPE_RGBA;
	png_byte bit_depth = 8;
	png_color_8 sig_bit;
	
	png_structp png_ptr;
	png_infop info_ptr;
	
	png_bytep * row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
	for (int y = 0; y < height; y++)
	{
		row_pointers[y] = (png_byte*) &data[y * width * 4];
	}
	
	
	/* create file */
	FILE *fp = fopen(file_name, "wb");
	if (!fp)
		abort_("[write_png_file] File %s could not be opened for writing", file_name);
	
	
	/* initialize stuff */
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	
	if (!png_ptr)
		abort_("[write_png_file] png_create_write_struct failed");
	
	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		abort_("[write_png_file] png_create_info_struct failed");
	
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during init_io");
	
	png_init_io(png_ptr, fp);
	
	
	/* write header */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during writing header");
	
	png_set_IHDR(png_ptr, info_ptr, width, height,
				 bit_depth, color_type, PNG_INTERLACE_NONE,
				 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
	
	
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.alpha = 8;

	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
		
	png_write_info(png_ptr, info_ptr);
	png_set_shift(png_ptr, &sig_bit);
	png_set_packing(png_ptr);
	
	/* write bytes */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during writing bytes");
	
	png_write_image(png_ptr, row_pointers);
	
	
	/* end write */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[write_png_file] Error during end of write");
	
	png_write_end(png_ptr, NULL);
	
	free(row_pointers);
	
	fclose(fp);
}
Exemple #13
0
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
             int transforms,
             voidp params)
{
    int row;

    if(png_ptr == NULL) return;
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
    if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
        png_set_invert_alpha(png_ptr);
#endif

    png_read_info(png_ptr, info_ptr);
    if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
        png_error(png_ptr,"Image is too high to process with png_read_png()");



#if defined(PNG_READ_16_TO_8_SUPPORTED)
    if (transforms & PNG_TRANSFORM_STRIP_16)
        png_set_strip_16(png_ptr);
#endif

#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
    if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
        png_set_strip_alpha(png_ptr);
#endif

#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
    if (transforms & PNG_TRANSFORM_PACKING)
        png_set_packing(png_ptr);
#endif

#if defined(PNG_READ_PACKSWAP_SUPPORTED)
    if (transforms & PNG_TRANSFORM_PACKSWAP)
        png_set_packswap(png_ptr);
#endif

#if defined(PNG_READ_EXPAND_SUPPORTED)
    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


#if defined(PNG_READ_INVERT_SUPPORTED)
    if (transforms & PNG_TRANSFORM_INVERT_MONO)
        png_set_invert_mono(png_ptr);
#endif

#if defined(PNG_READ_SHIFT_SUPPORTED)
    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)
    if (transforms & PNG_TRANSFORM_BGR)
        png_set_bgr(png_ptr);
#endif

#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
    if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
        png_set_swap_alpha(png_ptr);
#endif

#if defined(PNG_READ_SWAP_SUPPORTED)
    if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
        png_set_swap(png_ptr);
#endif



    png_read_update_info(png_ptr, info_ptr);



#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 * png_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;


    png_read_end(png_ptr, info_ptr);

    transforms = transforms;
    params = params;

}
Exemple #14
0
/* 
   Dump an image to a Portable Network Graphics (PNG) file. File_name
   is where the file goes, i_height and i_width are the height and
   width in pixels of the image. The data for the image is stored as a
   linear array of one byte for each of red, green, and blue
   components of an RGB pixel. Thus row[i] will begin at rgb_image +
   i*(i_width*3) and the blue pixel at image[i][0] would be rgb_image +
   i*(i_width*3) + 1.
   
 */
void 
write_png(const char *file_name, png_uint_32 i_height, png_uint_32 i_width,
	  void *rgb_image, /*in*/ png_text *text_ptr, int i_text_count )
{
  FILE *fp;
  png_structp png_ptr;
  png_infop info_ptr;
  png_color_8 sig_bit;
  png_bytep *row_pointers;

  unsigned int i,j;

  /* open the file */
  fp = fopen(file_name, "wb");
  if (fp == NULL)
    return;
  
  /* 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 check that
   * the library version is compatible with the one used at compile time,
   * in case we are using dynamically linked libraries.  REQUIRED.
   */
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL,
				    user_error_fn, user_warning_fn);
  
  if (png_ptr == NULL)
    {
      fclose(fp);
      return;
    }
  
  /* Allocate/initialize the image information data.  REQUIRED */
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL)
    {
      fclose(fp);
      png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
      return;
    }
  
  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_write_struct() call.
   */
  if (setjmp(png_ptr->jmpbuf))
    {
      /* If we get here, we had a problem writing the file */
      fclose(fp);
      png_destroy_write_struct(&png_ptr,  (png_infopp) &info_ptr);
      return;
   }

   /* Set up the output control using standard C streams. This
      is required. */
   png_init_io(png_ptr, fp);

   /* Set the image information here.  i_width and i_height are up to 2^31,
    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
    */
   png_set_IHDR(png_ptr, info_ptr, i_width, i_height, 8, PNG_COLOR_TYPE_RGB,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 
		PNG_FILTER_TYPE_BASE);

   /* For color images: */
   sig_bit.red   = 8;
   sig_bit.green = 8;
   sig_bit.blue  = 8;

   if (text_ptr)
     png_set_text(png_ptr, info_ptr, text_ptr, i_text_count);

   /* Write the file header information.  REQUIRED */
   png_write_info(png_ptr, info_ptr);

   /* Once we write out the header, the compression type on the text
    * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
    * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
    * at the end.
    */

   /* Shift the pixels up to a legal bit depth and fill in
    * as appropriate to correctly scale the image.
    */
   png_set_shift(png_ptr, &sig_bit);

   /* pack pixels into bytes */
   png_set_packing(png_ptr);

   row_pointers = png_malloc(png_ptr, i_height*sizeof(png_bytep *));
   for (i=0, j=0; i<i_height; i++, j+=i_width*3) {
     row_pointers[i] = rgb_image + j; 
   }
   
   png_set_rows   (png_ptr, info_ptr, row_pointers);
   png_write_image(png_ptr, row_pointers);

   /* You can write optional chunks like tEXt, zTXt, and tIME at the end
    * as well.
    */

   /* It is REQUIRED to call this to finish writing the rest of the file */
   png_write_end(png_ptr, info_ptr);

   /* if you allocated any text comments, free them here */
   /* free image data if allocated. */

   /* clean up after the write, and free any memory allocated */
   png_destroy_info_struct(png_ptr, &info_ptr);

   /* clean up after the write, and free any memory allocated */
   png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

   fclose(fp);

   return;
}
Exemple #15
0
static void read_png(void)
{
    unsigned char sig_buf[8];
    png_bytep png_buffer;
    png_bytep *png_rows;
    int linesize;
    struct Cell_head cellhd;
    unsigned int y, c;
    png_color_8p sig_bit;
    int sbit, interlace;
    FILE *ifp;

    /* initialize input stream and PNG library */

    ifp = fopen(input, "rb");
    if (!ifp)
	G_fatal_error(_("Unable to open PNG file '%s'"), input);

    if (fread(sig_buf, sizeof(sig_buf), 1, ifp) != 1)
	G_fatal_error(_("Input file empty or too short"));

    if (png_sig_cmp(sig_buf, 0, sizeof(sig_buf)) != 0)
	G_fatal_error(_("Input file not a PNG file"));

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
	G_fatal_error(_("Unable to allocate PNG structure"));

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
	G_fatal_error(_("Unable to allocate PNG structure"));

    if (setjmp(png_jmpbuf(png_ptr)))
	G_fatal_error(_("PNG error"));

    png_init_io(png_ptr, ifp);
    png_set_sig_bytes(png_ptr, sizeof(sig_buf));

    png_read_info(png_ptr, info_ptr);

    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
		 &color_type, &interlace_type, &compression_type, &filter_type);

    if (Header || G_verbose() == G_verbose_max())
	print_header();

    if (Header)
    {
	fclose(ifp);    
	exit(0);
    }

    /* read image parameters and set up data conversions */

    if (png_get_bit_depth(png_ptr, info_ptr) < 8)
	png_set_packing(png_ptr);

    sbit = png_get_sBIT(png_ptr, info_ptr, &sig_bit);
    if (sbit)
        png_set_shift(png_ptr, sig_bit);

    if (!png_get_gAMA(png_ptr, info_ptr, &f_gamma))
	f_gamma = 0.0;

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

    if (Float && color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    interlace = (interlace_type != PNG_INTERLACE_NONE);

    ialpha = (int) (alpha * channels[C_A].maxval);

    t_gamma = (f_gamma != 0.0 && d_gamma != 0.0)
	? f_gamma * d_gamma
	: 1.0;

    /* allocate input buffer */

    linesize = png_get_rowbytes(png_ptr, info_ptr);

    png_buffer = G_malloc(interlace
			  ? height * linesize
			  : linesize);

    if (interlace)
    {
	png_rows = G_malloc(height * sizeof(png_bytep));
	for (y = 0; y < height; y++)
	    png_rows[y] = png_buffer + y * linesize;
    }

    /* initialize cell header */

    Rast_get_window(&cellhd);

    cellhd.rows = height;
    cellhd.cols = width;
    cellhd.north = cellhd.rows;
    cellhd.south = 0.0;
    cellhd.east = cellhd.cols;
    cellhd.west = 0.0;
    cellhd.ns_res = 1;
    cellhd.ew_res = 1;

    Rast_set_window(&cellhd);

    /* initialize channel information */

    switch (color_type)
    {
    case PNG_COLOR_TYPE_GRAY:
	init_channel(&channels[C_Y]);
	break;

    case PNG_COLOR_TYPE_GRAY_ALPHA:
	init_channel(&channels[C_Y]);
	init_channel(&channels[C_A]);
	break;

    case PNG_COLOR_TYPE_PALETTE:
	init_channel(&channels[C_P]);
	break;

    case PNG_COLOR_TYPE_RGB:
	init_channel(&channels[C_R]);
	init_channel(&channels[C_G]);
	init_channel(&channels[C_B]);
	break;

    case PNG_COLOR_TYPE_RGB_ALPHA:
	init_channel(&channels[C_R]);
	init_channel(&channels[C_G]);
	init_channel(&channels[C_B]);
	init_channel(&channels[C_A]);
	break;
    }

    if (sbit)
    {
	channels[C_R].maxval = (1 << sig_bit->red  ) - 1;
	channels[C_G].maxval = (1 << sig_bit->green) - 1;
	channels[C_B].maxval = (1 << sig_bit->blue ) - 1;
	channels[C_Y].maxval = (1 << sig_bit->gray ) - 1;
	channels[C_A].maxval = (1 << sig_bit->alpha) - 1;
    }
    else
    {
	channels[C_R].maxval = (1 << bit_depth) - 1;
	channels[C_G].maxval = (1 << bit_depth) - 1;
	channels[C_B].maxval = (1 << bit_depth) - 1;
	channels[C_Y].maxval = (1 << bit_depth) - 1;
	channels[C_A].maxval = (1 << bit_depth) - 1;
    }

    /* read image and write raster layers */

    if (interlace)
	png_read_image(png_ptr, png_rows);

    for (y = 0; y < height; y++)
    {
	png_bytep p;

	if (interlace)
	    p = png_rows[y];
	else
	{
	    png_read_row(png_ptr, png_buffer, NULL);
	    p = png_buffer;
	}

	if (Float)
	    write_row_float(p);
	else
	    write_row_int(p);
    }

    png_read_end(png_ptr, NULL);

    fclose(ifp);

    /* close output files */

    for (c = 0; c < 6; c++)
    {
	channel *ch = &channels[c];

	if (!ch->active)
	    continue;

	Rast_close(ch->fd);

	if (Float)
	    G_free(ch->fbuf);
	else
	    G_free(ch->buf);
    }

    /* write title and color table */

    G_verbose_message(_("Creating support files for <%s>..."), output);

    for (c = 0; c < 6; c++)
    {
	channel *ch = &channels[c];

	if (!ch->active)
	    continue;

	if (title && *title)
	    Rast_put_cell_title(ch->name, title);

	if (Float)
	    write_colors_float(c);
	else
	    write_colors_int(c);
    }

    G_free(png_buffer);
    if (interlace)
	G_free(png_rows);

    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
}
Exemple #16
0
static gboolean real_save_png (GdkPixbuf        *pixbuf, 
                               gchar           **keys,
                               gchar           **values,
                               GError          **error,
                               gboolean          to_callback,
                               FILE             *f,
                               GdkPixbufSaveFunc save_func,
                               gpointer          user_data)
{
       png_structp png_ptr = NULL;
       png_infop info_ptr;
       png_textp text_ptr = NULL;
       guchar *ptr;
       guchar *pixels;
       int y;
       int i;
       png_bytep row_ptr;
       png_color_8 sig_bit;
       int w, h, rowstride;
       int has_alpha;
       int bpc;
       int num_keys;
       int compression = -1;
       gboolean success = TRUE;
       guchar *icc_profile = NULL;
       gsize icc_profile_size = 0;
       SaveToFunctionIoPtr to_callback_ioptr;

       num_keys = 0;

       if (keys && *keys) {
               gchar **kiter = keys;
               gchar **viter = values;

               while (*kiter) {
                       if (strncmp (*kiter, "tEXt::", 6) == 0) {
                               gchar  *key = *kiter + 6;
                               int     len = strlen (key);
                               if (len < 1 || len > 79) {
                                       g_set_error_literal (error,
                                                            GDK_PIXBUF_ERROR,
                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                                            _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
                                       success = FALSE;
                                       goto cleanup;
                               }
                               for (i = 0; i < len; i++) {
                                       if ((guchar) key[i] > 127) {
                                               g_set_error_literal (error,
                                                                    GDK_PIXBUF_ERROR,
                                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                                    _("Keys for PNG text chunks must be ASCII characters."));
                                               success = FALSE;
                                               goto cleanup;
                                       }
                               }
                               num_keys++;
                       } else if (strcmp (*kiter, "icc-profile") == 0) {
                               /* decode from base64 */
                               icc_profile = g_base64_decode (*viter, &icc_profile_size);
                               if (icc_profile_size < 127) {
                                       /* This is a user-visible error */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("Color profile has invalid length %d."),
                                                    (gint)icc_profile_size);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else if (strcmp (*kiter, "compression") == 0) {
                               char *endptr = NULL;
                               compression = strtol (*viter, &endptr, 10);

                               if (endptr == *viter) {
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
                                                    *viter);
                                       success = FALSE;
                                       goto cleanup;
                               }
                               if (compression < 0 || compression > 9) {
                                       /* This is a user-visible error;
                                        * lets people skip the range-checking
                                        * in their app.
                                        */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
                                                    compression);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else {
                               g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
                       }

                       ++kiter;
                       ++viter;
               }
       }

       if (num_keys > 0) {
               gchar **kiter = keys;
               gchar **viter = values;

               text_ptr = g_new0 (png_text, num_keys);
               for (i = 0; i < num_keys; i++) {
                       if (strncmp (*kiter, "tEXt::", 6) != 0) {
                                kiter++;
                                viter++;
                       }

                       text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
                       text_ptr[i].key  = *kiter + 6;
                       text_ptr[i].text = g_convert (*viter, -1, 
                                                     "ISO-8859-1", "UTF-8", 
                                                     NULL, &text_ptr[i].text_length, 
                                                     NULL);

#ifdef PNG_iTXt_SUPPORTED 
                       if (!text_ptr[i].text) {
                               text_ptr[i].compression = PNG_ITXT_COMPRESSION_NONE;
                               text_ptr[i].text = g_strdup (*viter);
                               text_ptr[i].text_length = 0;
                               text_ptr[i].itxt_length = strlen (text_ptr[i].text);
                               text_ptr[i].lang = NULL;
                               text_ptr[i].lang_key = NULL;
                       }
#endif

                       if (!text_ptr[i].text) {
                               gint j;
                               g_set_error (error,
                                            GDK_PIXBUF_ERROR,
                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                            _("Value for PNG text chunk %s cannot be converted to ISO-8859-1 encoding."), *kiter + 6);
                               for (j = 0; j < i; j++)
                                       g_free (text_ptr[j].text);
                               g_free (text_ptr);
                               return FALSE;
                       }

                        kiter++;
                        viter++;
               }
       }

       bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
       w = gdk_pixbuf_get_width (pixbuf);
       h = gdk_pixbuf_get_height (pixbuf);
       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
       has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
       pixels = gdk_pixbuf_get_pixels (pixbuf);

       png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
                                          error,
                                          png_simple_error_callback,
                                          png_simple_warning_callback);
       if (png_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }

       info_ptr = png_create_info_struct (png_ptr);
       if (info_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }
       if (setjmp (png_jmpbuf(png_ptr))) {
	       success = FALSE;
	       goto cleanup;
       }

       if (num_keys > 0) {
               png_set_text (png_ptr, info_ptr, text_ptr, num_keys);
       }

       if (to_callback) {
               to_callback_ioptr.save_func = save_func;
               to_callback_ioptr.user_data = user_data;
               to_callback_ioptr.error = error;
               png_set_write_fn (png_ptr, &to_callback_ioptr,
                                 png_save_to_callback_write_func,
                                 png_save_to_callback_flush_func);
       } else {
               png_init_io (png_ptr, f);
       }

       if (compression >= 0)
               png_set_compression_level (png_ptr, compression);

#if defined(PNG_iCCP_SUPPORTED)
        /* the proper ICC profile title is encoded in the profile */
        if (icc_profile != NULL) {
                png_set_iCCP (png_ptr, info_ptr,
                              "ICC profile", PNG_COMPRESSION_TYPE_BASE,
                              (png_bytep) icc_profile, icc_profile_size);
        }
#endif

       if (has_alpha) {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       } else {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       }
       sig_bit.red = bpc;
       sig_bit.green = bpc;
       sig_bit.blue = bpc;
       sig_bit.alpha = bpc;
       png_set_sBIT (png_ptr, info_ptr, &sig_bit);
       png_write_info (png_ptr, info_ptr);
       png_set_shift (png_ptr, &sig_bit);
       png_set_packing (png_ptr);

       ptr = pixels;
       for (y = 0; y < h; y++) {
               row_ptr = (png_bytep)ptr;
               png_write_rows (png_ptr, &row_ptr, 1);
               ptr += rowstride;
       }

       png_write_end (png_ptr, info_ptr);

cleanup:
        if (png_ptr != NULL)
                png_destroy_write_struct (&png_ptr, &info_ptr);

        g_free (icc_profile);

        if (text_ptr != NULL) {
                for (i = 0; i < num_keys; i++)
                        g_free (text_ptr[i].text);
                g_free (text_ptr);
        }

       return success;
}
static void read_png_file_low(const char* file_name, png_image_data_t *png_image_data)
{
    png_structp png_ptr;
    int number_of_passes;
	char header[8];	// 8 is the maximum size that can be checked
    int y;

	/* open file and test for it being a png */
	FILE *fp = fopen(file_name, "rb");
	if (!fp)
		abort_("[read_png_file] File %s could not be opened for reading", file_name);
	fread(header, 1, 8, fp);
	if (png_sig_cmp(header, 0, 8))
		abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);


	/* initialize stuff */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	
	if (!png_ptr)
		abort_("[read_png_file] png_create_read_struct failed");

	png_image_data->info_ptr = png_create_info_struct(png_ptr);
	if (!png_image_data->info_ptr)
		abort_("[read_png_file] png_create_info_struct failed");

	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[read_png_file] Error during init_io");
	png_init_io(png_ptr, fp);

	png_set_sig_bytes(png_ptr, 8); /* 8 == sig_read ? */

	png_read_info(png_ptr, png_image_data->info_ptr);

    /* set transformations */
/*
	if ((png_image_data->info_ptr->color_type & PNG_COLOR_TYPE_RGB) == 0)
        transforms |= PNG_TRANSFORM_BGR;
*/
   if (png_get_valid(png_ptr, png_image_data->info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit;

      png_get_sBIT(png_ptr, png_image_data->info_ptr, &sig_bit);
      printf("sig_bit: %d\n", sig_bit);
      png_set_shift(png_ptr, sig_bit);
   }

    /* TODO DFG: is this needed? */
	number_of_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr, png_image_data->info_ptr);





	/* read file */
	if (setjmp(png_jmpbuf(png_ptr)))
		abort_("[read_png_file] Error during read_image");

#if 1
	png_image_data->row_pointers = (png_bytep*) qemu_malloc(sizeof(png_bytep) * png_image_data->info_ptr->height);
	for (y=0; y < png_image_data->info_ptr->height; y++)
		png_image_data->row_pointers[y] = (png_byte*) qemu_malloc(png_image_data->info_ptr->rowbytes);

	png_read_image(png_ptr, png_image_data->row_pointers);
#endif
    /* DFG TODO: Cleanup */

/*    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); */

    fclose(fp);
}
Exemple #18
0
bool Image::save (const std::string &s)
{
	// Open the file
	std::ofstream outfile;
	outfile.open(s.c_str(), std::ifstream::out | std::ifstream::binary);

	png_structp png_ptr;
	png_infop info_ptr;

	// 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 check that
	// the library version is compatible with the one used at compile time,
	// in case we are using dynamically linked libraries.  REQUIRED.
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		return false;
	}

	// Allocate/initialize the image information data. 
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		::png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		return false;
	}

	// Set error handling.  REQUIRED if you aren't supplying your own
	// error handling functions in the png_create_write_struct() call.
	if (setjmp(png_jmpbuf(png_ptr))) {
		// If we get here, we had a problem reading the file
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return false;
	}

	// Set custom write routine
	png_set_write_fn(png_ptr, &outfile, &png_write_data, &png_flush_data);

	// Set the image information here.  Width and height are up to 2^31,
    // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
    // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
    // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
    // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
    // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
    // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
	png_set_IHDR(png_ptr, info_ptr, _window_width, _window_height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	// We are dealing with a color image then
	png_color_8 sig_bit;
	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	sig_bit.alpha = 8;
	png_set_sBIT(png_ptr, info_ptr, &sig_bit);


	// Optional gamma chunk is strongly suggested if you have any guess
	// as to the correct gamma of the image.
	//
	png_set_gAMA(png_ptr, info_ptr, 0.0);

	// Write the file header information.
	png_write_info(png_ptr, info_ptr);

	// Shift the pixels up to a legal bit depth and fill in
	// as appropriate to correctly scale the image.
	png_set_shift(png_ptr, &sig_bit);

	// pack pixels into bytes
	png_set_packing(png_ptr);

	// swap location of alpha bytes from ARGB to RGBA
	//png_set_swap_alpha(png_ptr);

	// Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
	// RGB (4 channels -> 3 channels). The second parameter is not used.
	//png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);

	// flip BGR pixels to RGB 
	//png_set_bgr(png_ptr);

	// swap bytes of 16-bit files to most significant byte first
	//png_set_swap(png_ptr);

	// swap bits of 1, 2, 4 bit packed pixel formats
	//png_set_packswap(png_ptr);

	// The easiest way to write the image (you may have a different memory
	// layout, however, so choose what fits your needs best).  You need to
	// use the first method if you aren't handling interlacing yourself.

	// Setup row pointers
	png_bytep *row_pointers = new png_bytep[_window_height];

	for (png_uint_32 k = 0; k < _window_height; k++)
		row_pointers[k] = (png_bytep) &getPixel(0,k);

	png_write_image(png_ptr, row_pointers);
	
	delete row_pointers;

	// It is REQUIRED to call this to finish writing the rest of the file
	png_write_end(png_ptr, info_ptr);

	// Similarly, if you png_malloced any data that you passed in with
	// png_set_something(), such as a hist or trans array, free it here,
	// when you can be sure that libpng is through with it.
	png_free(png_ptr, NULL);

	// clean up after the write, and free any memory allocated
	png_destroy_write_struct(&png_ptr, &info_ptr);

	return false;
}
Exemple #19
0
bool KIPIWriteImage::write2PNG(const QString& destPath)
{
    /*
    check this out for b/w support:
    http://lxr.kde.org/source/playground/graphics/krita-exp/kis_png_converter.cpp#607
    */
    QFile file(destPath);

    if (!file.open(QIODevice::ReadWrite))
    {
        qDebug() << "Failed to open PNG file for writing" ;
        return false;
    }

    uchar*       data       = 0;
    int          bitsDepth  = d->sixteenBit ? 16 : 8;
    png_color_8  sig_bit;
    png_bytep    row_ptr;
    png_structp  png_ptr    = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop    info_ptr   = png_create_info_struct(png_ptr);

    png_set_write_fn(png_ptr, (void*)&file, kipi_png_write_fn, kipi_png_flush_fn);

    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)      // Intel
        png_set_bgr(png_ptr);
    else                                                    // PPC
        png_set_swap_alpha(png_ptr);

    if (d->hasAlpha)
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 8 * sizeof(uchar)];
        else
            data = new uchar[d->width * 4 * sizeof(uchar)];
    }
    else
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB,        PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 6 * sizeof(uchar)];
        else
            data = new uchar[d->width * 3 * sizeof(uchar)];
    }

    sig_bit.red   = bitsDepth;
    sig_bit.green = bitsDepth;
    sig_bit.blue  = bitsDepth;
    sig_bit.alpha = bitsDepth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_compression_level(png_ptr, 9);

    // Write Software info.
    QString libpngver(QLatin1String(PNG_HEADER_VERSION_STRING));
    libpngver.replace(QLatin1Char('\n'), QLatin1Char(' '));
    QByteArray softAscii = libpngver.toLatin1();
    png_text text;
    text.key         = (png_charp)"Software";
    text.text        = softAscii.data();
    text.compression = PNG_TEXT_COMPRESSION_zTXt;
    png_set_text(png_ptr, info_ptr, &(text), 1);

    png_write_info(png_ptr, info_ptr);
    png_set_shift(png_ptr, &sig_bit);
    png_set_packing(png_ptr);

    uchar* ptr = (uchar*)d->data.data();
    uint   x, y, j;

    for (y = 0; y < d->height; ++y)
    {
        if (cancel())
        {
            delete [] data;
            file.close();
            png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
            png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
            return false;
        }

        j = 0;

        for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth())
        {
            if (d->sixteenBit)
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                    data[j++] = ptr[x+7];  // Alpha
                    data[j++] = ptr[x+6];
                }
                else
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                }
            }
            else
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                    data[j++] = ptr[x+3];  // Alpha
                }
                else
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                }
            }
        }

        row_ptr = (png_bytep) data;

        png_write_rows(png_ptr, &row_ptr, 1);
        ptr += (d->width * bytesDepth());
    }

    delete [] data;

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
    png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
    file.close();

    return true;
}
Exemple #20
0
bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    wxPNGInfoStruct wxinfo;

    wxinfo.verbose = verbose;
    wxinfo.stream.out = &stream;

    png_structp png_ptr = png_create_write_struct
                          (
                              PNG_LIBPNG_VER_STRING,
                              NULL,
                              wx_png_error,
                              wx_png_warning
                          );
    if (!png_ptr)
    {
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    if (setjmp(wxinfo.jmpbuf))
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    // NB: please see the comment near wxPNGInfoStruct declaration for
    //     explanation why this line is mandatory
    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);

    const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT)
                           ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
                           : wxPNG_TYPE_COLOUR;
    const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
                          ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
                          : 8;

    bool bHasAlpha = image->HasAlpha();
    bool bHasMask = image->HasMask();
    bool bUseAlpha = bHasAlpha || bHasMask;

    int iPngColorType;
    if ( iColorType==wxPNG_TYPE_COLOUR )
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
                        : PNG_COLOR_TYPE_RGB;
    }
    else
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
                        : PNG_COLOR_TYPE_GRAY;
    }

    if (image->HasOption(wxIMAGE_OPTION_PNG_FILTER))
        png_set_filter( png_ptr, PNG_FILTER_TYPE_BASE, image->GetOptionInt(wxIMAGE_OPTION_PNG_FILTER) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL))
        png_set_compression_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL))
        png_set_compression_mem_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY))
        png_set_compression_strategy( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE))
        png_set_compression_buffer_size( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE) );

    png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
                  iBitDepth, iPngColorType,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                  PNG_FILTER_TYPE_BASE);

    int iElements;
    png_color_8 sig_bit;

    if ( iPngColorType & PNG_COLOR_MASK_COLOR )
    {
        sig_bit.red =
            sig_bit.green =
                sig_bit.blue = (png_byte)iBitDepth;
        iElements = 3;
    }
    else // grey
    {
        sig_bit.gray = (png_byte)iBitDepth;
        iElements = 1;
    }

    if ( iPngColorType & PNG_COLOR_MASK_ALPHA )
    {
        sig_bit.alpha = (png_byte)iBitDepth;
        iElements++;
    }

    if ( iBitDepth == 16 )
        iElements *= 2;

    // save the image resolution if we have it
    int resX, resY;
    switch ( GetResolutionFromOptions(*image, &resX, &resY) )
    {
    case wxIMAGE_RESOLUTION_INCHES:
    {
        const double INCHES_IN_METER = 10000.0 / 254;
        resX = int(resX * INCHES_IN_METER);
        resY = int(resY * INCHES_IN_METER);
    }
    break;

    case wxIMAGE_RESOLUTION_CM:
        resX *= 100;
        resY *= 100;
        break;

    case wxIMAGE_RESOLUTION_NONE:
        break;

    default:
        wxFAIL_MSG( wxT("unsupported image resolution units") );
    }

    if ( resX && resY )
        png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );

    png_set_sBIT( png_ptr, info_ptr, &sig_bit );
    png_write_info( png_ptr, info_ptr );
    png_set_shift( png_ptr, &sig_bit );
    png_set_packing( png_ptr );

    unsigned char *
    data = (unsigned char *)malloc( image->GetWidth() * iElements );
    if ( !data )
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        return false;
    }

    unsigned char *
    pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);
    int iHeight = image->GetHeight();
    int iWidth = image->GetWidth();

    unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0;

    if ( bHasMask )
    {
        uchMaskRed = image->GetMaskRed();
        uchMaskGreen = image->GetMaskGreen();
        uchMaskBlue = image->GetMaskBlue();
    }

    unsigned char *pColors = image->GetData();

    for (int y = 0; y != iHeight; ++y)
    {
        unsigned char *pData = data;
        for (int x = 0; x != iWidth; x++)
        {
            unsigned char uchRed = *pColors++;
            unsigned char uchGreen = *pColors++;
            unsigned char uchBlue = *pColors++;

            switch ( iColorType )
            {
            default:
                wxFAIL_MSG( wxT("unknown wxPNG_TYPE_XXX") );
            // fall through

            case wxPNG_TYPE_COLOUR:
                *pData++ = uchRed;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                *pData++ = uchGreen;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                *pData++ = uchBlue;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                break;

            case wxPNG_TYPE_GREY:
            {
                // where do these coefficients come from? maybe we
                // should have image options for them as well?
                unsigned uiColor =
                    (unsigned) (76.544*(unsigned)uchRed +
                                150.272*(unsigned)uchGreen +
                                36.864*(unsigned)uchBlue);

                *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
                if ( iBitDepth == 16 )
                    *pData++ = (unsigned char)(uiColor & 0xFF);
            }
            break;

            case wxPNG_TYPE_GREY_RED:
                *pData++ = uchRed;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                break;
            }

            if ( bUseAlpha )
            {
                unsigned char uchAlpha = 255;
                if ( bHasAlpha )
                    uchAlpha = *pAlpha++;

                if ( bHasMask )
                {
                    if ( (uchRed == uchMaskRed)
                            && (uchGreen == uchMaskGreen)
                            && (uchBlue == uchMaskBlue) )
                        uchAlpha = 0;
                }

                *pData++ = uchAlpha;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
            }
        }

        png_bytep row_ptr = data;
        png_write_rows( png_ptr, &row_ptr, 1 );
    }

    free(data);
    png_write_end( png_ptr, info_ptr );
    png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );

    return true;
}
Exemple #21
0
bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    wxPNGInfoStruct wxinfo;

    wxinfo.verbose = verbose;
    wxinfo.stream.out = &stream;

    png_structp png_ptr = png_create_write_struct
                          (
                            PNG_LIBPNG_VER_STRING,
                            NULL,
                            wx_PNG_error,
                            wx_PNG_warning
                          );
    if (!png_ptr)
    {
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    if (setjmp(wxinfo.jmpbuf))
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    // NB: please see the comment near wxPNGInfoStruct declaration for
    //     explanation why this line is mandatory
    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);

    const int iHeight = image->GetHeight();
    const int iWidth = image->GetWidth();

    const bool bHasPngFormatOption
        = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT);

    int iColorType = bHasPngFormatOption
                            ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
                            : wxPNG_TYPE_COLOUR;

    bool bHasAlpha = image->HasAlpha();
    bool bHasMask = image->HasMask();

    bool bUsePalette = iColorType == wxPNG_TYPE_PALETTE
#if wxUSE_PALETTE
        || (!bHasPngFormatOption && image->HasPalette() )
#endif
    ;

    png_color_8 mask = { 0, 0, 0, 0, 0 };

    if (bHasMask)
    {
        mask.red   = image->GetMaskRed();
        mask.green = image->GetMaskGreen();
        mask.blue  = image->GetMaskBlue();
    }

    PaletteMap palette;

    if (bUsePalette)
    {
        png_color png_rgb  [PNG_MAX_PALETTE_LENGTH];
        png_byte  png_trans[PNG_MAX_PALETTE_LENGTH];

        const unsigned char *pColors = image->GetData();
        const unsigned char* pAlpha  = image->GetAlpha();

        if (bHasMask && !pAlpha)
        {
            // Mask must be first
            PaletteAdd(&palette, mask);
        }

        for (int y = 0; y < iHeight; y++)
        {
            for (int x = 0; x < iWidth; x++)
            {
                png_color_8 rgba;

                rgba.red   = *pColors++;
                rgba.green = *pColors++;
                rgba.blue  = *pColors++;
                rgba.gray  = 0;
                rgba.alpha = (pAlpha && !bHasMask) ? *pAlpha++ : 0;

                // save in our palette
                long index = PaletteAdd(&palette, rgba);

                if (index < PNG_MAX_PALETTE_LENGTH)
                {
                    // save in libpng's palette
                    png_rgb[index].red   = rgba.red;
                    png_rgb[index].green = rgba.green;
                    png_rgb[index].blue  = rgba.blue;
                    png_trans[index]     = rgba.alpha;
                }
                else
                {
                    bUsePalette = false;
                    break;
                }
            }
        }

        if (bUsePalette)
        {
            png_set_PLTE(png_ptr, info_ptr, png_rgb, palette.size());

            if (bHasMask && !pAlpha)
            {
                wxASSERT(PaletteFind(palette, mask) == 0);
                png_trans[0] = 0;
                png_set_tRNS(png_ptr, info_ptr, png_trans, 1, NULL);
            }
            else if (pAlpha && !bHasMask)
            {
                png_set_tRNS(png_ptr, info_ptr, png_trans, palette.size(), NULL);
            }
        }
    }

    /*
    If saving palettised was requested but it was decided we can't use a
    palette then reset the colour type to RGB.
    */
    if (!bUsePalette && iColorType == wxPNG_TYPE_PALETTE)
    {
        iColorType = wxPNG_TYPE_COLOUR;
    }

    bool bUseAlpha = !bUsePalette && (bHasAlpha || bHasMask);

    int iPngColorType;

    if (bUsePalette)
    {
        iPngColorType = PNG_COLOR_TYPE_PALETTE;
        iColorType = wxPNG_TYPE_PALETTE;
    }
    else if ( iColorType==wxPNG_TYPE_COLOUR )
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
                                  : PNG_COLOR_TYPE_RGB;
    }
    else
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
                                  : PNG_COLOR_TYPE_GRAY;
    }

    if (image->HasOption(wxIMAGE_OPTION_PNG_FILTER))
        png_set_filter( png_ptr, PNG_FILTER_TYPE_BASE, image->GetOptionInt(wxIMAGE_OPTION_PNG_FILTER) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL))
        png_set_compression_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL))
        png_set_compression_mem_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY))
        png_set_compression_strategy( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE))
        png_set_compression_buffer_size( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE) );

    int iBitDepth = !bUsePalette && image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
                            ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
                            : 8;

    png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
                  iBitDepth, iPngColorType,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                  PNG_FILTER_TYPE_BASE);

    int iElements;
    png_color_8 sig_bit;

    if ( iPngColorType & PNG_COLOR_MASK_COLOR )
    {
        sig_bit.red =
        sig_bit.green =
        sig_bit.blue = (png_byte)iBitDepth;
        iElements = 3;
    }
    else // grey
    {
        sig_bit.gray = (png_byte)iBitDepth;
        iElements = 1;
    }

    if ( bUseAlpha )
    {
        sig_bit.alpha = (png_byte)iBitDepth;
        iElements++;
    }

    if ( iBitDepth == 16 )
        iElements *= 2;

    // save the image resolution if we have it
    int resX, resY;
    switch ( GetResolutionFromOptions(*image, &resX, &resY) )
    {
        case wxIMAGE_RESOLUTION_INCHES:
            {
                const double INCHES_IN_METER = 10000.0 / 254;
                resX = int(resX * INCHES_IN_METER);
                resY = int(resY * INCHES_IN_METER);
            }
            break;

        case wxIMAGE_RESOLUTION_CM:
            resX *= 100;
            resY *= 100;
            break;

        case wxIMAGE_RESOLUTION_NONE:
            break;

        default:
            wxFAIL_MSG( wxT("unsupported image resolution units") );
    }

    if ( resX && resY )
        png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );

    png_set_sBIT( png_ptr, info_ptr, &sig_bit );
    png_write_info( png_ptr, info_ptr );
    png_set_shift( png_ptr, &sig_bit );
    png_set_packing( png_ptr );

    unsigned char *
        data = (unsigned char *)malloc( image->GetWidth() * iElements );
    if ( !data )
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        return false;
    }

    const unsigned char *
        pAlpha = (const unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);

    const unsigned char *pColors = image->GetData();

    for (int y = 0; y != iHeight; ++y)
    {
        unsigned char *pData = data;
        for (int x = 0; x != iWidth; x++)
        {
            png_color_8 clr;
            clr.red   = *pColors++;
            clr.green = *pColors++;
            clr.blue  = *pColors++;
            clr.gray  = 0;
            clr.alpha = (bUsePalette && pAlpha) ? *pAlpha++ : 0; // use with wxPNG_TYPE_PALETTE only

            switch ( iColorType )
            {
                default:
                    wxFAIL_MSG( wxT("unknown wxPNG_TYPE_XXX") );
                    // fall through

                case wxPNG_TYPE_COLOUR:
                    *pData++ = clr.red;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    *pData++ = clr.green;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    *pData++ = clr.blue;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    break;

                case wxPNG_TYPE_GREY:
                    {
                        // where do these coefficients come from? maybe we
                        // should have image options for them as well?
                        unsigned uiColor =
                            (unsigned) (76.544*(unsigned)clr.red +
                                        150.272*(unsigned)clr.green +
                                        36.864*(unsigned)clr.blue);

                        *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
                        if ( iBitDepth == 16 )
                            *pData++ = (unsigned char)(uiColor & 0xFF);
                    }
                    break;

                case wxPNG_TYPE_GREY_RED:
                    *pData++ = clr.red;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    break;

                case wxPNG_TYPE_PALETTE:
                    *pData++ = (unsigned char) PaletteFind(palette, clr);
                    break;
            }

            if ( bUseAlpha )
            {
                unsigned char uchAlpha = 255;
                if ( bHasAlpha )
                    uchAlpha = *pAlpha++;

                if ( bHasMask )
                {
                    if ( (clr.red == mask.red)
                            && (clr.green == mask.green)
                                && (clr.blue == mask.blue) )
                        uchAlpha = 0;
                }

                *pData++ = uchAlpha;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
            }
        }

        png_bytep row_ptr = data;
        png_write_rows( png_ptr, &row_ptr, 1 );
    }

    free(data);
    png_write_end( png_ptr, info_ptr );
    png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );

    return true;
}
Exemple #22
0
bool8 S9xDoScreenshot(int width, int height){
#ifdef HAVE_LIBPNG
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_color_8 sig_bit;
    png_color pngpal[256];
    int imgwidth;
    int imgheight;
    const char *fname=S9xGetFilename( FILE_SCREENSHOT );
    
#if 0
    Settings.TakeScreenshot=FALSE;
#endif

    if((fp=fopen(fname, "wb"))==NULL){
        perror("Screenshot failed");
        return FALSE;
    }

    png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png_ptr){
        fclose(fp);
        unlink(fname);
        return FALSE;
    }
    info_ptr=png_create_info_struct(png_ptr);
    if(!info_ptr){
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        fclose(fp);
        unlink(fname);
        return FALSE;
    }

    if(setjmp(png_jmpbuf(png_ptr))){
        perror("Screenshot: setjmp");
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
        unlink(fname);
        return FALSE;
    }

    imgwidth=width;
    imgheight=height;
#if 0
    if(Settings.StretchScreenshots==1){
        if(width<=256 && height>SNES_HEIGHT_EXTENDED) imgwidth=width<<1;
        if(width>256 && height<=SNES_HEIGHT_EXTENDED) imgheight=height<<1;
    } else if(Settings.StretchScreenshots==2){
#endif
        if(width<=256) imgwidth=width<<1;
        if(height<=SNES_HEIGHT_EXTENDED) imgheight=height<<1;
#if 0
    }
#endif
    
    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);

    /* 5 bits per color */
    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)];
    uint8 *screen=GFX.Screen;
    for(int y=0; y<height; y++, screen+=GFX.Pitch){
        png_byte *rowpix = row_pointer;
        for(int x=0; x<width; x++){
                uint32 r, g, b;
                DECOMPOSE_PIXEL((*(uint16 *)(screen+2*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);
    return TRUE;
#else
    perror("Screenshot support not available (libpng was not found at build time)");
	return FALSE;
#endif
}
/* pngReadImage: Reads an image from a memory buffer.
   Returns: non-zero if successful.
*/
int pngReadImage(int w, int h, int d, char* bits, char *data, int nBytes) {
  png_bytep *row_pointers = NULL;
  pngReadState rs;
  png_structp png_ptr;
  png_infop info_ptr;
  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;

  DBG("pngReadImage: png_sig_cmp");
  /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. */
  if(png_sig_cmp(data, (png_size_t)0, PNG_BYTES_TO_CHECK)) return 0;

  DBG("pngReadImage: png_create_read_struct");
  /* Create the png_struct */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) return 0;

  DBG("pngReadImage: png_create_info_struct");
  /* Allocate/initialize the image information data.  REQUIRED */
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
    return 0;
  }

  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_read_struct() call.
   */
  if (setjmp(png_jmpbuf(png_ptr))) {
    DBG("pngReadImage: triggered png_error");
    /* If we get here, we had a problem reading the file */
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
    if(row_pointers) free(row_pointers);
    return 0;
  }
  rs.data = data;
  rs.position = 0;
  rs.length = nBytes;
  png_set_read_fn(png_ptr, (void *)&rs, readBytes);


  DBG("pngReadImage: png_read_info");
  /* The call to png_read_info() gives us all of the information from the
   * PNG file before the first IDAT (image data chunk).  REQUIRED
   */
  png_read_info(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
	       &interlace_type, int_p_NULL, int_p_NULL);

  /* Set up the data transformations you want.  Note that these are all
   * optional.  Only call them if you want/need them.  Many of the
   * transformations only work on specific types of images, and many
   * are mutually exclusive.
   */

  /* tell libpng to strip 16 bit/color files down to 8 bits/color */
  png_set_strip_16(png_ptr);

   /* flip the RGB pixels to BGR (or RGBA to BGRA) */
  if (color_type & PNG_COLOR_MASK_COLOR) {
    DBG("pngReadImage: png_set_bgr");
    png_set_bgr(png_ptr);
  }

  if(d == 32 && color_type == PNG_COLOR_TYPE_RGB) {
    /* Add filler (or alpha) byte (before/after each RGB triplet) */
    DBG("pngReadImage: png_set_filler");
    png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
  }

  if(0) {
    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
     * byte into separate bytes (useful for paletted and grayscale images).
     */
    png_set_packing(png_ptr);
    
    /* Change the order of packed pixels to least significant bit first
     * (not useful if you are using png_set_packing). */
    png_set_packswap(png_ptr);

    /* Expand paletted colors into true RGB triplets */
    if (color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_palette_to_rgb(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);

  /* Expand paletted or RGB images with transparency to full alpha channels
   * so the data will be available as RGBA quartets.
   */
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(png_ptr);


  if(0) {
    /* Set the background color to draw transparent and alpha images over.
     * It is possible to set the red, green, and blue components directly
     * for paletted images instead of supplying a palette index.  Note that
     * even if the PNG file supplies a background, you are not required to
     * use it - you should use the (solid) application background if it has one
     */

    png_color_16 my_background, *image_background;
  
    if (png_get_bKGD(png_ptr, info_ptr, &image_background))
      png_set_background(png_ptr, image_background,
			 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
    else
      png_set_background(png_ptr, &my_background,
			 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
  }

  if(0) {
   /* Tell libpng to handle the gamma conversion for you.  The final call
    * is a good guess for PC generated images, but it should be configurable
    * by the user at run time by the user.  It is strongly suggested that
    * your application support gamma correction.
    */

    int intent;
    double screen_gamma = 1.2;

    if (png_get_sRGB(png_ptr, info_ptr, &intent))
      png_set_gamma(png_ptr, screen_gamma, 0.45455);
    else {
      double image_gamma;
      if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
	png_set_gamma(png_ptr, screen_gamma, image_gamma);
      else
	png_set_gamma(png_ptr, screen_gamma, 0.45455);
    }
  }

  if(0) {
    /* 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 (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);
    }
  }

  if(0) {
    /* flip the RGB pixels to BGR (or RGBA to BGRA) */
    if (color_type & PNG_COLOR_MASK_COLOR)
      png_set_bgr(png_ptr);
    
    /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
    png_set_swap_alpha(png_ptr);
    
    /* swap bytes of 16 bit files to least significant byte first */
    png_set_swap(png_ptr);
  }

  { /* initialize the png row pointers */
    int row, ppw = 32 / d;
    int pitch = ((w + ppw - 1) / ppw) * 4;
    int rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    if(0) {
      char info[100];
      sprintf(info, "Form pitch: %d\nPNG rowbytes: %d",pitch, rowbytes);
      DBG(info);
    }

    /* XXXX: It seems that this test is pretty pointless; PNG appears
       to return the raw rowbytes value, not the padded one.
       A better test is probably to compare the w/h/d values
       of png with the form values to ensure correctness. */
    if(pitch < rowbytes) {
      png_error(png_ptr, "Row bytes mismatch");
    }
    row_pointers = (png_bytep*) calloc(h, sizeof(void*));
    for (row = 0; row < h; row++) {
      row_pointers[row] = bits + (row*pitch);
    }
  }

  DBG("pngReadImage: png_read_image");
  /* Read the entire image in one go */
  png_read_image(png_ptr, row_pointers);

  DBG("pngReadImage: Cleaning up");
  /* clean up after the read, and free any memory allocated - REQUIRED */
  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);

  if(row_pointers) free(row_pointers);

  return 1;
}
Exemple #24
0
/* read a png file.  You may want to return an error code if the read
   fails (depending upon the failure). */
void read_png(char *file_name)
{
   FILE *fp;
   png_structp png_ptr;
   png_infop info_ptr;

   /* open the file */
   fp = fopen(file_name, "rb");
   if (!fp)
      return;

   /* 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 check that
      the header file is compatible with the library version.
    */
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
      (void *)user_error_ptr, user_error_fn, user_warning_fn);

   if (!png_ptr)
   {
      fclose(fp);
      return;
   }

   info_ptr = png_create_info_struct();
   if (!info_ptr)
   {
      fclose(fp);
      png_destroy_read_struct(&png_ptr,  (png_infopp)NULL, (png_infopp)NULL);
      return;
   }

   /* set error handling if you are using the setjmp/longjmp method */
   if (setjmp(png_ptr->jmpbuf))
   {
      /* Free all of the memory associated with the png_ptr and info_ptr */
      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
      fclose(fp);
      /* If we get here, we had a problem reading the file */
      return;
   }

   /* set up the input control if you are using standard C streams */
   png_init_io(png_ptr, fp);

   /* if you are using replacement read functions, instead of calling
      png_init_io() here you would call */
   png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
   /* where user_io_ptr is a structure you want available to the callbacks */

   /* read the file information */
   png_read_info(png_ptr, info_ptr);

   /* set up the transformations you want.  Note that these are
      all optional.  Only call them if you want them */

   /* expand paletted colors into true RGB triplets */
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_expand(png_ptr);

   /* expand grayscale images to the full 8 bits */
   if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8)
      png_set_expand(png_ptr);

   /* expand paletted or RGB images with transparency to full alpha channels
    * so the data will be available as RGBA quartets */
   if (info_ptr->valid & PNG_INFO_tRNS)
      png_set_expand(png_ptr);

   /* Set the background color to draw transparent and alpha
      images over.  It is possible to set the red, green, and blue
      components directly for paletted images. */

   png_color_16 my_background;

   if (info_ptr->valid & PNG_INFO_bKGD)
      png_set_background(png_ptr, &(info_ptr->background),
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
   else
      png_set_background(png_ptr, &my_background,
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

   /* tell libpng to handle the gamma conversion for you */
   if (info_ptr->valid & PNG_INFO_gAMA)
      png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma);
   else
      png_set_gamma(png_ptr, screen_gamma, 0.45);

   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   if (info_ptr->bit_depth == 16)
      png_set_strip_16(png_ptr);

   /* dither rgb files down to 8 bit palette & reduce palettes
      to the number of colors available on your screen */
   if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
   {
      if (info_ptr->valid & PNG_INFO_PLTE)
         png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette,
                        max_screen_colors, info_ptr->histogram);
      else
      {
         png_color std_color_cube[MAX_SCREEN_COLORS] =
            {/* ... colors ... */};

         png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
            MAX_SCREEN_COLORS, NULL);
      }
   }

   /* invert monocrome files to have 0 as white and 1 as black */
   if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY)
      png_set_invert(png_ptr);

   /* shift the pixels down to their true bit depth */
   if (info_ptr->valid & PNG_INFO_sBIT &&
      info_ptr->bit_depth > info_ptr->sig_bit)
      png_set_shift(png_ptr, &(info_ptr->sig_bit));

   /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes
      (useful only for paletted and grayscale images) */
   if (info_ptr->bit_depth < 8)
      png_set_packing(png_ptr);

   /* flip the rgb pixels to bgr */
   if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
      info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
      png_set_bgr(png_ptr);

   /* swap bytes of 16 bit files to least significant bit first */
   if (info_ptr->bit_depth == 16)
      png_set_swap(png_ptr);

   /* add a filler byte to RGB files (before or after each RGB triplet) */
   if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB)
      png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);

   /* turn on interlace handling if you are not using png_read_image() */
   number_passes = png_set_interlace_handling(png_ptr);

   /* optional call to gamma correct and add the background to the palette
      and update info structure. */
   png_read_update_info(png_ptr, info_ptr);

   /* allocate the memory to hold the image using the fields
      of png_info. */

   /* the easiest way to read the image */
   png_bytep row_pointers[height];

   for (row = 0; row < height; row++)
   {
     row_pointers[row] = malloc(info_ptr->rowbytes);
   }

   png_read_image(png_ptr, row_pointers);

   /* the other way to read images - deal with interlacing */

   for (pass = 0; pass < number_passes; pass++)
   {
      /* Read the image using the "sparkle" effect. */
      png_read_rows(png_ptr, row_pointers, NULL, number_of_rows);

      /* If you are only reading on row at a time, this works */
      for (y = 0; y < height; y++)
      {
         png_bytep row_pointers = row[y];
         png_read_rows(png_ptr, &row_pointers, NULL, 1);
      }

      /* to get the rectangle effect, use the third parameter */
      png_read_rows(png_ptr, NULL, row_pointers, number_of_rows);

      /* if you want to display the image after every pass, do
         so here */
   }

   /* read the rest of the file, getting any additional chunks in info_ptr */
   png_read_end(png_ptr, info_ptr);

   /* clean up after the read, and free any memory allocated */
   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

   /* close the file */
   fclose(fp);

   /* that's it */
   return;
}
Exemple #25
0
RADRT_API bool RADRT_CALL Encode(const Image &in, const Mipmap &mip, bool interlaced, void *&outData, AddrSize &outSize)
{
	RAD_ASSERT(in.format == Format_A8 || in.format == Format_RGB888 || in.format == Format_RGBA8888);

	if (in.format != Format_A8 &&
		in.format != Format_RGB888 &&
		in.format != Format_RGBA8888) return false;

	png_structp png;
	png_infop   info;

	png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0,
		PNGMalloc, PNGFree);

	if (!png) return false;

	info = png_create_info_struct(png);

	if (!info)
	{
		png_destroy_write_struct(&png, 0);
		return false;
	}

	stream::DynamicMemOutputBuffer ob(ZImageCodec);
	stream::OutputStream os(ob);

	png_set_write_fn(png, &os, PNGWrite, PNGFlush);
	png_set_IHDR(png, info, mip.width, mip.height, 8,
		(in.format == Format_A8) ? PNG_COLOR_TYPE_GRAY :
		(in.format == Format_RGB888) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
		interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_color_8 sig;
	memset(&sig, 0, sizeof(sig));
	
	if (in.format == Format_A8)
	{
		sig.gray = 8;
	}
	else
	{
		sig.red = 8;
		sig.green = 8;
		sig.blue = 8;
		sig.alpha = (in.format == Format_RGBA8888) ? 8 : 0;
	}

	png_set_sBIT(png, info, &sig);

	try
	{
		png_write_info(png, info);
	}
	catch (PNGException&)
	{
		png_destroy_write_struct(&png, &info);
		return false;
	}

	png_set_shift(png, &sig);

	int passes = 1;

	if (interlaced)
	{
		passes = png_set_interlace_handling(png);
	}

	for (int pass = 0; pass < passes; ++pass)
	{
		png_bytep src = (png_bytep)mip.data;

		for (int y = 0; y < mip.height; ++y)
		{
			png_write_rows(png, (png_bytepp)&src, 1);
			src += mip.stride;
		}
	}

	png_write_end(png, info);
	png_destroy_write_struct(&png, &info);

	outData = ob.OutputBuffer().Ptr();
	outSize = ob.OutputBuffer().Size();
	ob.OutputBuffer().Set(0, 0); // don't let the output buffer release the memory.

	return true;

}
Exemple #26
0
PyObject*
_png_module::_read_png(const Py::Object& py_fileobj, const bool float_result,
                       int result_bit_depth)
{
    png_byte header[8];   // 8 is the maximum size that can be checked
    FILE* fp = NULL;
    bool close_file = false;
    bool close_dup_file = false;
    PyObject *py_file = NULL;

    if (py_fileobj.isString())
    {
        if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"rb")) == NULL) {
            throw Py::Exception();
        }
        close_file = true;
    } else {
        py_file = py_fileobj.ptr();
    }

    if ((fp = npy_PyFile_Dup(py_file, "rb")))
    {
        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);
            throw Py::TypeError(
                "Object does not appear to be a 8-bit string path or a Python "
                "file-like object");
        }
        Py_XDECREF(read_method);
    }

    if (fp)
    {
        if (fread(header, 1, 8, fp) != 8)
        {
            throw Py::RuntimeError(
                "_image_module::readpng: error reading PNG header");
        }
    }
    else
    {
        _read_png_data(py_file, header, 8);
    }
    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");
    }

    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);

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

    int 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);

    /* 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 (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
    }
    //For gray, return an x by y array, not an x by y by 1
    int num_dims  = (png_get_color_type(png_ptr, info_ptr)
                                & PNG_COLOR_MASK_COLOR) ? 3 : 2;

    PyArrayObject *A = NULL;
    if (float_result) {
        double max_value = (1 << bit_depth) - 1;

        A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_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 < (png_uint_32)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 < (png_uint_32)dimensions[2]; p++)
                    {
                        *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                    }
                }
            }
        }
    } else {
        if (result_bit_depth < 0) {
            result_bit_depth = bit_depth;
        }

        if (result_bit_depth == 8) {
            A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE);
        } else if (result_bit_depth == 16) {
            A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UINT16);
        } else {
            throw Py::RuntimeError(
                "_image_module::readpng: image has unknown bit depth");
        }

        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]];

                    if (result_bit_depth == 16) {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p];
                        }
                    } else {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p] >> 8;
                        }
                    }
                }
                else
                {
                    png_byte* ptr = &(row[x * dimensions[2]]);
                    if (result_bit_depth == 16) {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p];
                        }
                    } else {
                        for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                        {
                            *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p];
                        }
                    }
                }
            }
        }
Exemple #27
0
int read_PNG(char *file_name)
{
    /*
     * Took this code from doc/fblib
     * and adjusted it to the likings
     * of this program.
     * ?i
     * It is really awesome that a NOOB
     * like me, Noisegate can actually
     * make useable software on an open
     * system like this Linux...
     *
     * openSOFtWARE rocKS
     */

    png_structp png_ptr;
    png_infop info_ptr;
    unsigned int sig_read = 0;
    png_uint_32 _width, _height, row;
    int bit_depth, color_type, interlace_type;
    FILE *fp;

    float screen_gamma;

    if ((fp = fopen(file_name, "rb")) == NULL)
          return -1;

    /* 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.  REQUIRED
     */
    //png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 
            (png_voidp)NULL, 
            (png_error_ptr)NULL, 
            (png_error_ptr)NULL);

    if (png_ptr == NULL){
        fclose(fp);
        return -1;
    }

    /* Allocate/initialize the memory for image information.  REQUIRED. */
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return -1;
    }

    /* 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))) {
        /* Free all of the memory associated with the png_ptr and info_ptr */
        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
        fclose(fp);
        /* If we get here, we had a problem reading the file */
        fprintf(stderr, "Error: Couldn't read the file.");
        return -1;
    }

    /* One of the following I/O initialization methods is REQUIRED */
    /* Set up the input control if you are using standard C streams */
    png_init_io(png_ptr, fp);

    /* If we have already read some of the signature */
    png_set_sig_bytes(png_ptr, sig_read);

   /* OK, you're doing it the hard way, with the lower-level functions */

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

   png_get_IHDR(png_ptr, info_ptr, &_width, &_height, &bit_depth, &color_type,
       &interlace_type, int_p_NULL, int_p_NULL);

   /* Set up the data transformations you want.  Note that these are all
    * optional.  Only call them if you want/need them.  Many of the
    * transformations only work on specific types of images, and many
    * are mutually exclusive.
    */

   /* Tell libpng to strip 16 bit/color files down to 8 bits/color */
   png_set_strip_16(png_ptr);

   /* Strip alpha bytes from the input data without combining with the
    * background (not recommended).
    */
   //png_set_strip_alpha(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).
    */
   png_set_packing(png_ptr);

   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing). */
   png_set_packswap(png_ptr);

   /* Expand paletted colors into true RGB triplets */
   if (color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_palette_to_rgb(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_expand_gray_1_2_4_to_8(png_ptr);

   /* Expand paletted or RGB images with transparency to full alpha channels
    * so the data will be available as RGBA quartets.
    */
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
      png_set_tRNS_to_alpha(png_ptr);

   /* Set the background color to draw transparent and alpha images over.
    * It is possible to set the red, green, and blue components directly
    * for paletted images instead of supplying a palette index.  Note that
    * even if the PNG file supplies a background, you are not required to
    * use it - you should use the (solid) application background if it has one.
    */

   png_color_16 my_background, *image_background;

   if (png_get_bKGD(png_ptr, info_ptr, &image_background))
      png_set_background(png_ptr, image_background,
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
   else
      png_set_background(png_ptr, &my_background,
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);


   screen_gamma = 1.0;

   int intent;

   if (png_get_sRGB(png_ptr, info_ptr, &intent))
      png_set_gamma(png_ptr, screen_gamma, 0.45455);
   else
   {
      double image_gamma;
      if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
         png_set_gamma(png_ptr, screen_gamma, image_gamma);
      else
         png_set_gamma(png_ptr, screen_gamma, 0.45455);
   }

   /* Invert monochrome files to have 0 as white and 1 as black */
   png_set_invert_mono(png_ptr);

   /* 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 (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit_p;

      png_get_sBIT(png_ptr, info_ptr, &sig_bit_p);
      png_set_shift(png_ptr, sig_bit_p);
   }

   /* Flip the RGB pixels to BGR (or RGBA to BGRA) */
   if (color_type & PNG_COLOR_MASK_COLOR)
      png_set_bgr(png_ptr);

   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
   png_set_swap_alpha(png_ptr);

   /* Swap bytes of 16 bit files to least significant byte first */
   png_set_swap(png_ptr);

   /* Add filler (or alpha) byte (before/after each RGB triplet) */
   png_set_filler(png_ptr, 0x00, PNG_FILLER_AFTER);

   /* Turn on interlace handling.  REQUIRED if you are not using
    * png_read_image().  To see how to handle interlacing passes,
    * see the png_read_row() method below:
    */
   //number_passes = png_set_interlace_handling(png_ptr);

   /* 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 (ie you selected such a transform above).
    */
   png_read_update_info(png_ptr, info_ptr);

   /* Allocate the memory to hold the image using the fields of info_ptr. */

   /* The easiest way to read the image: */
   png_bytep row_pointers[_height];

   /* Clear the pointer array */
   for (row = 0; row < _height; row++)
      row_pointers[row] = NULL;

   for (row = 0; row < _height; row++)
      row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
         info_ptr));

   /* Now it's time to read the image.  One of these methods is REQUIRED */
   png_read_image(png_ptr, row_pointers);


   /* Now mess this rowpointer thing into the tmp_buf
    * U dont know if width>_width and height>_height
    * so we trunc the guy
    */
    
   int maxY = _height>height?height:_height;
   int maxX = _width>width?finfo.line_length:_width;
   int pix_offset=0;

   for (row=0; row<maxY;row++){
       pix_offset = Ox*BPP + ((Oy+row)*finfo.line_length);
       memcpy(tmp_buf+pix_offset, row_pointers[row], maxX*BPP);
   }

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

   /* At this point you have read the entire image */

   /* Clean up after the read, and free any memory allocated - REQUIRED */
   png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);

   /* Close the file */
   fclose(fp);


   //printf("png W x H = %i x %i\n", _width, _height);
   /* That's it */
    return 0;
}
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
                           int transforms,
                           voidp params)
{
   int row;

   if (png_ptr == NULL)
      return;

   /* 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);
   if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
      png_error(png_ptr, "Image is too high to process with png_read_png()");

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

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

#ifdef 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, or 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

#ifdef 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

#ifdef 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 quantizing.
    */

#ifdef 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

#ifdef 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

#ifdef 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

#ifdef 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

#ifdef 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

/* Added at libpng-1.2.41 */
#ifdef 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

/* Added at libpng-1.2.41 */
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
   /* Expand grayscale image to RGB
    */
   if (transforms & PNG_TRANSFORM_GRAY_TO_RGB)
       png_set_gray_to_rgb(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 ------------------- */

   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
   if (info_ptr->row_pointers == NULL)
   {
    png_uint_32 iptr;

      info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
         info_ptr->height * png_sizeof(png_bytep));
      for (iptr=0; iptr<info_ptr->height; iptr++)
         info_ptr->row_pointers[iptr] = NULL;

      info_ptr->free_me |= PNG_FREE_ROWS;

      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);

   transforms = transforms; /* Quiet compiler warnings */
   params = params;

}
Exemple #29
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);
}