/**
 * @brief internal function used to write a byte array as a PNG file
 *
 * The PNG file is written as a 8bit image file, interlaced,
 * truecolor. Depending on the number of channels, the color model is
 * gray, gray+alpha, rgb, rgb+alpha.
 *
 * @todo handle 16bit
 *
 * @param fname PNG file name, "-" means stdout
 * @param data deinterlaced (RRR..GGG..BBB..AAA) image byte array
 * @param nx, ny, nc number of columns, lines and channels
 * @param dtype identifier for the data type to be used for output
 * @return 0 if everything OK, -1 if an error occured
 */
static int write_png_raw(const char *fname, const void *data,
                         size_t nx, size_t ny, size_t nc, int dtype)
{
    png_structp png_ptr;
    png_infop info_ptr;
    png_byte *idata = NULL, *idata_ptr = NULL;
    png_bytep *row_pointers = NULL;
    png_byte bit_depth;
    /* volatile : because of setjmp/longjmp */
    FILE *volatile fp;
    const unsigned char *data_u8 = NULL;
    const unsigned char *data_u8_ptr = NULL;
    const float *data_f32 = NULL;
    const float *data_f32_ptr = NULL;
    float tmp;
    int color_type, interlace, compression, filter;
    size_t size;
    size_t i, j, k;

    /* parameters check */
    if (0 >= nx || 0 >= ny || 0 >= nc)
        return -1;
    if (NULL == fname || NULL == data)
        return -1;
    if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
        return -1;

    /* open the PNG output file */
    if (0 == strcmp(fname, "-"))
        fp = stdout;
    else if (NULL == (fp = fopen(fname, "wb")))
        return -1;

    /* allocate the interlaced array and row pointers */
    size = nx * ny * nc;
    if (NULL == (idata = (png_byte *) malloc(size * sizeof(png_byte))))
        return write_png_abort(fp, NULL, NULL, NULL, NULL);

    if (NULL == (row_pointers = (png_bytep *) malloc(ny * sizeof(png_bytep))))
        return write_png_abort(fp, idata, NULL, NULL, NULL);

    /*
     * create and initialize the png_struct
     * with the default stderr and error handling
     */
    if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                   NULL, NULL, NULL)))
        return write_png_abort(fp, idata, row_pointers, NULL, NULL);

    /* allocate/initialize the memory for image information */
    if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
        return write_png_abort(fp, idata, row_pointers, &png_ptr, NULL);

    /* set error handling */
    if (0 != setjmp(png_jmpbuf(png_ptr)))
        /* if we get here, we had a problem reading the file */
        return write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);

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

    /* set image informations */
    bit_depth = 8;
    switch (nc)
    {
    case 1:
        color_type = PNG_COLOR_TYPE_GRAY;
        break;
    case 2:
        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
        break;
    case 3:
        color_type = PNG_COLOR_TYPE_RGB;
        break;
    case 4:
        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
        break;
    default:
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        free(row_pointers);
        free(idata);
        (void) fclose(fp);
        return -1;
    }
    interlace = PNG_INTERLACE_ADAM7;
    compression = PNG_COMPRESSION_TYPE_BASE;
    filter = PNG_FILTER_TYPE_BASE;

    /* set image header */
    png_set_IHDR(png_ptr, info_ptr, (png_uint_32) nx, (png_uint_32) ny,
                 bit_depth, color_type, interlace, compression, filter);
    /* TODO : significant bit (sBIT), gamma (gAMA), comments (text) chunks */
    png_write_info(png_ptr, info_ptr);

    /*
     * interlace and convert RRR GGG BBB to RGB RGB RGB
     * the image is interlaced layer after layer
     * this involves more memory exchange, but allows a generic loop
     */
    switch (dtype)
    {
    case IO_PNG_U8:
        data_u8 = (unsigned char *) data;
        for (k = 0; k < nc; k++)
        {
            /* channel loop */
            data_u8_ptr = data_u8 + (size_t) (nx * ny * k);
            idata_ptr = idata + (size_t) k;
            for (j = 0; j < ny; j++)
            {
                /* row loop */
                for (i = 0; i < nx; i++)
                {
                    /* pixel loop */
                    *idata_ptr = (png_byte) * data_u8_ptr++;
                    idata_ptr += nc;
                }
            }
        }
        break;
    case IO_PNG_F32:
        data_f32 = (float *) data;
        for (k = 0; k < nc; k++)
        {
            /* channel loop */
            data_f32_ptr = data_f32 + (size_t) (nx * ny * k);
            idata_ptr = idata + (size_t) k;
            for (j = 0; j < ny; j++)
            {
                /* row loop */
                for (i = 0; i < nx; i++)
                {
                    /* pixel loop */
                    tmp = floor(*data_f32_ptr++ + .5);
                    *idata_ptr = (png_byte) (tmp < 0. ? 0. :
                                             (tmp > 255. ? 255. : tmp));
                    idata_ptr += nc;
                }
            }
        }
        break;
    }

    /* set row pointers */
    for (j = 0; j < ny; j++)
        row_pointers[j] = idata + (size_t) (nc * nx * j);

    /* write out the entire image and end it */
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, info_ptr);

    /* clean up and free any memory allocated, close the file */
    (void) write_png_abort(fp, idata, row_pointers, &png_ptr, &info_ptr);

    return 0;
}
Beispiel #2
0
void save(void)
{
	char file[MAX_PATH];
	strcpy(file,firstFile);

	char* p = strrchr(file,'\\');
	if (p == 0)
		p = file;
	else
		p++;
	char* x = strrchr(p,'.');
	if (x == 0)
		x = p+strlen(p);
	strcpy(x,".png");

	OPENFILENAME ofn;
	ZeroMemory(&ofn, sizeof ofn);
	ofn.lStructSize = sizeof ofn;
	ofn.hwndOwner = wnd;
	ofn.lpstrFilter = "PNG Image Files (*.png)\0*.png\0All Files (*.*)\0*.*\0";
	ofn.lpstrFile = file;
	ofn.nMaxFile = sizeof file;
	ofn.lpstrTitle = "Save as a PNG Image";
	ofn.Flags = OFN_ENABLEHOOK|OFN_ENABLESIZING|OFN_EXPLORER|OFN_HIDEREADONLY;
	ofn.lpfnHook = fileDialogProc;
	prepareOFN(&ofn);

	if (GetSaveFileName(&ofn))
	{
		FILE* f = fopen(file,"wb");
		if (f == 0)
			fatal("Could not open ouput PNG file");

		png_structp pngp = png_create_write_struct
			(PNG_LIBPNG_VER_STRING,(png_voidp)0,0,0);
		if (pngp == 0)
			fatal("Could not create PNG write structure");
		png_infop infop = png_create_info_struct(pngp);
		if (infop == 0)
			fatal("Could not create PNG info structure");

		if (setjmp(png_jmpbuf(pngp)))
			fatal("Could not write PNG file");

		png_init_io(pngp,f);
		png_set_IHDR(pngp,infop,width,height,8,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
		png_set_bgr(pngp);

		png_bytep* rows = (png_bytep*)malloc(sizeof(png_bytep)*height);
		for (int y = 0; y < height; y++)
			rows[y] = bits+(3*y*width);
		png_set_rows(pngp,infop,rows);

		png_write_png(pngp,infop,PNG_TRANSFORM_IDENTITY,0);

		free(rows);
		png_destroy_write_struct(&pngp,&infop);
		fclose(f);
	}
}
Beispiel #3
0
static int savePNGto(FILE *fp, gPixmap *pixmap)
{
	gUnmanagedSurface *surface = pixmap->surface;
	if (!surface)
		return -2;

	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (!png_ptr)
	{
		eDebug("[ePNG] couldn't allocate write struct");
		return -2;
	}
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		eDebug("[ePNG] failed to allocate info struct");
		png_destroy_write_struct(&png_ptr, 0);
		return -3;
	}

	png_set_IHDR(png_ptr, info_ptr, surface->x, surface->y, surface->bpp/surface->bypp,
		PNG_COLOR_TYPE_RGB_ALPHA,
		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		eDebug("[ePNG] png setjump failed or activated");
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return -4;
	}
	png_init_io(png_ptr, fp);
	png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
	png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);

	png_write_info(png_ptr, info_ptr);
	png_set_packing(png_ptr);

	png_byte *row_pointer;
	png_byte *cr = new png_byte[surface->y * surface->stride];
	if (cr == NULL)
	{
		eDebug("[ePNG] failed to allocate memory image");
		return -5;
	}
	for (int i = 0; i < surface->y; ++i)
	{
		row_pointer = ((png_byte*)surface->data) + i * surface->stride;
		if (surface->bypp == 4)
		{
			memcpy(cr, row_pointer, surface->stride);
			for (int j = 0; j < surface->stride; j += 4)
			{
				unsigned char tmp = cr[j];
				cr[j] = cr[j+2];
				cr[j+2] = tmp;
			}
			png_write_row(png_ptr, cr);
		}
		else
			png_write_row(png_ptr, row_pointer);
	}
	delete [] cr;

	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);
	return 0;
}
Beispiel #4
0
/* Read a PNG image file from "fname", using routines from libpng.
 * Returns 0 on success, or negative on various failures:
 *   -2: File is not PNG, or file is corrupt
 *   -3: Can't malloc a big enough image buffer
 *   -4: PNG image data is neither grayscale nor RGB (unsupported format)
 */
int ReadPNG(const char *fname, unsigned char (**data)[3], int *w, int *h)
{
    FILE *fp = fopen(fname, "rb");
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_infop end_info = NULL;
    int transforms = PNG_TRANSFORM_STRIP_16
                   | PNG_TRANSFORM_STRIP_ALPHA
                   | PNG_TRANSFORM_PACKING
                   | PNG_TRANSFORM_PACKSWAP
                   | PNG_TRANSFORM_EXPAND
                   | PNG_TRANSFORM_SHIFT;
    int channels;
    int bytes;
    png_bytepp row_pointers = NULL;
    int rc = 0;

    if (fp == NULL)
      return -1;

    (*data) = NULL;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    if (png_ptr == NULL) goto err_nomem;

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) goto err_nomem;

    end_info = png_create_info_struct(png_ptr);
    if (end_info == NULL) goto err_nomem;

    if (setjmp(png_jmpbuf(png_ptr))) goto err_corrupt;
    png_init_io(png_ptr, fp);
    png_read_png(png_ptr, info_ptr, transforms, NULL);

    *w = png_get_image_width(png_ptr, info_ptr);
    *h = png_get_image_height(png_ptr, info_ptr);
    channels = png_get_channels(png_ptr, info_ptr);
    bytes = png_get_rowbytes(png_ptr, info_ptr);

    if (bytes != channels*(*w))
      goto err_unsupported;

    row_pointers = png_get_rows(png_ptr, info_ptr);
    if (row_pointers == NULL) goto err_nomem;

    (*data) = malloc(*w * *h * sizeof **data);
    if (*data == NULL) goto err_nomem;

    if (channels == 1) {
        int j;
        for (j=0; j < *h; ++j) {
            int i;
            unsigned char (*imrow)[3] = (*data) + j*(*w);
            for (i=0; i < *w; ++i)
              memset(imrow[i], row_pointers[j][i], 3);
        }
    }
    else if (channels == 3) {
        int j;
        for (j=0; j < *h; ++j) {
            unsigned char (*imrow)[3] = (*data) + j*(*w);
            memcpy(imrow, row_pointers[j], 3*(*w));
        }
    }
    else goto err_unsupported;

