| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951 | /* SLiM - Simple Login Manager   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>   Copyright (C) 2012	Nobuhiro Iwamatsu <iwamatsu@nigauri.org>   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   The following code has been adapted and extended from   xplanet 1.0.1, Copyright (C) 2002-04 Hari Nair <hari@alumni.caltech.edu>*/#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;#include "image.h"extern "C" {	#include <jpeglib.h>	#include <png.h>}Image::Image() : width(0), height(0), area(0),rgb_data(NULL), png_alpha(NULL), quality_(80) {}Image::Image(const int w, const int h, const unsigned char *rgb, const unsigned char *alpha) :width(w), height(h), area(w*h), quality_(80) {	width = w;	height = h;	area = w * h;	rgb_data = (unsigned char *) malloc(3 * area);	memcpy(rgb_data, rgb, 3 * area);	if (alpha == NULL) {		png_alpha = NULL;	} else {		png_alpha = (unsigned char *) malloc(area);		memcpy(png_alpha, alpha, area);	}}Image::~Image() {	free(rgb_data);	free(png_alpha);}boolImage::Read(const char *filename) {	char buf[4];	unsigned char *ubuf = (unsigned char *) buf;	int success = 0;	FILE *file;	file = fopen(filename, "rb");	if (file == NULL)		return(false);	/* see what kind of file we have */	fread(buf, 1, 4, file);	fclose(file);	if ((ubuf[0] == 0x89) && !strncmp("PNG", buf+1, 3))		success = readPng(filename, &width, &height, &rgb_data, &png_alpha);	else if ((ubuf[0] == 0xff) && (ubuf[1] == 0xd8))		success = readJpeg(filename, &width, &height, &rgb_data);	else {		fprintf(stderr, "Unknown image format\n");		success = 0;	}	return(success == 1);}voidImage::Reduce(const int factor) {	if (factor < 1)		return;	int scale = 1;	for (int i = 0; i < factor; i++)		scale *= 2;	double scale2 = scale*scale;	int w = width / scale;	int h = height / scale;	int new_area = w * h;	unsigned char *new_rgb = (unsigned char *) malloc(3 * new_area);	memset(new_rgb, 0, 3 * new_area);	unsigned char *new_alpha = NULL;	if (png_alpha != NULL) {		new_alpha = (unsigned char *) malloc(new_area);		memset(new_alpha, 0, new_area);	}	int ipos = 0;	for (int j = 0; j < height; j++) {		int js = j / scale;		for (int i = 0; i < width; i++) {			int is = i/scale;			for (int k = 0; k < 3; k++)				new_rgb[3*(js * w + is) + k] += static_cast<unsigned char> ((rgb_data[3*ipos + k] + 0.5) / scale2);			if (png_alpha != NULL)				new_alpha[js * w + is] += static_cast<unsigned char> (png_alpha[ipos]/scale2);			ipos++;		}	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = new_alpha;	width = w;	height = h;	area = w * h;}voidImage::Resize(const int w, const int h) {	if (width==w && height==h){		return;	}	int new_area = w * h;	unsigned char *new_rgb = (unsigned char *) malloc(3 * new_area);	unsigned char *new_alpha = NULL;	if (png_alpha != NULL)		new_alpha = (unsigned char *) malloc(new_area);	const double scale_x = ((double) w) / width;	const double scale_y = ((double) h) / height;	int ipos = 0;	for (int j = 0; j < h; j++) {		const double y = j / scale_y;		for (int i = 0; i < w; i++) {			const double x = i / scale_x;			if (new_alpha == NULL)				getPixel(x, y, new_rgb + 3*ipos);			else				getPixel(x, y, new_rgb + 3*ipos, new_alpha + ipos);			ipos++;		}	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = new_alpha;	width = w;	height = h;	area = w * h;}/* Find the color of the desired point using bilinear interpolation. *//* Assume the array indices refer to the denter of the pixel, so each *//* pixel has corners at (i - 0.5, j - 0.5) and (i + 0.5, j + 0.5) */voidImage::getPixel(double x, double y, unsigned char *pixel) {	getPixel(x, y, pixel, NULL);}voidImage::getPixel(double x, double y, unsigned char *pixel, unsigned char *alpha) {	if (x < -0.5)		x = -0.5;	if (x >= width - 0.5)		x = width - 0.5;	if (y < -0.5)		y = -0.5;	if (y >= height - 0.5)		y = height - 0.5;	int ix0 = (int) (floor(x));	int ix1 = ix0 + 1;	if (ix0 < 0)		ix0 = width - 1;	if (ix1 >= width)		ix1 = 0;	int iy0 = (int) (floor(y));	int iy1 = iy0 + 1;	if (iy0 < 0)		iy0 = 0;	if (iy1 >= height)		iy1 = height - 1;	const double t = x - floor(x);	const double u = 1 - (y - floor(y));	double weight[4];	weight[1] = t * u;	weight[0] = u - weight[1];	weight[2] = 1 - t - u + weight[1];	weight[3] = t - weight[1];	unsigned char *pixels[4];	pixels[0] = rgb_data + 3 * (iy0 * width + ix0);	pixels[1] = rgb_data + 3 * (iy0 * width + ix1);	pixels[2] = rgb_data + 3 * (iy1 * width + ix0);	pixels[3] = rgb_data + 3 * (iy1 * width + ix1);	memset(pixel, 0, 3);	for (int i = 0; i < 4; i++) {		for (int j = 0; j < 3; j++)			pixel[j] += (unsigned char) (weight[i] * pixels[i][j]);	}	if (alpha != NULL) {		unsigned char pixels[4];		pixels[0] = png_alpha[iy0 * width + ix0];		pixels[1] = png_alpha[iy0 * width + ix1];		pixels[2] = png_alpha[iy0 * width + ix0];		pixels[3] = png_alpha[iy1 * width + ix1];		for (int i = 0; i < 4; i++)			*alpha = (unsigned char) (weight[i] * pixels[i]);	}}/* Merge the image with a background, taking care of the * image Alpha transparency. (background alpha is ignored). * The images is merged on position (x, y) on the * background, the background must contain the image. */void Image::Merge(Image* background, const int x, const int y) {	if (x + width > background->Width()|| y + height > background->Height())		return;	if (background->Width()*background->Height() != width*height)		background->Crop(x, y, width, height);	double tmp;	unsigned char *new_rgb = (unsigned char *) malloc(3 * width * height);	memset(new_rgb, 0, 3 * width * height);	const unsigned char *bg_rgb = background->getRGBData();	int ipos = 0;	if (png_alpha != NULL){		for (int j = 0; j < height; j++) {			for (int i = 0; i < width; i++) {				for (int k = 0; k < 3; k++) {					tmp = rgb_data[3*ipos + k]*png_alpha[ipos]/255.0							+ bg_rgb[3*ipos + k]*(1-png_alpha[ipos]/255.0);					new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);				}				ipos++;			}		}	} else {		for (int j = 0; j < height; j++) {			for (int i = 0; i < width; i++) {				for (int k = 0; k < 3; k++) {					tmp = rgb_data[3*ipos + k];					new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);				}				ipos++;			}		}	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = NULL;}/* Merge the image with a background, taking care of the * image Alpha transparency. (background alpha is ignored). * The images is merged on position (x, y) on the * background, the background must contain the image. */#define IMG_POS_RGB(p, x) (3 * p + x)void Image::Merge_non_crop(Image* background, const int x, const int y){	int bg_w = background->Width();	int bg_h = background->Height();	if (x + width > bg_w || y + height > bg_h)		return;	double tmp;	unsigned char *new_rgb = (unsigned char *)malloc(3 * bg_w * bg_h);	const unsigned char *bg_rgb = background->getRGBData();	int pnl_pos = 0;	int bg_pos = 0;	int pnl_w_end = x + width;	int pnl_h_end = y + height;	memcpy(new_rgb, bg_rgb, 3 * bg_w * bg_h);	for (int j = 0; j < bg_h; j++) {		for (int i = 0; i < bg_w; i++) {			if (j >= y && i >= x && j < pnl_h_end && i < pnl_w_end ) {				for (int k = 0; k < 3; k++) {					if (png_alpha != NULL)						tmp = rgb_data[IMG_POS_RGB(pnl_pos, k)]							* png_alpha[pnl_pos]/255.0							+ bg_rgb[IMG_POS_RGB(bg_pos, k)]							* (1 - png_alpha[pnl_pos]/255.0);					else						tmp = rgb_data[IMG_POS_RGB(pnl_pos, k)];					new_rgb[IMG_POS_RGB(bg_pos, k)] = static_cast<unsigned char>(tmp);				}				pnl_pos++;			}			bg_pos++;		}	}	width = bg_w;	height = bg_h;	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = NULL;}/* Tile the image growing its size to the minimum entire * multiple of w * h. * The new dimensions should be > of the current ones. * Note that this flattens image (alpha removed) */void Image::Tile(const int w, const int h) {	if (w < width || h < height)		return;	int nx = w / width;	if (w % width > 0)		nx++;	int ny = h / height;	if (h % height > 0)		ny++;	int newwidth = nx*width;	int newheight=ny*height;	unsigned char *new_rgb = (unsigned char *) malloc(3 * newwidth * newheight);	memset(new_rgb, 0, 3 * width * height * nx * ny);	int ipos = 0;	int opos = 0;	for (int r = 0; r < ny; r++) {		for (int c = 0; c < nx; c++) {			for (int j = 0; j < height; j++) {				for (int i = 0; i < width; i++) {					opos = j*width + i;					ipos = r*width*height*nx + j*newwidth + c*width +i;					for (int k = 0; k < 3; k++) {						new_rgb[3*ipos + k] = static_cast<unsigned char> (rgb_data[3*opos + k]);					}				}			}		}	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = NULL;	width = newwidth;	height = newheight;	area = width * height;	Crop(0,0,w,h);}/* Crop the image */void Image::Crop(const int x, const int y, const int w, const int h) {	if (x+w > width || y+h > height) {		return;	}	int x2 = x + w;	int y2 = y + h;	unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);	memset(new_rgb, 0, 3 * w * h);	unsigned char *new_alpha = NULL;	if (png_alpha != NULL) {		new_alpha = (unsigned char *) malloc(w * h);		memset(new_alpha, 0, w * h);	}	int ipos = 0;	int opos = 0;	for (int j = 0; j < height; j++) {		for (int i = 0; i < width; i++) {			if (j>=y && i>=x && j<y2 && i<x2) {				for (int k = 0; k < 3; k++) {					new_rgb[3*ipos + k] = static_cast<unsigned char> (rgb_data[3*opos + k]);				}				if (png_alpha != NULL)					new_alpha[ipos] = static_cast<unsigned char> (png_alpha[opos]);				ipos++;			}			opos++;		}	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	if (png_alpha != NULL)		png_alpha = new_alpha;	width = w;	height = h;	area = w * h;}/* Center the image in a rectangle of given width and height. * Fills the remaining space (if any) with the hex color */void Image::Center(const int w, const int h, const char *hex) {	unsigned long packed_rgb;	sscanf(hex, "%lx", &packed_rgb);	unsigned long r = packed_rgb>>16;	unsigned long g = packed_rgb>>8 & 0xff;	unsigned long b = packed_rgb & 0xff;	unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);	memset(new_rgb, 0, 3 * w * h);	int x = (w - width) / 2;	int y = (h - height) / 2;	if (x<0) {		Crop((width - w)/2,0,w,height);		x = 0;	}	if (y<0) {		Crop(0,(height - h)/2,width,h);		y = 0;	}	int x2 = x + width;	int y2 = y + height;	int ipos = 0;	int opos = 0;	double tmp;	area = w * h;	for (int i = 0; i < area; i++) {		new_rgb[3*i] = r;		new_rgb[3*i+1] = g;		new_rgb[3*i+2] = b;	}	if (png_alpha != NULL) {		for (int j = 0; j < h; j++) {			for (int i = 0; i < w; i++) {				if (j>=y && i>=x && j<y2 && i<x2) {					ipos = j*w + i;					for (int k = 0; k < 3; k++) {						tmp = rgb_data[3*opos + k]*png_alpha[opos]/255.0							  + new_rgb[k]*(1-png_alpha[opos]/255.0);						new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);					}					opos++;				}			}		}	} else {		for (int j = 0; j < h; j++) {			for (int i = 0; i < w; i++) {				if (j>=y && i>=x && j<y2 && i<x2) {					ipos = j*w + i;					for (int k = 0; k < 3; k++) {						tmp = rgb_data[3*opos + k];						new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);					}					opos++;				}			}		}	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = NULL;	width = w;	height = h;}/* Fill the image with the given color and adjust its dimensions * to passed values. */void Image::Plain(const int w, const int h, const char *hex) {	unsigned long packed_rgb;	sscanf(hex, "%lx", &packed_rgb);	unsigned long r = packed_rgb>>16;	unsigned long g = packed_rgb>>8 & 0xff;	unsigned long b = packed_rgb & 0xff;	unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);	memset(new_rgb, 0, 3 * w * h);	area = w * h;	for (int i = 0; i < area; i++) {		new_rgb[3*i] = r;		new_rgb[3*i+1] = g;		new_rgb[3*i+2] = b;	}	free(rgb_data);	free(png_alpha);	rgb_data = new_rgb;	png_alpha = NULL;	width = w;	height = h;}voidImage::computeShift(unsigned long mask,					unsigned char &left_shift,					unsigned char &right_shift) {	left_shift = 0;	right_shift = 8;	if (mask != 0) {		while ((mask & 0x01) == 0) {			left_shift++;			mask >>= 1;		}		while ((mask & 0x01) == 1) {			right_shift--;			mask >>= 1;		}	}}PixmapImage::createPixmap(Display* dpy, int scr, Window win) {	int i, j;   /* loop variables */	const int depth = DefaultDepth(dpy, scr);	Visual *visual = DefaultVisual(dpy, scr);	Colormap colormap = DefaultColormap(dpy, scr);	Pixmap tmp = XCreatePixmap(dpy, win, width, height,							   depth);	char *pixmap_data = NULL;	switch (depth) {	case 32:	case 24:		pixmap_data = new char[4 * width * height];		break;	case 16:	case 15:		pixmap_data = new char[2 * width * height];		break;	case 8:		pixmap_data = new char[width * height];		break;	default:		break;	}	XImage *ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0,								  pixmap_data, width, height,								  8, 0);	int entries;	XVisualInfo v_template;	v_template.visualid = XVisualIDFromVisual(visual);	XVisualInfo *visual_info = XGetVisualInfo(dpy, VisualIDMask,							   &v_template, &entries);	unsigned long ipos = 0;	switch (visual_info->c_class) {	case PseudoColor: {			XColor xc;			xc.flags = DoRed | DoGreen | DoBlue;			int num_colors = 256;			XColor *colors = new XColor[num_colors];			for (i = 0; i < num_colors; i++)				colors[i].pixel = (unsigned long) i;			XQueryColors(dpy, colormap, colors, num_colors);			int *closest_color = new int[num_colors];			for (i = 0; i < num_colors; i++) {				xc.red = (i & 0xe0) << 8;		   /* highest 3 bits */				xc.green = (i & 0x1c) << 11;		/* middle 3 bits */				xc.blue = (i & 0x03) << 14;		 /* lowest 2 bits */				/* find the closest color in the colormap */				double distance, distance_squared, min_distance = 0;				for (int ii = 0; ii < num_colors; ii++) {					distance = colors[ii].red - xc.red;					distance_squared = distance * distance;					distance = colors[ii].green - xc.green;					distance_squared += distance * distance;					distance = colors[ii].blue - xc.blue;					distance_squared += distance * distance;					if ((ii == 0) || (distance_squared <= min_distance)) {						min_distance = distance_squared;						closest_color[i] = ii;					}				}			}			for (j = 0; j < height; j++) {				for (i = 0; i < width; i++) {					xc.red = (unsigned short) (rgb_data[ipos++] & 0xe0);					xc.green = (unsigned short) (rgb_data[ipos++] & 0xe0);					xc.blue = (unsigned short) (rgb_data[ipos++] & 0xc0);					xc.pixel = xc.red | (xc.green >> 3) | (xc.blue >> 6);					XPutPixel(ximage, i, j,							  colors[closest_color[xc.pixel]].pixel);				}			}			delete [] colors;			delete [] closest_color;		}		break;	case TrueColor: {			unsigned char red_left_shift;			unsigned char red_right_shift;			unsigned char green_left_shift;			unsigned char green_right_shift;			unsigned char blue_left_shift;			unsigned char blue_right_shift;			computeShift(visual_info->red_mask, red_left_shift,						 red_right_shift);			computeShift(visual_info->green_mask, green_left_shift,						 green_right_shift);			computeShift(visual_info->blue_mask, blue_left_shift,						 blue_right_shift);			unsigned long pixel;			unsigned long red, green, blue;			for (j = 0; j < height; j++) {				for (i = 0; i < width; i++) {					red = (unsigned long)						  rgb_data[ipos++] >> red_right_shift;					green = (unsigned long)							rgb_data[ipos++] >> green_right_shift;					blue = (unsigned long)						   rgb_data[ipos++] >> blue_right_shift;					pixel = (((red << red_left_shift) & visual_info->red_mask)							 | ((green << green_left_shift)								& visual_info->green_mask)							 | ((blue << blue_left_shift)								& visual_info->blue_mask));					XPutPixel(ximage, i, j, pixel);				}			}		}		break;	default: {			logStream << "Login.app: could not load image" << endl;			return(tmp);		}	}	GC gc = XCreateGC(dpy, win, 0, NULL);	XPutImage(dpy, tmp, gc, ximage, 0, 0, 0, 0, width, height);	XFreeGC(dpy, gc);	XFree(visual_info);	delete [] pixmap_data;	/* Set ximage data to NULL since pixmap data was deallocated above */	ximage->data = NULL;	XDestroyImage(ximage);	return(tmp);}intImage::readJpeg(const char *filename, int *width, int *height,				unsigned char **rgb){	int ret = 0;	struct jpeg_decompress_struct cinfo;	struct jpeg_error_mgr jerr;	unsigned char *ptr = NULL;	FILE *infile = fopen(filename, "rb");	if (infile == NULL) {		logStream << APPNAME << "Cannot fopen file: " << filename << endl;		return ret;	}	cinfo.err = jpeg_std_error(&jerr);	jpeg_create_decompress(&cinfo);	jpeg_stdio_src(&cinfo, infile);	jpeg_read_header(&cinfo, TRUE);	jpeg_start_decompress(&cinfo);	/* Prevent against integer overflow */	if(cinfo.output_width >= MAX_DIMENSION	   || cinfo.output_height >= MAX_DIMENSION)	{		logStream << APPNAME << "Unreasonable dimension found in file: "				  << filename << endl;		goto close_file;	}	*width = cinfo.output_width;	*height = cinfo.output_height;	rgb[0] = (unsigned char*)				malloc(3 * cinfo.output_width * cinfo.output_height);	if (rgb[0] == NULL) {		logStream << APPNAME << ": Can't allocate memory for JPEG file."				  << endl;		goto close_file;	}	if (cinfo.output_components == 3) {		ptr = rgb[0];		while (cinfo.output_scanline < cinfo.output_height) {			jpeg_read_scanlines(&cinfo, &ptr, 1);			ptr += 3 * cinfo.output_width;		}	} else if (cinfo.output_components == 1) {		ptr = (unsigned char*) malloc(cinfo.output_width);		if (ptr == NULL) {			logStream << APPNAME << ": Can't allocate memory for JPEG file."					  << endl;			goto rgb_free;		}		unsigned int ipos = 0;		while (cinfo.output_scanline < cinfo.output_height) {			jpeg_read_scanlines(&cinfo, &ptr, 1);			for (unsigned int i = 0; i < cinfo.output_width; i++) {				memset(rgb[0] + ipos, ptr[i], 3);				ipos += 3;			}		}		free(ptr);	}	jpeg_finish_decompress(&cinfo);	ret = 1;	goto close_file;rgb_free:	free(rgb[0]);close_file:	jpeg_destroy_decompress(&cinfo);	fclose(infile);	return(ret);}intImage::readPng(const char *filename, int *width, int *height,			   unsigned char **rgb, unsigned char **alpha){	int ret = 0;	png_structp png_ptr;	png_infop info_ptr;	png_bytepp row_pointers;	unsigned char *ptr = NULL;	png_uint_32 w, h;	int bit_depth, color_type, interlace_type;	int i;	FILE *infile = fopen(filename, "rb");	if (infile == NULL) {		logStream << APPNAME << "Can not fopen file: " << filename << endl;		return ret;	}	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,									 (png_voidp) NULL,									 (png_error_ptr) NULL,									 (png_error_ptr) NULL);	if (!png_ptr) {		goto file_close;	}	info_ptr = png_create_info_struct(png_ptr);	if (!info_ptr) {		png_destroy_read_struct(&png_ptr, (png_infopp) NULL,								(png_infopp) NULL);	}#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4		if (setjmp(png_jmpbuf((png_ptr)))) {#else	if (setjmp(png_ptr->jmpbuf)) {#endif		goto png_destroy;	}	png_init_io(png_ptr, infile);	png_read_info(png_ptr, info_ptr);	png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,				 &interlace_type, (int *) NULL, (int *) NULL);	/* Prevent against integer overflow */	if(w >= MAX_DIMENSION || h >= MAX_DIMENSION) {		logStream << APPNAME << "Unreasonable dimension found in file: "				  << filename << endl;		goto png_destroy;	}	*width = (int) w;	*height = (int) h;	if (color_type == PNG_COLOR_TYPE_RGB_ALPHA		|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA)	{		alpha[0] = (unsigned char *) malloc(*width * *height);		if (alpha[0] == NULL) {			logStream << APPNAME					<< ": Can't allocate memory for alpha channel in PNG file."					<< endl;			goto png_destroy;		}	}	/* Change a paletted/grayscale image to RGB */	if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)	{		png_set_expand(png_ptr);	}	/* Change a grayscale image to RGB */	if (color_type == PNG_COLOR_TYPE_GRAY		|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA)	{		png_set_gray_to_rgb(png_ptr);	}	/* If the PNG file has 16 bits per channel, strip them down to 8 */	if (bit_depth == 16) {	  png_set_strip_16(png_ptr);	}	/* use 1 byte per pixel */	png_set_packing(png_ptr);	row_pointers = (png_byte **) malloc(*height * sizeof(png_bytep));	if (row_pointers == NULL) {		logStream << APPNAME << ": Can't allocate memory for PNG file." << endl;		goto png_destroy;	}	for (i = 0; i < *height; i++) {		row_pointers[i] = (png_byte*) malloc(4 * *width);		if (row_pointers == NULL) {			logStream << APPNAME << ": Can't allocate memory for PNG file."					  << endl;			goto rows_free;		}	}	png_read_image(png_ptr, row_pointers);	rgb[0] = (unsigned char *) malloc(3 * (*width) * (*height));	if (rgb[0] == NULL) {		logStream << APPNAME << ": Can't allocate memory for PNG file." << endl;		goto rows_free;	}	if (alpha[0] == NULL) {		ptr = rgb[0];		for (i = 0; i < *height; i++) {			memcpy(ptr, row_pointers[i], 3 * (*width));			ptr += 3 * (*width);		}	} else {		ptr = rgb[0];		for (i = 0; i < *height; i++) {			unsigned int ipos = 0;			for (int j = 0; j < *width; j++) {				*ptr++ = row_pointers[i][ipos++];				*ptr++ = row_pointers[i][ipos++];				*ptr++ = row_pointers[i][ipos++];				alpha[0][i * (*width) + j] = row_pointers[i][ipos++];			}		}	}	ret = 1; /* data reading is OK */rows_free:	for (i = 0; i < *height; i++) {		if (row_pointers[i] != NULL ) {			free(row_pointers[i]);		}	}	free(row_pointers);png_destroy:	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);file_close:	fclose(infile);	return(ret);}
 |