go_return:
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    fclose(fp);
    return rc;

err_corrupt:
    rc = -2;
    free(data);
    goto go_return;
err_nomem:
    rc = -3;
    free(data);
    goto go_return;
err_unsupported:
    rc = -4;
    free(data);
    goto go_return;
}
/**
* From: http://stackoverflow.com/a/11297197
*/
GLuint gl4::TextureManager::_loadTextureFromPNG(const char * file_name, int * width, int * height)
{
    png_byte header[8];

    FILE *fp = fopen(file_name, "rb");
    if (fp == 0)
    {
        perror(file_name);
        return 0;
    }

    // read the header
    fread(header, 1, 8, fp);

    if (png_sig_cmp(header, 0, 8))
    {
        fprintf(stderr, "error: %s is not a PNG.\n", file_name);
        fclose(fp);
        return 0;
    }

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
    {
        fprintf(stderr, "error: png_create_read_struct returned 0.\n");
        fclose(fp);
        return 0;
    }

    // create png info struct
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        fprintf(stderr, "error: png_create_info_struct returned 0.\n");
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        fclose(fp);
        return 0;
    }

    // create png info struct
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info)
    {
        fprintf(stderr, "error: png_create_info_struct returned 0.\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
        fclose(fp);
        return 0;
    }

    // the code in this if statement gets called if libpng encounters an error
    if (setjmp(png_jmpbuf(png_ptr))) {
        fprintf(stderr, "error from libpng\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        fclose(fp);
        return 0;
    }

    // init png reading
    png_init_io(png_ptr, fp);

    // let libpng know you already read the first 8 bytes
    png_set_sig_bytes(png_ptr, 8);

    // read all the info up to the image data
    png_read_info(png_ptr, info_ptr);

    // variables to pass to get info
    int bit_depth, color_type;
    png_uint_32 temp_width, temp_height;

    // get info about png
    png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type,
        NULL, NULL, NULL);

    if (width != 0){ *width = temp_width; }
    if (height != 0){ *height = temp_height; }

    // Update the png info struct.
    png_read_update_info(png_ptr, info_ptr);

    // Row size in bytes.
    int rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    // glTexImage2d requires rows to be 4-byte aligned
    rowbytes += 3 - ((rowbytes-1) % 4);

    // Allocate the image_data as a big block, to be given to opengl
    png_byte * image_data;
    image_data = (png_byte*)std::malloc(rowbytes * temp_height * sizeof(png_byte)+15);
    if (image_data == NULL)
    {
        fprintf(stderr, "error: could not allocate memory for PNG image data\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        fclose(fp);
        return 0;
    }

    // row_pointers is for pointing to image_data for reading the png with libpng
    png_bytep * row_pointers = (png_bytep*)std::malloc(temp_height * sizeof(png_bytep));
    if (row_pointers == NULL)
    {
        fprintf(stderr, "error: could not allocate memory for PNG row pointers\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        free(image_data);
        fclose(fp);
        return 0;
    }

    // set the individual row_pointers to point at the correct offsets of image_data
    int i;
    for (i = 0; i < temp_height; i++)
    {
        row_pointers[temp_height - 1 - i] = image_data + i * rowbytes;
    }

    // read the png into image_data through row_pointers
    png_read_image(png_ptr, row_pointers);

    // Generate the OpenGL texture object
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, temp_width, temp_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

    // clean up
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    free(image_data);
    free(row_pointers);
    fclose(fp);
    return texture;
}
Beispiel #6
0
/** PNG content to bitmap conversion.
 *
 * This routine generates a bitmap object from a PNG image content
 */
static struct bitmap *
png_cache_convert(struct content *c)
{
	png_structp png_ptr;
	png_infop info_ptr;
	png_infop end_info_ptr;
	volatile struct bitmap *bitmap = NULL;
	struct png_cache_read_data_s png_cache_read_data;
	png_uint_32 width, height;
	volatile png_bytep *row_pointers = NULL;

	png_cache_read_data.data = 
		content__get_source_data(c, &png_cache_read_data.size);

	if ((png_cache_read_data.data == NULL) || 
	    (png_cache_read_data.size <= 8)) {
		return NULL;
	}

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
			nspng_error, nspng_warning);
	if (png_ptr == NULL) {
		return NULL;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		return NULL;
	}

	end_info_ptr = png_create_info_struct(png_ptr);
	if (end_info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return NULL;
	}

	/* setup error exit path */
	if (setjmp(png_jmpbuf(png_ptr))) {
		/* cleanup and bail */
		goto png_cache_convert_error;
	}

	/* read from a buffer instead of stdio */
	png_set_read_fn(png_ptr, &png_cache_read_data, png_cache_read_fn);

	/* ensure the png info structure is populated */
	png_read_info(png_ptr, info_ptr);

	/* setup output transforms */
	nspng_setup_transforms(png_ptr, info_ptr);

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

	/* Claim the required memory for the converted PNG */
	bitmap = bitmap_create(width, height, BITMAP_NEW);
	if (bitmap == NULL) {
		/* cleanup and bail */
		goto png_cache_convert_error;
	}

	row_pointers = calc_row_pointers((struct bitmap *) bitmap);

	if (row_pointers != NULL) {
		png_read_image(png_ptr, (png_bytep *) row_pointers);
	}

png_cache_convert_error:

	/* cleanup png read */
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);

	free((png_bytep *) row_pointers);

	if (bitmap != NULL)
		bitmap_modified((struct bitmap *)bitmap);

	return (struct bitmap *)bitmap;
}
Beispiel #7
0
VBuf *BmpHandleToPngByte(HBITMAP hBmp)
{
	BITMAP		bmp;
	BITMAPINFO	*bmi = NULL;
	int			palette, total_size, header_size, data_size, line_size;
	HWND		hWnd = ::GetDesktopWindow();
	HDC			hDc = NULL;
	VBuf		bmpVbuf;
	png_struct	*png  = NULL;
	png_info	*info = NULL;
	png_color_8	sbit;
	png_byte	**lines = NULL;
	VBuf		*vbuf = NULL, *ret = NULL;

	if (!::GetObject(hBmp, sizeof(bmp), &bmp)) return NULL;

	//if (bmp.bmBitsPixel < 24)
	bmp.bmBitsPixel = 24;

	line_size   = bmp.bmWidth * ALIGN_SIZE(bmp.bmBitsPixel, 8) / 8;
	line_size   = ALIGN_SIZE(line_size, 4);
	data_size   = line_size * bmp.bmHeight;
	palette     = bmp.bmBitsPixel <= 8 ? 1 << bmp.bmBitsPixel : 0;
	header_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palette;
	total_size	= header_size + data_size;

	if (!bmpVbuf.AllocBuf(total_size)) return	NULL;
	bmi = (BITMAPINFO *)bmpVbuf.Buf();

	bmi->bmiHeader.biSize         = sizeof(BITMAPINFOHEADER);
	bmi->bmiHeader.biWidth        = bmp.bmWidth;
	bmi->bmiHeader.biHeight       = bmp.bmHeight;
	bmi->bmiHeader.biPlanes       = 1;
	bmi->bmiHeader.biBitCount     = bmp.bmBitsPixel;
	bmi->bmiHeader.biCompression  = BI_RGB;
	bmi->bmiHeader.biClrUsed      = palette;
	bmi->bmiHeader.biClrImportant = palette;

	if (!(hDc = ::GetDC(hWnd)) ||
		!::GetDIBits(hDc, hBmp, 0, bmp.bmHeight, (char *)bmi + header_size, bmi, DIB_RGB_COLORS)) {
		goto END;
	}

	if (!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) return NULL;
	if (!(info = png_create_info_struct(png))) goto END;
	if (!(vbuf = new VBuf(0, total_size))) goto END;

	png_set_write_fn(png, (void *)vbuf, (png_rw_ptr)png_vbuf_wfunc,
					(png_flush_ptr)png_vbuf_wflush);

	if (palette) {
		png_color	png_palette[256];
		for (int i=0; i < palette; i++) {
			png_palette[i].red		= bmi->bmiColors[i].rgbRed;
			png_palette[i].green	= bmi->bmiColors[i].rgbGreen;
			png_palette[i].blue		= bmi->bmiColors[i].rgbBlue;
		}
		png_set_IHDR(png, info, bmp.bmWidth, bmp.bmHeight, bmp.bmBitsPixel,
					PNG_COLOR_TYPE_PALETTE,
					PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
		png_set_PLTE(png, info, png_palette, palette);
	}
	else {
		png_set_IHDR(png, info, bmp.bmWidth, bmp.bmHeight, 8,
					bmp.bmBitsPixel > 24 ? PNG_COLOR_TYPE_RGB_ALPHA  : PNG_COLOR_TYPE_RGB,
					PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
	}
	sbit.red = sbit.green = sbit.blue = 8;
	sbit.alpha = bmp.bmBitsPixel > 24 ? 8 : 0;
	png_set_sBIT(png, info, &sbit);

	if (setjmp(png_jmpbuf(png))) {
		goto END;
	}
	else {
		png_write_info(png, info);
		png_set_bgr(png);

		lines = (png_byte **)malloc(sizeof(png_bytep *) * bmp.bmHeight);

		for (int i = 0; i < bmp.bmHeight; i++) {
			lines[i] = bmpVbuf.Buf() + header_size + line_size * (bmp.bmHeight - i - 1);
		}
		png_write_image(png, lines);
		png_write_end(png, info);
		ret = vbuf;
	}

END:
	if (png) png_destroy_write_struct(&png, &info);
	if (hDc) ::ReleaseDC(hWnd, hDc);
	if (lines) free(lines);
	if (!ret && vbuf) delete vbuf;
	return	ret;
}
Beispiel #8
0
static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, volatile bool mask)
{
	png_byte header[8];
	png_structp png_ptr;
	png_infop info_ptr, end_info;
	uint bit_depth, colour_type;
	uint i, pixelsize;
	SpriteLoader::CommonPixel *dst;

	if (!OpenPNGFile(filename, id, mask)) return mask; // If mask is true, and file not found, continue true anyway, as it isn't a show-stopper

	/* Check the header */
	FioReadBlock(header, 8);
	if (png_sig_cmp(header, 0, 8) != 0) return false;

	/* Create the reader */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_my_error, png_my_warning);
	if (png_ptr == NULL) return false;

	/* Create initial stuff */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		return false;
	}
	end_info = png_create_info_struct(png_ptr);
	if (end_info == NULL) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		return false;
	}

	/* Make sure that upon error, we can clean up graceful */
	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		return false;
	}

	/* Read the file */
	png_set_read_fn(png_ptr, NULL, png_my_read);
	png_set_sig_bytes(png_ptr, 8);

	png_read_info(png_ptr, info_ptr);

	if (!mask) {
		/* Read the text chunks */
		png_textp text_ptr;
		int num_text = 0;
		png_get_text(png_ptr, info_ptr, &text_ptr, &num_text);
		if (num_text == 0) DEBUG(misc, 0, "Warning: PNG Sprite '%s/%d.png' doesn't have x_offs and y_offs; expect graphical problems", filename, id);
		for (int i = 0; i < num_text; i++) {
			/* x_offs and y_offs are in the text-chunk of PNG */
			if (strcmp("x_offs", text_ptr[i].key) == 0) sprite->x_offs = strtol(text_ptr[i].text, NULL, 0);
			if (strcmp("y_offs", text_ptr[i].key) == 0) sprite->y_offs = strtol(text_ptr[i].text, NULL, 0);
		}

		sprite->height = png_get_image_height(png_ptr, info_ptr);
		sprite->width  = png_get_image_width(png_ptr, info_ptr);
		sprite->AllocateData(sprite->width * sprite->height);
	}

	bit_depth  = png_get_bit_depth(png_ptr, info_ptr);
	colour_type = png_get_color_type(png_ptr, info_ptr);

	if (mask && (bit_depth != 8 || colour_type != PNG_COLOR_TYPE_PALETTE)) {
		DEBUG(misc, 0, "Ignoring mask for SpriteID %d as it isn't a 8 bit palette image", id);
		return true;
	}

	if (!mask) {
		if (bit_depth == 16) png_set_strip_16(png_ptr);

		if (colour_type == PNG_COLOR_TYPE_PALETTE) {
			png_set_palette_to_rgb(png_ptr);
			colour_type = PNG_COLOR_TYPE_RGB;
		}
		if (colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
			png_set_gray_to_rgb(png_ptr);
			colour_type = PNG_COLOR_TYPE_RGB;
		}

		if (colour_type == PNG_COLOR_TYPE_RGB) {
			png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
		}

		pixelsize = sizeof(uint32);
	} else {
		pixelsize = sizeof(uint8);
	}

	png_bytep row_pointer = AllocaM(png_byte, png_get_image_width(png_ptr, info_ptr) * pixelsize);

	for (i = 0; i < png_get_image_height(png_ptr, info_ptr); i++) {
		png_read_row(png_ptr, row_pointer, NULL);

		dst = sprite->data + i * png_get_image_width(png_ptr, info_ptr);

		for (uint x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) {
			if (mask) {
				if (row_pointer[x * sizeof(uint8)] != 0) {
					dst[x].r = 0;
					dst[x].g = 0;
					dst[x].b = 0;
					/* Alpha channel is used from the original image (to allow transparency in remap colours) */
					dst[x].m = row_pointer[x * sizeof(uint8)];
				}
			} else {
				dst[x].r = row_pointer[x * sizeof(uint32) + 0];
				dst[x].g = row_pointer[x * sizeof(uint32) + 1];
				dst[x].b = row_pointer[x * sizeof(uint32) + 2];
				dst[x].a = row_pointer[x * sizeof(uint32) + 3];
				dst[x].m = 0;
			}
		}
	}

	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

	return true;
}
Beispiel #9
0
Image* Image::LoadPNG( IFileReader* file ) {
	png_byte header[8];
	if ( file->ReadByte( header, sizeof(header) ) == false ) {
		RETURN_ERROR( "failed to read png header from %s", file->GetFileName( ) );
	}

	if ( png_sig_cmp(header, 0, 8) != 0 ) {
		RETURN_ERROR( "%s is not png format!", file->GetFileName( ) );
	}

	png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
	if ( png_ptr == NULL ) {
		RETURN_ERROR( "png_create_read_struct returned 0" );
	}

	// create png info struct
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if ( info_ptr == NULL ) {
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		RETURN_ERROR( "png_create_info_struct returned 0" );
	}

	// create png info struct
	png_infop end_info = png_create_info_struct(png_ptr);
	if ( end_info == NULL )
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
		RETURN_ERROR( "error: png_create_info_struct returned 0" );
	}

	// init png reading
	png_set_read_fn( png_ptr, file, png_read_callback );

	// the code in this if statement gets called if libpng encounters an error
	if ( setjmp( png_jmpbuf( png_ptr ) ) ) {
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		RETURN_ERROR( "error from libpng" );
	}

	// let libpng know you already read the first 8 bytes
	png_set_sig_bytes( png_ptr, 8 );

	// read all the info up to the image data
	png_read_info( png_ptr, info_ptr );

	// variables to pass to get info
	int bit_depth, color_type;
	png_uint_32 width, height;

	// get info about png
	png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );

	bool hasAlpha = false;
	if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) {
		png_set_tRNS_to_alpha( png_ptr );
		hasAlpha = true;
	}
	// Expands PNG with less than 8bits per channel to 8bits.
	if ( bit_depth < 8 ) {
		png_set_packing ( png_ptr );
	// Shrinks PNG with 16bits per color channel down to 8bits.
	}
	else if ( bit_depth == 16 ) {
		png_set_strip_16( png_ptr );
	}
	// Indicates that image needs conversion to RGBA if needed.
	GLint format;
	switch ( color_type ) {
	case PNG_COLOR_TYPE_PALETTE:
		png_set_palette_to_rgb( png_ptr );
		format = hasAlpha ? GL_RGBA : GL_RGB;
		break;
	case PNG_COLOR_TYPE_RGB:
		format = hasAlpha ? GL_RGBA : GL_RGB;
		break;
	case PNG_COLOR_TYPE_RGBA:
		format = GL_RGBA;
		break;
	case PNG_COLOR_TYPE_GRAY:
		png_set_expand_gray_1_2_4_to_8( png_ptr );
		format = hasAlpha ? GL_LUMINANCE_ALPHA:GL_LUMINANCE;
		break;
	case PNG_COLOR_TYPE_GA:
		png_set_expand_gray_1_2_4_to_8( png_ptr );
		format = GL_LUMINANCE_ALPHA;
		break;
    default:
        format = 0;
        break;
	}

	// Update the png info struct.
	png_read_update_info( png_ptr, info_ptr );

	// Row size in bytes.
	int rowbytes = (int)png_get_rowbytes( png_ptr, info_ptr );

	// glTexImage2d requires rows to be 4-byte aligned
	rowbytes += 3 - ((rowbytes-1) % 4);

	// Allocate the image_data as a big block, to be given to opengl
	png_byte* image_data;
	image_data = new png_byte[rowbytes * height * sizeof(png_byte) + 15];
	if (image_data == NULL) {
		delete[] image_data;
		png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
		RETURN_ERROR( "could not allocate memory for PNG image data" );
	}

	// row_pointers is for pointing to image_data for reading the png with libpng
	png_bytep* row_pointers = new png_bytep[height * sizeof(png_bytep)];
	if (row_pointers == NULL) {
		delete[] image_data;
		delete[] row_pointers;
		png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
		RETURN_ERROR( "could not allocate memory for PNG row pointers" );
	}

	// set the individual row_pointers to point at the correct offsets of image_data
	for ( unsigned int i = 0; i < height; i++ ) {
		row_pointers[height - 1 - i] = image_data + i * rowbytes;
	}

	// read the png into image_data through row_pointers
	png_read_image( png_ptr, row_pointers );

	png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );

	return new Image( width, height, format, image_data );
}
Beispiel #10
0
void
read_png(unsigned char **block, png_uint_32 *width, png_uint_32 *height, FILE *file)
{
    png_structp png_ptr;
    png_infop   info_ptr;
    png_bytep *row_pointers;
    unsigned row, x, y;
    int rowbytes;
    char *dst;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
    if (png_ptr == NULL) {
	printf("\nERROR: read_png: Could not create read struct.\n");
	exit(1);
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
	printf("\nERROR: read_png: Could not create info struct.\n");
	png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
	exit(1);
    }


    if (setjmp(png_ptr->jmpbuf)) {

	printf("\nERROR: read_png: fatal error.\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_info **)0);
        /* free pointers before returning, if necessary */
        free(png_ptr);
        free(info_ptr);

	exit(1);
    }

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


    /* 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, NULL, NULL);

    // printf("read_png: width=%d, height=%d, bit_depth=%d\n", width, height, bit_depth);
    // printf("read_png: color_type=%d, interlace_type=%d\n", color_type, interlace_type);
    
    // strip alpha information
    if (color_type & PNG_COLOR_MASK_ALPHA) {
        png_set_strip_alpha(png_ptr);
    }

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

    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
     * byte into separate bytes (useful for paletted and grayscale images).
     */
    png_set_packing(png_ptr);

    /* Expand paletted colors into true RGB triplets */
    png_set_expand(png_ptr);

    png_start_read_image(png_ptr);

    /* The easiest way to read the image: */

    rowbytes = png_get_rowbytes(png_ptr, info_ptr) * 3;
    row_pointers = (png_bytep *)malloc((*height) * sizeof(*row_pointers));

    row_pointers[0] = (png_bytep)malloc(rowbytes * (*height) * 2);

    for(row = 1; row < (*height); row++) {
	row_pointers[row] = row_pointers[row - 1] + rowbytes*2;
    }
    /* Read the entire image in one go */
    png_read_image(png_ptr, row_pointers);

    // we use fixed height here because block is of limited, fixed size
    // not fixed any more

    *block = realloc(*block, *height * *width * 3);

    // *block = malloc(*height * *width * 6);

    dst = *block;
    for(y = 0; y < *height; y++) {
	for(x = 0; x < *width * 3; x++) {
	  *dst++ = row_pointers[y][x];

	  // *dst++ = 0;
	}
    }
  
    free(row_pointers[0]);
    free(row_pointers);

    /* 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);
}
static int
open_png(const char *name, png_structp *png_ptr, png_infop *info_ptr,
	 FILE **fp, png_uint_32 *width, png_uint_32 *height,
	 png_byte *channels)
{
	char resPath[256];
	unsigned char header[8];
	int color_type, bit_depth, result = 0;
	size_t bytesRead;

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

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

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

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

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

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

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

	png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
		     &color_type, NULL, NULL, NULL);

	*channels = png_get_channels(*png_ptr, *info_ptr);

	if (bit_depth == 8 && *channels == 3 &&
	    color_type == PNG_COLOR_TYPE_RGB) {
		/* 8-bit RGB images: great, nothing to do. */
	} else if (bit_depth <= 8 && *channels == 1 &&
		   color_type == PNG_COLOR_TYPE_GRAY) {
		/* 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. */
		png_set_expand_gray_1_2_4_to_8(*png_ptr);
	} else if (bit_depth <= 8 && *channels == 1 &&
		   color_type == PNG_COLOR_TYPE_PALETTE) {
		/* paletted images: expand to 8-bit RGB. Note that we DON'T
		 * currently expand the tRNS chunk (if any) to an alpha
		 * channel, because minui doesn't support alpha channels
		 * in general. */
		png_set_palette_to_rgb(*png_ptr);
		*channels = 3;
	} else {
		fprintf(stderr,
			"minui doesn't support PNG depth %d channels %d "
			"color_type %d\n",
			bit_depth, *channels, color_type);
		result = -7;
		goto exit;
	}

	return result;

exit:
	if (result < 0)
		png_destroy_read_struct(png_ptr, info_ptr, NULL);

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

	return result;
}
Beispiel #12
0
    /*! \brief Reads a PNG file and places the pixel data in the
     * passed array.
     *
     * \param filename The name of the file to read.
     * \param image The array of \ref Pixel data to read the image into.
     * \param width Variable used to return the width of the image.
     * \param height Variable used to return the height of the image.
     */
    inline void readPNGFile(const std::string& filename,
			    std::vector<uint8_t>& image, 
			    size_t& width, size_t& height,
			    size_t& components) 
    {

      std::ifstream pngFile(filename.c_str(), std::fstream::binary);

      if(!pngFile.is_open()) {
	std::stringstream strm;
	strm << "failed to open file '" << filename << "'";
	throw std::runtime_error(strm.str().c_str());
      }
      
      pngFile.exceptions(std::fstream::badbit | std::fstream::failbit);
      
      const size_t pngHeaderSize = 8;
      png_byte pngHeader[pngHeaderSize];

      pngFile.read(reinterpret_cast<char*>(pngHeader), pngHeaderSize);

      if(png_sig_cmp(pngHeader, 0, pngHeaderSize)) {
	std::stringstream strm;
	strm << "failed to read '" << filename << "': not a png file";
	throw std::runtime_error(strm.str().c_str());
      }

      png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
					       NULL, NULL, NULL);

      if(!png)
	throw std::runtime_error("failed to allocate png_struct");

      png_infop pngInfo = png_create_info_struct(png);

      if(!pngInfo) {
	png_destroy_read_struct(&png, NULL, NULL);
	throw std::runtime_error("failed to allocate png_info_struct");
      }

      png_infop pngEndInfo = png_create_info_struct(png);

      if(!pngEndInfo) {
	png_destroy_read_struct(&png, &pngInfo, NULL);
	throw std::runtime_error("failed to allocate png_info_struct");
      }

      // set up error handling the hard way
      if(setjmp(png_jmpbuf(png))) {
	png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
	throw std::runtime_error("libpng: failed to set up io");
      }

      png_set_read_fn(png, static_cast<void*>(&pngFile),
		      detail::read);

      png_set_sig_bytes(png, pngHeaderSize);

      png_read_info(png, pngInfo);

      if(png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGBA &&
	 png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGB) {

	png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);

	std::stringstream strm;
	strm << "unsupported color type in '" << filename << "'";
	throw std::runtime_error(strm.str().c_str());
      }

      width = png_get_image_width(png, pngInfo);
      height = png_get_image_height(png, pngInfo);
      components = png_get_channels(png, pngInfo);

      if ((components != 3) && (components != 4))
	throw std::runtime_error("Unsupported number of components");
      size_t bitDepth = png_get_bit_depth(png, pngInfo);


      if(bitDepth != 8) {
	png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
	
	std::stringstream strm;
	strm << "failed to read '" << filename << "': invalid bit " <<
	  "depth: " << bitDepth;
	throw std::runtime_error(strm.str().c_str());
      }

      size_t bytesPerRow = png_get_rowbytes(png, pngInfo);
      png_bytep* pngRows = new png_bytep[height];
      png_bytep pngData = 0;

      image.resize(height * width * components);

      size_t offset = 0;
      png_bytep basePointer = reinterpret_cast<png_bytep>(&image[0]);

      for(size_t row = 0; row < height; ++row) {
	pngRows[row] = basePointer + offset;
	offset += bytesPerRow;
      }

      // set up error handling the hard way
      if(setjmp(png_jmpbuf(png))) {
	png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
	delete[] pngData;
	delete[] pngRows;
	throw std::runtime_error("libpng: failed to read image");
      }

      png_read_image(png, pngRows);
      png_read_end(png, pngEndInfo);

      // all went well, we can clean up now
      png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
      delete[] pngData;
      delete[] pngRows;
    }
Beispiel #13
0
    /*! \brief Writes a PNG file using the pixel data in the passed
     * array.
     *
     * \param filename The name of the file to create/overwrite.
     * \param image The array of \ref Pixel data to write out.
     * \param width The width of the image.
     * \param height The height of the image.
     * \param compressionLevel The level of compression requested from the PNG library.
     * \param disableFiltering Prevent the PNG library from filtering the output.
     * \param flip Flips the vertical ordering of the image (to allow easy saving of OpenGL renderings).
     */
    inline void writePNGFile(const std::string& filename,
			     std::vector<uint8_t >& image, 
			     size_t width, size_t height,
			     size_t components,
			     int compressionLevel = PNG_COMPRESSION_TYPE_DEFAULT,
			     bool disableFiltering = false, bool flip = false) {

      if(image.size() != width * height * components) 
	{
	  std::stringstream strm;
	  strm << "invalid input to writePNGFile(): " <<
	    "size mismatch of input vector (is " << image.size() <<
	    ", should be " << width << "x" << height << " = " <<
	    width * height;
	  throw std::runtime_error(strm.str().c_str());
	}

      if(compressionLevel < 0 || compressionLevel > 9) {
	std::stringstream strm;
	strm << "invalid input to writePNGFile(): " <<
	  "valid compression levels range from 0 to 9 (default: " <<
	  PNG_COMPRESSION_TYPE_DEFAULT << ")";
	throw std::runtime_error(strm.str().c_str());
      }

      std::ofstream pngFile(filename.c_str(), std::fstream::binary);

      if(!pngFile.is_open()) 
	{
	  std::stringstream strm;
	  strm << "failed to open file '" << filename << "'";
	  throw std::runtime_error(strm.str().c_str());
	}

      pngFile.exceptions(std::fstream::badbit | std::fstream::failbit);

      png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
						NULL, NULL, NULL);

      if(!png)
	throw std::runtime_error("failed to allocate png_struct");

      png_infop pngInfo = png_create_info_struct(png);

      if(!pngInfo) {
	png_destroy_write_struct(&png, NULL);
	throw std::runtime_error("failed to allocate png_info_struct");
      }

      // set up error handling the hard way
      if(setjmp(png_jmpbuf(png))) {
	png_destroy_write_struct(&png, &pngInfo);
	throw std::runtime_error("libpng: failed to set up io");
      }

      png_set_write_fn(png, static_cast<void*>(&pngFile),
		       detail::write, detail::flush);

      switch (components)
	{
	case 3:
	  png_set_IHDR(png, pngInfo, width, height, 8, PNG_COLOR_TYPE_RGB,
		       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
		       PNG_FILTER_TYPE_BASE);
	  break;
	case 4:
	  png_set_IHDR(png, pngInfo, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
		       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
		       PNG_FILTER_TYPE_BASE);
	  break;
	default:
	  throw std::runtime_error("Unsupported number of components");
	}

      if(disableFiltering)
	png_set_filter(png, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);

      if(compressionLevel != PNG_COMPRESSION_TYPE_DEFAULT)
	png_set_compression_level(png, compressionLevel);

      png_write_info(png, pngInfo);

      size_t bytesPerRow = png_get_rowbytes(png, pngInfo);
      png_bytep* pngRows = new png_bytep[height];

      if(image.size() != (height * bytesPerRow)) 
	{
	  std::stringstream strm;
	  strm << "writePNGFile(): invalid size of input data";
	  throw std::runtime_error(strm.str().c_str());
	}

      size_t offset = 0;
      png_bytep basePointer = reinterpret_cast<png_bytep>(&image[0]);
			
      if (flip)
	for(int row = height - 1; row >= 0; --row) 
	  {
	    pngRows[row] = basePointer + offset;
	    offset += bytesPerRow;
	  }
      else
	for(size_t row = 0; row < height; ++row) 
	  {
	    pngRows[row] = basePointer + offset;
	    offset += bytesPerRow;
	  }

      // set up error handling the hard way
      if(setjmp(png_jmpbuf(png))) {
	png_destroy_write_struct(&png, &pngInfo);
	delete[] pngRows;
	throw std::runtime_error("libpng: failed to write image");
      }

      png_write_image(png, pngRows);
      png_write_end(png, NULL);

      // all went well, we can clean up now
      png_destroy_write_struct(&png, &pngInfo);
      delete[] pngRows;
    }
Beispiel #14
0
/**
 * @brief internal function used to read a PNG file into an array
 *
 * @todo don't loose 16bit info
 *
 * @param fname PNG file name, "-" means stdin
 * @param nx, ny, nc pointers to variables to be filled
 *        with the number of columns, lines and channels of the image
 * @param transform a PNG_TRANSFORM to be added to the default read transforms
 * @param dtype identifier for the data type to be used for output
 * @return pointer to an allocated array of pixels,
 *         or NULL if an error happens
 */
static void *read_png_raw(const char *fname,
                          size_t * nx, size_t * ny, size_t * nc,
                          int transform, int dtype)
{
    png_byte png_sig[PNG_SIG_LEN];
    png_structp png_ptr;
    png_infop info_ptr;
    png_bytepp row_pointers;
    png_bytep row_ptr;
    /* volatile : because of setjmp/longjmp */
    FILE *volatile fp = NULL;
    void *data = NULL;
    unsigned char *data_u8 = NULL;
    unsigned char *data_u8_ptr = NULL;
    float *data_f32 = NULL;
    float *data_f32_ptr = NULL;
    size_t size;
    size_t i, j, k;

    /* parameters check */
    if (NULL == fname || NULL == nx || NULL == ny || NULL == nc)
        return NULL;
    if (IO_PNG_U8 != dtype && IO_PNG_F32 != dtype)
        return NULL;

    /* open the PNG input file */
    if (0 == strcmp(fname, "-"))
        fp = stdin;
    else if (NULL == (fp = fopen(fname, "rb")))
        return NULL;

    /* read in some of the signature bytes and check this signature */
    if ((PNG_SIG_LEN != fread(png_sig, 1, PNG_SIG_LEN, fp))
        || 0 != png_sig_cmp(png_sig, (png_size_t) 0, PNG_SIG_LEN))
        return read_png_abort(fp, NULL, NULL);

    /*
     * create and initialize the png_struct
     * with the default stderr and error handling
     */
    if (NULL == (png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                                  NULL, NULL, NULL)))
        return read_png_abort(fp, NULL, NULL);

    /* allocate/initialize the memory for image information */
    if (NULL == (info_ptr = png_create_info_struct(png_ptr)))
        return read_png_abort(fp, &png_ptr, NULL);

    /* set error handling */
    if (0 != setjmp(png_jmpbuf(png_ptr)))
        /* if we get here, we had a problem reading the file */
        /* free all of the memory associated with the png_ptr and info_ptr */
        return read_png_abort(fp, &png_ptr, &info_ptr);

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

    /* let libpng know that some bytes have been read */
    png_set_sig_bytes(png_ptr, PNG_SIG_LEN);

    /*
     * set the read filter transforms, to get 8bit RGB whatever the
     * original file may contain:
     * PNG_TRANSFORM_STRIP_16      strip 16-bit samples to 8 bits
     * PNG_TRANSFORM_PACKING       expand 1, 2 and 4-bit
     *                             samples to bytes
     */
    transform |= (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING);

    /* read in the entire image at once */
    png_read_png(png_ptr, info_ptr, transform, NULL);

    /* get image informations */
    *nx = (size_t) png_get_image_width(png_ptr, info_ptr);
    *ny = (size_t) png_get_image_height(png_ptr, info_ptr);
    *nc = (size_t) png_get_channels(png_ptr, info_ptr);
    row_pointers = png_get_rows(png_ptr, info_ptr);

    /*
     * allocate the output data RGB array
     * deinterlace and convert png RGB RGB RGB 8bit to RRR GGG BBB
     * the image is deinterlaced layer after layer
     * this generic loop also works for one single channel
     */
    size = *nx * *ny * *nc;
    switch (dtype)
    {
    case IO_PNG_U8:
        if (NULL == (data_u8 =
                     (unsigned char *) malloc(size * sizeof(unsigned char))))
            return read_png_abort(fp, &png_ptr, &info_ptr);
        data = (void *) data_u8;
        for (k = 0; k < *nc; k++)
        {
            /* channel loop */
            data_u8_ptr = data_u8 + (size_t) (*nx * *ny * k);
            for (j = 0; j < *ny; j++)
            {
                /* row loop */
                row_ptr = row_pointers[j] + k;
                for (i = 0; i < *nx; i++)
                {
                    /* pixel loop */
                    *data_u8_ptr++ = (unsigned char) *row_ptr;
                    row_ptr += *nc;
                }
            }
        }
        break;
    case IO_PNG_F32:
        if (NULL == (data_f32 = (float *) malloc(size * sizeof(float))))
            return read_png_abort(fp, &png_ptr, &info_ptr);
        data = (void *) data_f32;
        for (k = 0; k < *nc; k++)
        {
            /* channel loop */
            data_f32_ptr = data_f32 + (size_t) (*nx * *ny * k);
            for (j = 0; j < *ny; j++)
            {
                /* row loop */
                row_ptr = row_pointers[j] + k;
                for (i = 0; i < *nx; i++)
                {
                    /* pixel loop */
                    *data_f32_ptr++ = (float) *row_ptr;
                    row_ptr += *nc;
                }
            }
        }
        break;
    }

    /* clean up and free any memory allocated, close the file */
    (void) read_png_abort(fp, &png_ptr, &info_ptr);

    return data;
}
Beispiel #15
0
void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
                 mapnik::image_data_8 const& image,
                 unsigned width,
                 unsigned height,
                 unsigned color_depth,
                 int compression,
                 int strategy,
                 std::vector<unsigned> const&alpha)
{
    png_voidp error_ptr=0;
    png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                                error_ptr,0, 0);

    if (!png_ptr) return;

    // switch on optimization only if supported
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
    png_uint_32 mask, flags;
    flags = png_get_asm_flags(png_ptr);
    mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
    png_set_asm_flags(png_ptr, flags | mask);
#endif
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
        return;
    }
    jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr);
    if (jmp_context)
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return;
    }
    png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>);

    png_set_compression_level(png_ptr, compression);
    png_set_compression_strategy(png_ptr, strategy);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr,width,height,color_depth,
                 PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);

    png_color* pal = const_cast<png_color*>(reinterpret_cast<const png_color*>(&palette[0]));
    png_set_PLTE(png_ptr, info_ptr, pal, palette.size());

    // make transparent lowest indexes, so tRNS is small
    if (alpha.size()>0)
    {
        std::vector<png_byte> trans(alpha.size());
        unsigned alphaSize=0;//truncate to nonopaque values
        for(unsigned i=0; i < alpha.size(); i++)
        {
            trans[i]=alpha[i];
            if (alpha[i]<255)
                alphaSize = i+1;
        }
        if (alphaSize>0)
            png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0);
    }

    png_write_info(png_ptr, info_ptr);
    for (unsigned i=0;i<height;i++)
    {
        png_write_row(png_ptr,(png_bytep)image.getRow(i));
    }

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}
Beispiel #16
0
static HPDF_STATUS
LoadPngData  (HPDF_Dict     image,
              HPDF_Xref     xref,
              HPDF_Stream   png_data,
              HPDF_BOOL     delayed_loading)

{
	HPDF_STATUS ret = HPDF_OK;
	png_uint_32 width, height;
	int bit_depth, color_type;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;

	HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n"));

	/* create read_struct. */
	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
			image->error, PngErrorFunc, PngErrorFunc);

	if (png_ptr == NULL) {
		HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0);
		return HPDF_FAILD_TO_ALLOC_MEM;
	}

	/* create info-struct */
	info_ptr = png_create_info_struct (png_ptr);

	if (info_ptr == NULL) {
		HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0);
		goto Exit;
	}

	png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK);
	png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc);

	/* reading info structure. */
	png_read_info(png_ptr, info_ptr);
	if (image->error->error_no != HPDF_OK) {
		goto Exit;
	}

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

	/* 16bit images are not supported. */
	if (bit_depth == 16) {
		png_set_strip_16(png_ptr);
	}

	png_read_update_info(png_ptr, info_ptr);
	if (image->error->error_no != HPDF_OK) {
		goto Exit;
	}

	/* check palette-based images for transparent areas and load them immediately if found */
	if (xref && PNG_COLOR_TYPE_PALETTE & color_type) {
		png_bytep trans;
		int num_trans;
		HPDF_Dict smask;
		png_bytep smask_data;

		if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || 
			!png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) {
			goto no_transparent_color_in_palette;
		}

		smask = HPDF_DictStream_New (image->mmgr, xref);
		if (!smask) {
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
		ret = HPDF_Dict_AddName (smask, "Type", "XObject");
		ret += HPDF_Dict_AddName (smask, "Subtype", "Image");
		ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width);
		ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
		ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth);

		if (ret != HPDF_OK) {
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		smask_data = HPDF_GetMem(image->mmgr, width * height);
		if (!smask_data) {
			HPDF_Dict_Free(smask);
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_FILE_IO_ERROR;
			goto Exit;
		}
		HPDF_FreeMem(image->mmgr, smask_data);


		ret += CreatePallet(image, png_ptr, info_ptr);
		ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width);
		ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddNumber (image, "BitsPerComponent",	(HPDF_UINT)bit_depth);
		ret += HPDF_Dict_Add (image, "SMask", smask);

		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return HPDF_OK;
	}

no_transparent_color_in_palette:

	/* read images with alpha channel right away 
	   we have to do this because image transparent mask must be added to the Xref */
	if (xref && PNG_COLOR_MASK_ALPHA & color_type) {
		HPDF_Dict smask;
		png_bytep smask_data;

		smask = HPDF_DictStream_New (image->mmgr, xref);
		if (!smask) {
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
		ret = HPDF_Dict_AddName (smask, "Type", "XObject");
		ret += HPDF_Dict_AddName (smask, "Subtype", "Image");
		ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width);
		ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
		ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth);

		if (ret != HPDF_OK) {
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		smask_data = HPDF_GetMem(image->mmgr, width * height);
		if (!smask_data) {
			HPDF_Dict_Free(smask);
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		if (ReadTransparentPngData(image, png_ptr, info_ptr, smask_data) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_FILE_IO_ERROR;
			goto Exit;
		}
		HPDF_FreeMem(image->mmgr, smask_data);

		if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
			ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray");
		} else {
			ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB");
		}
		ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width);
		ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddNumber (image, "BitsPerComponent",	(HPDF_UINT)bit_depth);
		ret += HPDF_Dict_Add (image, "SMask", smask);

		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return HPDF_OK;
	}

	/* if the image has color palette, copy the pallet of the image to
	 * create color map.
	 */
	if (color_type == PNG_COLOR_TYPE_PALETTE)
		ret = CreatePallet(image, png_ptr, info_ptr);
	else if (color_type == PNG_COLOR_TYPE_GRAY)
		ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray");
	else
		ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB");

	if (ret != HPDF_OK)
		goto Exit;

	/* read image-data
	 * if the image is interlaced, read whole image at once.
	 * if delayed_loading is HPDF_TRUE, the data does not load this phase.
	 */
	if (delayed_loading) {
		image->before_write_fn = PngBeforeWrite;
		image->after_write_fn = PngAfterWrite;
	} else {
		if (png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE)
			ret = ReadPngData_Interlaced(image, png_ptr, info_ptr);
		else
			ret = ReadPngData(image, png_ptr, info_ptr);

		if (ret != HPDF_OK)
			goto Exit;
	}

	/* setting the info of the image. */
	if (HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width)
			!= HPDF_OK)
		goto Exit;

	if (HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height)
			!= HPDF_OK)
		goto Exit;

	if (HPDF_Dict_AddNumber (image, "BitsPerComponent",
				(HPDF_UINT)bit_depth) != HPDF_OK)
		goto Exit;

	/* clean up */
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	return HPDF_OK;

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

	if (ret != HPDF_OK) {
		return ret;
	}
	return image->error->error_no;
}
boolean mgSaveToPng(FILE *png_file, struct memGfx *mg, boolean useTransparency)
/* Save PNG to an already open file.
 * If useTransparency, then the first color in memgfx's colormap/palette is
 * assumed to be the image background color, and pixels of that color
 * are made transparent. */
/* Reference: http://libpng.org/pub/png/libpng-1.2.5-manual.html */
{
if (!png_file || !mg)
    errAbort("mgSaveToPng: called with a NULL");
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
					  NULL, // don't need pointer to data for err/warn handlers
					  pngAbort, pngWarn);
if (!png)
    {
    errAbort("png_write_struct failed");
    return FALSE;
    }
png_infop info = png_create_info_struct(png);
if (!info)
    {
    errAbort("png create_info_struct failed");
    png_destroy_write_struct(&png, NULL);
    return FALSE;
    }

// If setjmp returns nonzero, it means png_error is returning control here.
// But that should not happen because png_error should call pngAbort which calls errAbort.
if (setjmp(png_jmpbuf(png)))
    {
    png_destroy_write_struct(&png, &info);
    fclose(png_file);
    errAbort("pngwrite: setjmp nonzero.  "
	     "why didn't png_error..pngAbort..errAbort stop execution before this errAbort?");
    return FALSE;
    }

// Configure PNG output params:
png_init_io(png, png_file);
#ifdef COLOR32
png_set_IHDR(png, info, mg->width, mg->height, 8, // 8=bit_depth
             PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
#else
png_set_IHDR(png, info, mg->width, mg->height, 8, // 8=bit_depth
             PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_PLTE(png, info,
             (png_color *)(mg->colorMap), // png_color is same as struct rgbColor!
             mg->colorsUsed);
#endif
#ifndef COLOR32
if (useTransparency)
    {
    // First palette color is assumed to be background/transparent, so
    // that's the only one we need in the parallel array opacities[].
    png_byte opacities[] = {0};
    int num_opacities = ArraySize(opacities);
    png_color_16p nonPalette_opacities_values = NULL; // n/a for us, we're using palette
    png_set_tRNS(png, info, opacities, num_opacities, nonPalette_opacities_values);
    }
#endif

// Write header/params, write pixels, close and clean up.
// PNG wants a 2D array of pointers to byte offsets into palette/colorMap.
// mg has a 1D array of byte offsets.  Make row pointers for PNG:

png_byte **row_pointers = needMem(mg->height * sizeof(png_byte *));
int i;
for (i = 0;  i < mg->height;  i++)
    row_pointers[i] = (unsigned char *)&(mg->pixels[i*mg->width]);
png_set_rows(png, info, row_pointers);
png_write_png(png, info, PNG_TRANSFORM_IDENTITY, // no transform
	      NULL); // unused as of PNG 1.2
png_destroy_write_struct(&png, &info);
return TRUE;
}
Beispiel #18
0
///////////////////////////////////////////////////////////////////////
// code based on example code from
// http://zarb.org/~gc/html/libpng.html  
///////////////////////////////////////////////////////////////////////
void FIELD_2D::readPNG(string filename)
{
  cout << " Reading in PNG file " << filename.c_str() << endl;

  int width, height;
  png_structp png_ptr;
  png_infop info_ptr;
  png_byte color_type;
  png_byte bit_depth;

  int number_of_passes;
  png_bytep* row_pointers;
  png_byte header[8];    // 8 is the maximum size that can be checked

  // open file and test for it being a png 
  FILE *fp = fopen(filename.c_str(), "rb");
  if (fp == NULL)
  {
    printf("[read_png_file] File %s could not be opened for reading\n", filename.c_str());
    exit(0);
  }
  fread(header, 1, 8, fp);
  if (png_sig_cmp(header, 0, 8))
    printf("[read_png_file] File %s is not recognized as a PNG file\n", filename.c_str());

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

  if (!png_ptr)
    printf("[read_png_file] png_create_read_struct failed\n");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    printf("[read_png_file] png_create_info_struct failed\n");

  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[read_png_file] Error during init_io\n");

  png_init_io(png_ptr, fp);
  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);
  color_type = png_get_color_type(png_ptr, info_ptr);
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);

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

  // read file
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[read_png_file] Error during read_image\n");

  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for (int y = 0; y < height; y++)
    row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));

  png_read_image(png_ptr, row_pointers);
  fclose(fp);

  // push the data into the member variables
  _xRes = width;
  _yRes = height;
  _totalCells = _xRes * _yRes;

  if (_data) delete[] _data;
  _data = new float[_totalCells];

  if (color_type == PNG_COLOR_TYPE_GRAY)
  {
    cout << " PNG color type is gray" << endl;
    for (int y = 0; y < _yRes; y++)
      for (int x = 0; x < _xRes; x++)
        (*this)(x,y) = row_pointers[height - 1 - y][x] / 255.0;
  }
  else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  {
    cout << " PNG color type is gray with alpha" << endl;
    for (int y = 0; y < _yRes; y++)
      for (int x = 0; x < _xRes; x++)
        (*this)(x,y) = row_pointers[height - 1 - y][2 * x] / 255.0;
  }
  else if (color_type == PNG_COLOR_TYPE_RGB)
  {
    cout << " PNG color type is RGB" << endl;
    for (int y = 0; y < _yRes; y++)
      for (int x = 0; x < _xRes; x++)
      {
        float r = (float)row_pointers[height - 1 - y][3 * x] / 255.0;
        float g = (float)row_pointers[height - 1 - y][3 * x + 1] / 255.0;
        float b = (float)row_pointers[height - 1 - y][3 * x + 2] / 255.0;
        (*this)(x,y) = (r + g + b) / 3.0;
      }
  }
  else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  {
    cout << " PNG color type is RGB with alpha" << endl;
    for (int y = 0; y < _yRes; y++)
      for (int x = 0; x < _xRes; x++)
      {
        float r = (float)row_pointers[height - 1 - y][4 * x] / 255.0;
        float g = (float)row_pointers[height - 1 - y][4 * x + 1] / 255.0;
        float b = (float)row_pointers[height - 1 - y][4 * x + 2] / 255.0;
        (*this)(x,y) = (r + g + b) / 3.0;
      }
  }
  else
  {
    cout << " PNG color type " << (int)color_type << " is unsupported! " << endl;
    exit(0);
  }

  for (int y = 0; y < height; y++)
    free(row_pointers[y]);
  free(row_pointers);
}
Beispiel #19
0
HBITMAP PngByteToBmpHandle(VBuf *vbuf)
{
	png_struct	*png  = NULL;
	png_info	*info = NULL;
	HBITMAP		hBmp  = NULL;
	BITMAPINFO	*bmi  = NULL;
	png_byte	**row = NULL;
	BYTE		*data = NULL;
	HWND		hWnd = ::GetDesktopWindow();
	HDC			hDc   = NULL;
	int			line_size, aligned_line_size, header_size;
	VBuf		bmpVbuf;

	if (vbuf->Size() < PNG_SIG_SIZE || !png_check_sig(vbuf->Buf(), PNG_SIG_SIZE)) return NULL;

	if (!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) return NULL;
	if (!(info = png_create_info_struct(png))) goto END;

	if (setjmp(png_jmpbuf(png))) goto END;

	png_set_user_limits(png, 15000, 10000); // 15,000 * 10,000 pix
	png_set_read_fn(png, (void *)vbuf, (png_rw_ptr)png_vbuf_rfunc);
	png_read_png(png, info, PNG_TRANSFORM_BGR, NULL);

	if (info->bit_depth > 8) goto END; // not support

	line_size = info->width * info->channels * ALIGN_SIZE(info->bit_depth, 8) / 8;
	aligned_line_size = ALIGN_SIZE(line_size, 4);
	header_size = sizeof(BITMAPV5HEADER) + sizeof(RGBQUAD) * info->num_palette;

	if (!bmpVbuf.AllocBuf(header_size + aligned_line_size * info->height)) goto END;
	bmi = (BITMAPINFO *)bmpVbuf.Buf();

	bmi->bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	bmi->bmiHeader.biSizeImage   = aligned_line_size * info->height;
	bmi->bmiHeader.biWidth       = info->width;
	bmi->bmiHeader.biHeight      = -(int)info->height;
	bmi->bmiHeader.biPlanes      = 1;
	bmi->bmiHeader.biCompression = BI_RGB;

	if (info->color_type == PNG_COLOR_TYPE_PALETTE) {
		bmi->bmiHeader.biBitCount = info->bit_depth;
		bmi->bmiHeader.biClrUsed = info->num_palette;
		for (int i=0; i < info->num_palette; i++) {
			bmi->bmiColors[i].rgbRed	= info->palette[i].red;
			bmi->bmiColors[i].rgbGreen	= info->palette[i].green;
			bmi->bmiColors[i].rgbBlue	= info->palette[i].blue;
		}
	}
	else  {
		bmi->bmiHeader.biBitCount = info->bit_depth * info->channels;
		if (info->channels == 4) {
			bmi->bmiHeader.biSize	= sizeof(BITMAPV5HEADER);
			BITMAPV5HEADER *bm5		= (BITMAPV5HEADER*)bmi;
			bm5->bV5Compression		= BI_BITFIELDS;
			bm5->bV5RedMask			= 0x00FF0000;
			bm5->bV5GreenMask		= 0x0000FF00;
			bm5->bV5BlueMask		= 0x000000FF;
			bm5->bV5AlphaMask		= 0xFF000000;
		}
	}

	if (!(row = png_get_rows(png, info))) goto END;

	data = bmpVbuf.Buf() + header_size;
	u_int i;
	for (i=0; i < info->height; i++) {
		memcpy(data + aligned_line_size * i, row[i], line_size);
	}

	if (!(hDc = ::GetDC(hWnd))) goto END;
	hBmp = ::CreateDIBitmap(hDc, (BITMAPINFOHEADER *)bmi, CBM_INIT, data, bmi, DIB_RGB_COLORS);
	if (hDc) ::ReleaseDC(hWnd, hDc);

END:
	png_destroy_read_struct(&png, &info, 0);
	return	hBmp;
}
Beispiel #20
0
///////////////////////////////////////////////////////////////////////
// code based on example code from
// http://zarb.org/~gc/html/libpng.html  
///////////////////////////////////////////////////////////////////////
void FIELD_2D::writePNG(string filename)
{
  cout << " Writing out PNG file " << filename.c_str() << endl;

  int width = _xRes; 
  int height = _yRes;

  // copy image data into pointers
  png_bytep* row_pointers;
  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for (int y = 0; y < height; y++)
    row_pointers[y] = (png_byte*) malloc(sizeof(png_byte) * width);

  for (int y = 0; y < height; y++)
    for (int x = 0; x < width; x++)
    {
      float value = (*this)(x,y) * 255;
      value = (value > 255)  ? 255 : value;
      value = (value < 0)  ? 0 : value;
      row_pointers[height - 1 - y][x] = (unsigned char)value;
    }

  png_structp png_ptr;
  png_infop info_ptr;
  png_byte color_type = PNG_COLOR_TYPE_GRAY;
  png_byte bit_depth = 8;

  // create file
  FILE *fp = fopen(filename.c_str(), "wb");
  if (fp == NULL)
    printf("[write_png_file] File %s could not be opened for writing\n", filename.c_str());

  // initialize stuff
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    printf("[write_png_file] png_create_write_struct failed\n");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    printf("[write_png_file] png_create_info_struct failed\n");

  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during init_io\n");

  png_init_io(png_ptr, fp);

  // write header
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during writing header\n");

  png_set_IHDR(png_ptr, info_ptr, width, height,
       bit_depth, color_type, PNG_INTERLACE_NONE,
       PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  // write bytes
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during writing bytes\n");

  png_write_image(png_ptr, row_pointers);
  
  // end write
  if (setjmp(png_jmpbuf(png_ptr)))
    printf("[write_png_file] Error during end of write\n");

  png_write_end(png_ptr, NULL);

  // cleanup heap allocation
  for (int y=0; y<height; y++)
    free(row_pointers[y]);
  free(row_pointers);

  fclose(fp);
}
Beispiel #21
0
Texture* PNGLoader::load(string fileName, bool mipMaps)
{
	png_structp png_ptr;
	png_infop info_ptr;
	unsigned long sig_read = 0;
	int bit_depth, color_type, interlace_type;
	png_uint_32 width, height;
	unsigned short components;

	// Load file from disk
	FILE* file = fopen(fileName.c_str(), "rb");

	if (file == NULL)
		return NULL;

	// Create png read and info structures
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	if (png_ptr == NULL)
	{
		fclose(file);
		return NULL;
	}

	info_ptr = png_create_info_struct(png_ptr);

	if (info_ptr == NULL)
	{
		fclose(NULL);
		return NULL;
	}

	// Set up the function to read bytes from file stream
	png_set_read_fn(png_ptr, file, png_read_file_data);
	png_set_sig_bytes(png_ptr, sig_read);
	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*) &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);

	// Adjust image format
	if (color_type == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb(png_ptr);

	if (bit_depth < 8)
	{
		if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
			png_set_gray_1_2_4_to_8(png_ptr);
		else
			png_set_packing(png_ptr);
	}

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

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

	if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png_ptr);

	png_read_update_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, (png_uint_32*) &width, (png_uint_32*)&height, &bit_depth, &color_type, NULL, NULL, NULL);

	if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	{
#ifdef __BIG_ENDIAN__
		png_set_swap_alpha(png_ptr);
#else
		png_set_bgr(png_ptr);
#endif
	}

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

	// Store the components amount
	if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
		components = 32;
	else
		components = 24;

	// Start reading from buffer
	png_byte** row = new png_byte*[height];
	png_byte* buffer = new png_byte[width * height * (components / 8)];
	png_byte* it = buffer;

	for (png_uint_32 i = 0; i < height; i++)
	{
		row[i] = it;
		it += width * (components / 8);
	}

	png_read_image(png_ptr, row);
	png_read_end(png_ptr, NULL);

	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	Texture* tex = new Texture(buffer, width, height, components, mipMaps);

	delete [] row;
	delete [] buffer;

	fclose(file);

	return tex;
}
Beispiel #22
0
/* Writes a non-interlaced, no-frills PNG, taking the usual save_xyz
 *  parameters.  Returns non-zero on error.
 */
bool _al_save_png_f(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp)
{
   jmp_buf jmpbuf;
   png_structp png_ptr = NULL;
   png_infop info_ptr = NULL;
   int colour_type;

   /* Create and initialize the png_struct with the
    * desired error handler functions.
    */
   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                     (void *)NULL, NULL, NULL);
   if (!png_ptr)
      goto Error;

   /* Allocate/initialize the image information data. */
   info_ptr = png_create_info_struct(png_ptr);
   if (!info_ptr)
      goto Error;

   /* Set error handling. */
   if (setjmp(jmpbuf)) {
      goto Error;
   }
   png_set_error_fn(png_ptr, jmpbuf, user_error_fn, NULL);

   /* Use packfile routines. */
   png_set_write_fn(png_ptr, fp, (png_rw_ptr) write_data, 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.
    */
   colour_type = PNG_COLOR_TYPE_RGB_ALPHA;

   /* Set compression level. */
   png_set_compression_level(png_ptr, _al_png_compression_level);

   png_set_IHDR(png_ptr, info_ptr,
                al_get_bitmap_width(bmp), al_get_bitmap_height(bmp),
                8, colour_type,
                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                PNG_FILTER_TYPE_BASE);

   /* Optionally write comments into the image ... Nah. */

   /* Write the file header information. */
   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.
    */
   if (!save_rgba(png_ptr, bmp))
      goto Error;

   png_write_end(png_ptr, info_ptr);

   png_destroy_write_struct(&png_ptr, &info_ptr);

   return true;

 Error:

   if (png_ptr) {
      if (info_ptr)
         png_destroy_write_struct(&png_ptr, &info_ptr);
      else
         png_destroy_write_struct(&png_ptr, NULL);
   }

   return false;
}
Beispiel #23
0
static int
png_load_file(FILE *infile, unsigned long *pWidth,
              unsigned long *pHeight, unsigned char *red,
              unsigned char *green, unsigned char *blue,
              int *pChannels, unsigned long *pRowbytes,
              unsigned char **image_data)
{
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    int bit_depth, color_type;
    png_uint_32 width, height;
    unsigned char sig[8];
    png_color_16p pBackground;
    double gamma;
    png_uint_32 i, rowbytes;
    png_bytepp row_pointers = NULL;

    fread(sig, 1, 8, infile);
    if (png_sig_cmp(sig, 0, 8))
        return 1;               /* bad signature */

    png_ptr =
        png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 4;               /* out of memory */

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 4;               /* out of memory */
    }

    /* setjmp() must be called in every function that calls a PNG-reading
     * libpng function */

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 2;
    }

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

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

    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
                 &color_type, NULL, NULL, NULL);
    if (pWidth)
        *pWidth = width;
    if (pHeight)
        *pHeight = height;

    if (red && green && blue) {
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {

            png_get_bKGD(png_ptr, info_ptr, &pBackground);

            if (bit_depth == 16) {
                *red = pBackground->red >> 8;
                *green = pBackground->green >> 8;
                *blue = pBackground->blue >> 8;
            } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
                if (bit_depth == 1)
                    *red = *green = *blue = pBackground->gray ? 255 : 0;
                else if (bit_depth == 2)
                    *red = *green = *blue = (255 / 3) * pBackground->gray;
                else            /* bit_depth == 4 */
                    *red = *green = *blue = (255 / 15) * pBackground->gray;
            } else {
                *red = (unsigned char) pBackground->red;
                *green = (unsigned char) pBackground->green;
                *blue = (unsigned char) pBackground->blue;
            }
        }
Beispiel #24
0
// Reads the header and initializes the output fields, if not NULL.
//
// @param stream Input data. Will be read to get enough information to properly
//      setup the codec.
// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
//      If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
//      expected to continue to own it for the lifetime of the png_ptr.
// @param outCodec Optional output variable.  If non-NULL, will be set to a new
//      SkPngCodec on success.
// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
//      png_structp on success.
// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
//      png_infop on success;
// @return true on success, in which case the caller is responsible for calling
//      png_destroy_read_struct(png_ptrp, info_ptrp).
//      If it returns false, the passed in fields (except stream) are unchanged.
static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec,
                        png_structp* png_ptrp, png_infop* info_ptrp) {
    // The image is known to be a PNG. Decode enough to know the SkImageInfo.
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
                                                 sk_error_fn, sk_warning_fn);
    if (!png_ptr) {
        return false;
    }

    AutoCleanPng autoClean(png_ptr);

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == nullptr) {
        return false;
    }

    autoClean.setInfoPtr(info_ptr);

    // FIXME: Could we use the return value of setjmp to specify the type of
    // error?
    if (setjmp(png_jmpbuf(png_ptr))) {
        return false;
    }

    png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);

#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
    // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
    // This needs to be installed before we read the png header.  Android may store ninepatch
    // chunks in the header.
    if (chunkReader) {
        png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
        png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
    }
#endif

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

    // Tell libpng to strip 16 bit/color files down to 8 bits/color.
    // TODO: Should we handle this in SkSwizzler?  Could this also benefit
    //       RAW decodes?
    if (bitDepth == 16) {
        SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
        png_set_strip_16(png_ptr);
    }

    // Now determine the default colorType and alphaType and set the required transforms.
    // Often, we depend on SkSwizzler to perform any transforms that we need.  However, we
    // still depend on libpng for many of the rare and PNG-specific cases.
    SkEncodedInfo::Color color;
    SkEncodedInfo::Alpha alpha;
    switch (encodedColorType) {
        case PNG_COLOR_TYPE_PALETTE:
            // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
            // byte into separate bytes (useful for paletted and grayscale images).
            if (bitDepth < 8) {
                // TODO: Should we use SkSwizzler here?
                png_set_packing(png_ptr);
            }

            color = SkEncodedInfo::kPalette_Color;
            // Set the alpha depending on if a transparency chunk exists.
            alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
                    SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
            break;
        case PNG_COLOR_TYPE_RGB:
            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                // Convert to RGBA if transparency chunk exists.
                png_set_tRNS_to_alpha(png_ptr);
                color = SkEncodedInfo::kRGBA_Color;
                alpha = SkEncodedInfo::kBinary_Alpha;
            } else {
                color = SkEncodedInfo::kRGB_Color;
                alpha = SkEncodedInfo::kOpaque_Alpha;
            }
            break;
        case PNG_COLOR_TYPE_GRAY:
            // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
            if (bitDepth < 8) {
                // TODO: Should we use SkSwizzler here?
                png_set_expand_gray_1_2_4_to_8(png_ptr);
            }

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                png_set_tRNS_to_alpha(png_ptr);
                color = SkEncodedInfo::kGrayAlpha_Color;
                alpha = SkEncodedInfo::kBinary_Alpha;
            } else {
                color = SkEncodedInfo::kGray_Color;
                alpha = SkEncodedInfo::kOpaque_Alpha;
            }
            break;
        case PNG_COLOR_TYPE_GRAY_ALPHA:
            color = SkEncodedInfo::kGrayAlpha_Color;
            alpha = SkEncodedInfo::kUnpremul_Alpha;
            break;
        case PNG_COLOR_TYPE_RGBA:
            color = SkEncodedInfo::kRGBA_Color;
            alpha = SkEncodedInfo::kUnpremul_Alpha;
            break;
        default:
            // All the color types have been covered above.
            SkASSERT(false);
            color = SkEncodedInfo::kRGBA_Color;
            alpha = SkEncodedInfo::kUnpremul_Alpha;
    }

    int numberPasses = png_set_interlace_handling(png_ptr);

    autoClean.release();
    if (png_ptrp) {
        *png_ptrp = png_ptr;
    }
    if (info_ptrp) {
        *info_ptrp = info_ptr;
    }

    if (outCodec) {
        sk_sp<SkColorSpace> colorSpace = read_color_space(png_ptr, info_ptr);
        if (!colorSpace) {
            // Treat unmarked pngs as sRGB.
            colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
        }

        SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8);
        SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace);

        if (SkEncodedInfo::kOpaque_Alpha == alpha) {
            png_color_8p sigBits;
            if (png_get_sBIT(png_ptr, info_ptr, &sigBits)) {
                if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
                    // Recommend a decode to 565 if the sBIT indicates 565.
                    imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType);
                }
            }
        }

        if (1 == numberPasses) {
            *outCodec = new SkPngNormalCodec(encodedInfo, imageInfo, stream,
                    chunkReader, png_ptr, info_ptr, bitDepth);
        } else {
            *outCodec = new SkPngInterlacedCodec(encodedInfo, imageInfo, stream,
                    chunkReader, png_ptr, info_ptr, bitDepth, numberPasses);
        }
    }

    return true;
}
Beispiel #25
0
int read_header(const char *filename, dt_imageio_png_t *png)
{
  png->f = fopen(filename, "rb");

  if(!png->f) return 1;

#define NUM_BYTES_CHECK (8)

  png_byte dat[NUM_BYTES_CHECK];

  size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f);

  if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK))
  {
    fclose(png->f);
    return 1;
  }

  png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if(!png->png_ptr)
  {
    fclose(png->f);
    return 1;
  }

  png->info_ptr = png_create_info_struct(png->png_ptr);
  if(!png->info_ptr)
  {
    fclose(png->f);
    png_destroy_read_struct(&png->png_ptr, NULL, NULL);
    return 1;
  }

  if(setjmp(png_jmpbuf(png->png_ptr)))
  {
    fclose(png->f);
    png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
    return 1;
  }

  png_init_io(png->png_ptr, png->f);

  // we checked some bytes
  png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK);

  // image info
  png_read_info(png->png_ptr, png->info_ptr);

  png->bit_depth = png_get_bit_depth(png->png_ptr, png->info_ptr);
  png->color_type = png_get_color_type(png->png_ptr, png->info_ptr);

  // image input transformations

  // palette => rgb
  if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr);

  // 1, 2, 4 bit => 8 bit
  if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8)
  {
    png_set_expand_gray_1_2_4_to_8(png->png_ptr);
    png->bit_depth = 8;
  }

  // strip alpha channel
  if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr);

  // grayscale => rgb
  if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png->png_ptr);

  // reflect changes
  png_read_update_info(png->png_ptr, png->info_ptr);

  // png->bytespp = 3*bit_depth/8;
  png->width = png_get_image_width(png->png_ptr, png->info_ptr);
  png->height = png_get_image_height(png->png_ptr, png->info_ptr);

#undef NUM_BYTES_CHECK

  return 0;
}
Beispiel #26
0
Py::Object
Image::write_png(const Py::Tuple& args)
{
  //small memory leak in this function - JDH 2004-06-08
  _VERBOSE("Image::write_png");

  args.verify_length(1);

  FILE *fp = NULL;
  Py::Object py_fileobj = Py::Object(args[0]);
  if (py_fileobj.isString()) {
    std::string fileName = Py::String(py_fileobj);
    const char *file_name = fileName.c_str();
    if ((fp = fopen(file_name, "wb")) == NULL)
      throw Py::RuntimeError( Printf("Could not open file %s", file_name).str() );
  }
  else {
    PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write");
    if (!(write_method && PyCallable_Check(write_method))) {
      Py_XDECREF(write_method);
      throw Py::TypeError("Object does not appear to be a path or a Python file-like object");
    }
    Py_XDECREF(write_method);
  }

  png_structp png_ptr;
  png_infop info_ptr;
  struct png_color_8_struct sig_bit;
  png_uint_32 row=0;

  //todo: allocate on heap
  png_bytep *row_pointers = NULL;
  std::pair<agg::int8u*,bool> bufpair;
  bufpair.first = NULL;
  bufpair.second = false;

  try {
    row_pointers = new png_bytep[rowsOut];
    if (!row_pointers)
      throw Py::RuntimeError("Out of memory");

    bufpair = _get_output_buffer();
    for (row = 0; row < rowsOut; ++row)
      row_pointers[row] = bufpair.first + row * colsOut * 4;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL)
      throw Py::RuntimeError("Could not create write struct");

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
      throw Py::RuntimeError("Could not create info struct");

    if (setjmp(png_ptr->jmpbuf))
      throw Py::RuntimeError("Error building image");

    if (fp) {
      png_init_io(png_ptr, fp);
    } else {
      png_set_write_fn(png_ptr, (void*)py_fileobj.ptr(),
		       &write_png_data, &flush_png_data);
    }
    png_set_IHDR(png_ptr, info_ptr,
                 colsOut, rowsOut, 8,
                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    // this a a color image!
    sig_bit.gray = 0;
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    /* if the image has an alpha channel then */
    sig_bit.alpha = 8;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    png_write_info(png_ptr, info_ptr);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);
  } catch (...) {
    if (bufpair.second) delete [] bufpair.first;
    if (fp) fclose(fp);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    delete [] row_pointers;
    throw;
  }

  if (fp) fclose(fp);
  delete [] row_pointers;
  if (bufpair.second) delete [] bufpair.first;

  return Py::Object();
}
Beispiel #27
0
int writePng( PIXEL ** matrix, int width, int height) { 
        png_structp     png_ptr;
        png_infop       info_ptr;
        png_bytep * row_pointers;
        int i,j,x,y;


        /* create file */
        FILE *fp = fopen("terrain.png", "wb");
        if (!fp)
                //abort_("[write_png_file] File %s could not be opened for writing", "decoded.png");
		return -1;


        /* 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");
		return -1;

        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
                //abort_("[write_png_file] png_create_info_struct failed");
		return -1;

        if (setjmp(png_jmpbuf(png_ptr)))
                //abort_("[write_png_file] Error during init_io");
		return -1;

        png_init_io(png_ptr, fp);

        /* write header */
        if (setjmp(png_jmpbuf(png_ptr)))
                //abort_("[write_png_file] Error during writing header");
		return -1;

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

        png_write_info(png_ptr, info_ptr);

    
        /* init buffer */
        row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height );
        for (y=0; y<height; y++)
                row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));

        /* COPY BUFFER */
        if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
                //abort_("[process_file] input file is PNG_COLOR_TYPE_RGB but must be PNG_COLOR_TYPE_RGBA "
                  //     "(lacks the alpha channel)");
		return -1;

        if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA)
                //abort_("[process_file] color_type of input file must be PNG_COLOR_TYPE_RGBA (%d) (is %d)",
                  //     PNG_COLOR_TYPE_RGBA, png_get_color_type(png_ptr, info_ptr));
		return -1;

        for (y=0; y<height; y++) {
                png_byte* row = row_pointers[y];
                for (x=0; x<width; x++) {
			//std::cout << x << " " << y <<"\n";
                        png_byte* ptr = &(row[x*4]);

                        ptr[0] = matrix[x][y].Red;
                        ptr[1] = matrix[x][y].Green;
                        ptr[2] = matrix[x][y].Blue;
                        ptr[3] = 255;
                }
        }

        /* write bytes */
        if (setjmp(png_jmpbuf(png_ptr)))
                //abort_("[write_png_file] Error during writing bytes");
		return -1;

        png_write_image(png_ptr, row_pointers);


        /* end write */
        if (setjmp(png_jmpbuf(png_ptr)))
                //abort_("[write_png_file] Error during end of write");
		return -1;

        png_write_end(png_ptr, NULL);

        /* cleanup heap allocation */
        for (y=0; y<height; y++)
                free(row_pointers[y]);
        free(row_pointers);

        fclose(fp);
}
Beispiel #28
0
Py::Object
_image_module::readpng(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;

  // convert misc color types to rgb for simplicity
  if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
      info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png_ptr);
  else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png_ptr);


  int bit_depth = info_ptr->bit_depth;
  if (bit_depth == 16)  png_set_strip_16(png_ptr);


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

  bool rgba = info_ptr->color_type == PNG_COLOR_TYPE_RGBA;
  if ( (info_ptr->color_type != PNG_COLOR_TYPE_RGB) && !rgba) {
    std::cerr << "Found color type " << (int)info_ptr->color_type  << std::endl;
    throw Py::RuntimeError("_image_module::readpng: cannot handle color_type");
  }

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



  int dimensions[3];
  dimensions[0] = height;  //numrows
  dimensions[1] = width;   //numcols
  dimensions[2] = 4;

  PyArrayObject *A = (PyArrayObject *) PyArray_FromDims(3, dimensions, PyArray_FLOAT);


  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 = (rgba) ? &(row[x*4]) : &(row[x*3]);
      size_t offset = y*A->strides[0] + x*A->strides[1];
      //if ((y<10)&&(x==10)) std::cout << "r = " << ptr[0] << " " << ptr[0]/255.0 << std::endl;
      *(float*)(A->data + offset + 0*A->strides[2]) = ptr[0]/255.0;
      *(float*)(A->data + offset + 1*A->strides[2]) = ptr[1]/255.0;
      *(float*)(A->data + offset + 2*A->strides[2]) = ptr[2]/255.0;
      *(float*)(A->data + offset + 3*A->strides[2]) = rgba ? ptr[3]/255.0 : 1.0;
    }
  }

  //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);
}
Beispiel #29
0
/* TODO: I wonder why this function ALWAYS returns 0 */
int loadPNG(ePtr<gPixmap> &result, const char *filename, int accel)
{
	if (pixmapFromTable(result, filename) == 0)
		return 0;

	CFile fp(filename, "rb");

	if (!fp)
	{
		eDebug("[ePNG] couldn't open %s", filename );
		return 0;
	}
	{
		__u8 header[8];
		if (!fread(header, 8, 1, fp))
		{
			eDebug("[ePNG] failed to get png header");
			return 0;
		}
		if (png_sig_cmp(header, 0, 8))
		{
			eDebug("[ePNG] header size mismatch");
			return 0;
		}
	}
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (!png_ptr)
	{
		eDebug("[ePNG] failed to create read struct");
		return 0;
	}
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		eDebug("[ePNG] failed to create info struct");
		png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
		return 0;
	}
	png_infop end_info = png_create_info_struct(png_ptr);
	if (!end_info)
	{
		eDebug("[ePNG] failed to create end info struct");
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		return 0;
	}
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		eDebug("[ePNG] png setjump failed or activated");
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		result = 0;
		return 0;
	}
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);
	png_read_info(png_ptr, info_ptr);

	png_uint_32 width, height;
	int bit_depth;
	int color_type;
	int interlace_type;
	int channels;
	int trns;

	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, 0, 0);
	channels = png_get_channels(png_ptr, info_ptr);
	trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
	//eDebug("[ePNG] %s: before %dx%dx%dbpcx%dchan coltyp=%d", filename, (int)width, (int)height, bit_depth, channels, color_type);

	/*
	 * gPixmaps use 8 bits per channel. rgb pixmaps are stored as abgr.
	 * So convert 1,2 and 4 bpc to 8bpc images that enigma can blit
	 * so add 'empty' alpha channel
	 * Expand G+tRNS to GA, RGB+tRNS to RGBA
	 */
	if (bit_depth == 16)
		png_set_strip_16(png_ptr);
	if (bit_depth < 8)
		png_set_packing (png_ptr);

	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_expand_gray_1_2_4_to_8(png_ptr);
	if (color_type == PNG_COLOR_TYPE_GRAY && trns)
		png_set_tRNS_to_alpha(png_ptr);
	if ((color_type == PNG_COLOR_TYPE_GRAY && trns) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(png_ptr);
		png_set_bgr(png_ptr);
	}

	if (color_type == PNG_COLOR_TYPE_RGB) {
		if (trns)
			png_set_tRNS_to_alpha(png_ptr);
		else
			png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
	}

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

	// Update the info structures after the transformations take effect
	if (interlace_type != PNG_INTERLACE_NONE)
		png_set_interlace_handling(png_ptr);  // needed before read_update_info()
	png_read_update_info (png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
	channels = png_get_channels(png_ptr, info_ptr);

	result = new gPixmap(width, height, bit_depth * channels, pixmapDisposed, accel);
	gUnmanagedSurface *surface = result->surface;

	png_bytep *rowptr = new png_bytep[height];
	for (unsigned int i = 0; i < height; i++)
		rowptr[i] = ((png_byte*)(surface->data)) + i * surface->stride;
	png_read_image(png_ptr, rowptr);

	delete [] rowptr;

	int num_palette = -1, num_trans = -1;
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
			png_color *palette;
			png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
			if (num_palette)
				surface->clut.data = new gRGB[num_palette];
			else
				surface->clut.data = 0;
			surface->clut.colors = num_palette;

			for (int i = 0; i < num_palette; i++) {
				surface->clut.data[i].a = 0;
				surface->clut.data[i].r = palette[i].red;
				surface->clut.data[i].g = palette[i].green;
				surface->clut.data[i].b = palette[i].blue;
			}
			if (trns) {
				png_byte *trans;
				png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0);
				for (int i = 0; i < num_trans; i++)
					surface->clut.data[i].a = 255 - trans[i];
				for (int i = num_trans; i < num_palette; i++)
					surface->clut.data[i].a = 0;
			}
		}
		else {
			surface->clut.data = 0;
			surface->clut.colors = 0;
		}
		surface->clut.start = 0;
	}
	pixmapToTable(result, filename);
	//eDebug("[ePNG] %s: after  %dx%dx%dbpcx%dchan coltyp=%d cols=%d trans=%d", filename, (int)width, (int)height, bit_depth, channels, color_type, num_palette, num_trans);

	png_read_end(png_ptr, end_info);
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	return 0;
}
Beispiel #30
0
void pngRead(const std::string& file, ImageBuffer<RGBA8>& image)
{
	// open file
	FILE* fp = nullptr;
	try
	{
		fp = fopen(file.c_str(), "rb");		
		if(!fp)
			throw;

		// check if it's a png, 8 is the maximum size that can be checked
		png_byte header[8];
		fread(header, 1, 8, fp);
		if(png_sig_cmp(header, 0, 8))
			throw;

		// try to create read struct
		png_structp pStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
		if(!pStruct)
			throw;

		// try to create info struct
		png_infop pInfo = png_create_info_struct(pStruct);
		if(!pInfo)
			throw;

		// read info
		png_init_io(pStruct, fp);
		png_set_sig_bytes(pStruct, 8);
		png_read_info(pStruct, pInfo);

		int width = png_get_image_width(pStruct, pInfo);
		int height = png_get_image_height(pStruct, pInfo);
		png_byte colorType = png_get_color_type(pStruct, pInfo);
		png_byte bitDepth = png_get_bit_depth(pStruct, pInfo);
		png_byte channels = png_get_channels(pStruct, pInfo);

		png_read_update_info(pStruct, pInfo);

		// read data	
		std::vector<std::vector<png_byte>> rowBytes(height);
		std::vector<png_byte*> rowPointers(height);
		png_size_t rowByteCount = png_get_rowbytes(pStruct, pInfo);
		for(int y = 0; y < height; y++)
		{
			rowBytes[y].resize(rowByteCount);
			rowPointers[y] = rowBytes[y].data();
		}
	
		png_read_image(pStruct, rowPointers.data());

		if(colorType == PNG_COLOR_TYPE_RGB)
		{
			image.setSize(width, height);
			for(int y = 0; y < height; y++)
			{
				png_byte* pBytes = rowPointers[y];
				for(int x = 0; x < width; x++, pBytes += 3)
				{
					image(x, y) = {pBytes[0], pBytes[1], pBytes[2], 255};
				}
			}
		}
		else if(colorType == PNG_COLOR_TYPE_RGBA)
		{
			image.setSize(width, height);
			for(int y = 0; y < height; y++)
			{
				png_byte* pBytes = rowPointers[y];
				for(int x = 0; x < width; x++, pBytes += 4)
				{
					image(x, y) = {pBytes[0], pBytes[1], pBytes[2], pBytes[3]};
				}
			}
		}
		else
		{
			throw;
		}
	}
	catch(...)
	{
		// File couldn't be loaded or read.
		assert(0);
		if(fp)
			fclose(fp);
	}
}