Esempio n. 1
0
int main(int argc, char *argv[]){
  FILE *fp;
  gdImagePtr im1, im2, imOut;
  int i,x,y,xsize,ysize,c;
  int c1,c2;

  if(argc != 4){
    fprintf(stderr, "[%s] compiled [%s/%s %s]\n", argv[0], __DATE__, __TIME__, DIRE);
    fprintf(stderr, "Usage : %s in-gif1 in-gif2 out-gif\n", argv[0]);
    exit(1);
  }

  im1 = fromGif(argv[1]);
  im2 = fromGif(argv[2]);

  outfile = argv[3];

  xsize = gdImageSX(im1);
  ysize = gdImageSY(im2);

  imOut = gdImageCreate(xsize, ysize);

  for(i=0; i<gdImageColorsTotal(im1); i++){
    int r,g,b;
    r = gdImageRed(  im1, i);
    g = gdImageGreen(im1, i);
    b = gdImageBlue( im1, i);
  }

  for(y=0; y<ysize; y++){
    int r,g,b;
    for(x=0; x<xsize; x++){
      c1 = gdImageGetPixel(im1, x, y);
      c2 = gdImageGetPixel(im2, x, y);
      r = gdImageRed(  im1, c1) - gdImageRed(  im2, c2);
      g = gdImageGreen(im1, c1) - gdImageGreen(im2, c2);
      b = gdImageBlue( im1, c1) - gdImageBlue( im2, c2);
      r = (r + 256) % 256;
      g = (g + 256) % 256;
      b = (b + 256) % 256;
      c = allocOrExact(imOut, r, g, b);
      gdImageSetPixel(imOut, x, y, c);
    }
  }
  gdImageDestroy(im1);
  gdImageDestroy(im2);

  fp = fopen(outfile, "wb");
  if(!fp){
    fprintf(stderr, "Can't open [%s]\n", outfile);
    exit(1);
  }
  gdImageGif(imOut, fp);
  fclose(fp);

  gdImageDestroy(imOut);

  return 0;
}
Esempio n. 2
0
result_t Image::get_colorsTotal(int32_t &retVal)
{
    if (!m_image)
        return CHECK_ERROR(CALL_E_INVALID_CALL);

    retVal = gdImageColorsTotal(m_image);
    return 0;
}
JBoolean
PadColormap
	(
	gdImagePtr image
	)
{
	JSize colorCount = gdImageColorsTotal(image);
	if (colorCount >= kMinColorCount)
		{
		return kJFalse;
		}

	const JSize extraColorCount = kMinColorCount - colorCount;

	int x = gdImageSX(image) - extraColorCount;
	if (x < 0)
		{
		cerr << "image is too small to fit extra colors on single raster line" << endl;
		exit(1);
		}

	int y = gdImageSY(image) - 1;

	int c = gdImageGetPixel(image, x,y);
	int r = gdImageRed  (image, c);
	int g = gdImageGreen(image, c);
	int b = gdImageBlue (image, c);

	int delta = -1;
	if (r < 127 || g < 127 || b < 127)
		{
		delta = +1;
		}

	for (JIndex i=1; i<=extraColorCount; i++)
		{
		assert( x < gdImageSX(image) );

		while ((c = gdImageColorExact(image, r,g,b)) != -1)
			{
			r = JMax(0, JMin(r + delta, 255));
			g = JMax(0, JMin(g + delta, 255));
			b = JMax(0, JMin(b + delta, 255));
			}

		c = gdImageColorAllocate(image, r,g,b);
		assert( c != -1 );
		gdImageSetPixel(image, x,y, c);

		x++;
		}

	return kJTrue;
}
void
PrintGIFInfo
	(
	gdImagePtr image
	)
{
	cout << endl;
	cout << "Index\tRed\tGreen\tBlue" << endl;

	const JSize colorCount = gdImageColorsTotal(image);
	for (JIndex i=0; i<colorCount; i++)
		{
		cout << i;
		cout << '\t' << gdImageRed  (image, i);
		cout << '\t' << gdImageGreen(image, i);
		cout << '\t' << gdImageBlue (image, i);
		cout << endl;
		}

	cout << endl;

	cout << "Number of colors:        " << colorCount << endl;

	const int transparentColor = gdImageGetTransparent(image);
	cout << "Transparent color index: ";
	if (transparentColor == kNoTransparentColor)
		{
		cout << "none";
		}
	else
		{
		cout << transparentColor;
		}
	cout << endl;

	cout << endl;

	cout << "Width:      " << gdImageSX(image) << endl;
	cout << "Height:     " << gdImageSY(image) << endl;
	cout << "Interlaced: ";
	if (gdImageGetInterlaced(image))
		{
		cout << "yes";
		}
	else
		{
		cout << "no";
		}
	cout << endl;

	cout << endl;
}
static void make_thumb(void *conf)
{
	int colors = 0;
	int transparent = -1;
	ngx_image_conf_t *info = conf;
	info->dst_im = gdImageCreateTrueColor(info->width,info->height);
	colors = gdImageColorsTotal(info->src_im);
	transparent = gdImageGetTransparent(info->src_im);
	if (transparent == -1)
        {
		gdImageSaveAlpha(info->src_im,1);
		gdImageColorTransparent(info->src_im, -1);
		if(colors == 0)
		{
			gdImageAlphaBlending(info->dst_im,0);
			gdImageSaveAlpha(info->dst_im,1);
		}
		if(colors)
		{
			gdImageTrueColorToPalette(info->dst_im,1,256);
		}
    }
    if(info->w_margin == 1)
    {

		info->w_im = gdImageCreateTrueColor(info->width,info->height);
		gdImageFilledRectangle(info->w_im, 0, 0, info->width,info->height, gdImageColorAllocate(info->w_im, 255, 255, 255));
        info->dst_im = gdImageCreateTrueColor(info->max_width,info->max_height);
        gdImageFilledRectangle(info->dst_im, 0, 0, info->max_width,info->max_height, gdImageColorAllocate(info->dst_im, 255, 255, 255));
		gdImageCopyResampled(info->w_im, info->src_im, 0, 0, info->src_x, info->src_y,info->width, info->height, info->src_w,info->src_h);
		gdImageCopyResampled(info->dst_im, info->w_im, info->dst_x,info->dst_y, 0, 0,info->width, info->height, info->width, info->height);
        gdImageDestroy(info->w_im);
    }
    else
    {

        gdImageCopyResampled(info->dst_im,info->src_im,info->dst_x,info->dst_y,info->src_x,info->src_y,info->width,info->height,info->src_w,info->src_h);
    }
    gdImageDestroy(info->src_im);
}
static ngx_buf_t *
ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
{
    int                            sx, sy, dx, dy, ox, oy, ax, ay, size,
                                   colors, palette, transparent, sharpen,
                                   red, green, blue, t,
                                   offset_x, offset_y;
    u_char                        *out;
    ngx_buf_t                     *b;
    ngx_uint_t                     resize;
    gdImagePtr                     src, dst;
    ngx_pool_cleanup_t            *cln;
    ngx_http_image_filter_conf_t  *conf;

    src = ngx_http_image_source(r, ctx);

    if (src == NULL) {
        return NULL;
    }

    sx = gdImageSX(src);
    sy = gdImageSY(src);

    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);

    if (!ctx->force
        && ctx->angle == 0
        && (ngx_uint_t) sx <= ctx->max_width
        && (ngx_uint_t) sy <= ctx->max_height)
    {
        gdImageDestroy(src);
        return ngx_http_image_asis(r, ctx);
    }

    colors = gdImageColorsTotal(src);

    if (colors && conf->transparency) {
        transparent = gdImageGetTransparent(src);

        if (transparent != -1) {
            palette = colors;
            red = gdImageRed(src, transparent);
            green = gdImageGreen(src, transparent);
            blue = gdImageBlue(src, transparent);

            goto transparent;
        }
    }

    palette = 0;
    transparent = -1;
    red = 0;
    green = 0;
    blue = 0;

transparent:

    gdImageColorTransparent(src, -1);

    dx = sx;
    dy = sy;

    if (conf->filter == NGX_HTTP_IMAGE_RESIZE) {

        if ((ngx_uint_t) dx > ctx->max_width) {
            dy = dy * ctx->max_width / dx;
            dy = dy ? dy : 1;
            dx = ctx->max_width;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            dx = dx * ctx->max_height / dy;
            dx = dx ? dx : 1;
            dy = ctx->max_height;
        }

        resize = 1;

    } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {

        resize = 0;

    } else { /* NGX_HTTP_IMAGE_CROP */

        resize = 0;

        if ((double) dx / dy < (double) ctx->max_width / ctx->max_height) {
            if ((ngx_uint_t) dx > ctx->max_width) {
                dy = dy * ctx->max_width / dx;
                dy = dy ? dy : 1;
                dx = ctx->max_width;
                resize = 1;
            }

        } else {
            if ((ngx_uint_t) dy > ctx->max_height) {
                dx = dx * ctx->max_height / dy;
                dx = dx ? dx : 1;
                dy = ctx->max_height;
                resize = 1;
            }
        }
    }

    if (resize) {
        dst = ngx_http_image_new(r, dx, dy, palette);
        if (dst == NULL) {
            gdImageDestroy(src);
            return NULL;
        }

        if (colors == 0) {
            gdImageSaveAlpha(dst, 1);
            gdImageAlphaBlending(dst, 0);
        }

        gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);

        if (colors) {
            gdImageTrueColorToPalette(dst, 1, 256);
        }

        gdImageDestroy(src);

    } else {
        dst = src;
    }

    if (ctx->angle) {
        src = dst;

        ax = (dx % 2 == 0) ? 1 : 0;
        ay = (dy % 2 == 0) ? 1 : 0;

        switch (ctx->angle) {

        case 90:
        case 270:
            dst = ngx_http_image_new(r, dy, dx, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }
            if (ctx->angle == 90) {
                ox = dy / 2 + ay;
                oy = dx / 2 - ax;

            } else {
                ox = dy / 2 - ay;
                oy = dx / 2 + ax;
            }

            gdImageCopyRotated(dst, src, ox, oy, 0, 0,
                               dx + ax, dy + ay, ctx->angle);
            gdImageDestroy(src);

            t = dx;
            dx = dy;
            dy = t;
            break;

        case 180:
            dst = ngx_http_image_new(r, dx, dy, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }
            gdImageCopyRotated(dst, src, dx / 2 - ax, dy / 2 - ay, 0, 0,
                               dx + ax, dy + ay, ctx->angle);
            gdImageDestroy(src);
            break;
        }
    }

    if (conf->filter == NGX_HTTP_IMAGE_CROP) {

        src = dst;

        if ((ngx_uint_t) dx > ctx->max_width) {
            ox = dx - ctx->max_width;

        } else {
            ox = 0;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            oy = dy - ctx->max_height;

        } else {
            oy = 0;
        }

        if (ox || oy) {

            dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);

            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }

            offset_x = ngx_http_image_filter_get_value(r, conf->oxcv,
                                                       conf->offset_x);
            offset_y = ngx_http_image_filter_get_value(r, conf->oycv,
                                                       conf->offset_y);

            if (offset_x == NGX_HTTP_IMAGE_OFFSET_LEFT) {
                ox = 0;

            } else if (offset_x == NGX_HTTP_IMAGE_OFFSET_CENTER) {
                ox /= 2;
            }

            if (offset_y == NGX_HTTP_IMAGE_OFFSET_TOP) {
                oy = 0;

            } else if (offset_y == NGX_HTTP_IMAGE_OFFSET_CENTER) {
                oy /= 2;
            }

            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "image crop: %d x %d @ %d x %d",
                           dx, dy, ox, oy);

            if (colors == 0) {
                gdImageSaveAlpha(dst, 1);
                gdImageAlphaBlending(dst, 0);
            }

            gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);

            if (colors) {
                gdImageTrueColorToPalette(dst, 1, 256);
            }

            gdImageDestroy(src);
        }
    }

    if (transparent != -1 && colors) {
        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
    }

    sharpen = ngx_http_image_filter_get_value(r, conf->shcv, conf->sharpen);
    if (sharpen > 0) {
        gdImageSharpen(dst, sharpen);
    }

    out = ngx_http_image_out(r, ctx->type, dst, &size);

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "image: %d x %d %d", sx, sy, colors);

    gdImageDestroy(dst);
    ngx_pfree(r->pool, ctx->image);

    if (out == NULL) {
        return NULL;
    }

    cln = ngx_pool_cleanup_add(r->pool, 0);
    if (cln == NULL) {
        gdFree(out);
        return NULL;
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        gdFree(out);
        return NULL;
    }

    cln->handler = ngx_http_image_cleanup;
    cln->data = out;

    b->pos = out;
    b->last = out + size;
    b->memory = 1;
    b->last_buf = 1;

    ngx_http_image_length(r, b);

    return b;
}
Esempio n. 7
0
/* {{{ _php_image_output_ctx */
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
{
	zval *imgind;
	char *file = NULL;
	int file_len = 0;
	long quality, basefilter;
	gdImagePtr im;
	int argc = ZEND_NUM_ARGS();
	int q = -1, i;
	int f = -1;
	gdIOCtx *ctx = NULL;
	zval *to_zval = NULL;
	php_stream *stream;

	/* The third (quality) parameter for Wbmp stands for the threshold when called from image2wbmp().
	 * The third (quality) parameter for Wbmp and Xbm stands for the foreground color index when called
	 * from imagey<type>().
	 */
	if (image_type == PHP_GDIMG_TYPE_XBM) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rp!|ll", &imgind, &file, &file_len, &quality, &basefilter) == FAILURE) {
			return;
		}
	} else {
		/* PHP_GDIMG_TYPE_GIF
		 * PHP_GDIMG_TYPE_PNG 
		 * PHP_GDIMG_TYPE_JPG 
		 * PHP_GDIMG_TYPE_WBM 
		 * PHP_GDIMG_TYPE_WEBP 
		 * */
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z/!ll", &imgind, &to_zval, &quality, &basefilter) == FAILURE) {
			return;
		}
	}

	ZEND_FETCH_RESOURCE(im, gdImagePtr, &imgind, -1, "Image", phpi_get_le_gd());

	if (argc >= 3) {
		q = quality; /* or colorindex for foreground of BW images (defaults to black) */
		if (argc == 4) {
			f = basefilter;
		}
	}

	if (argc > 1 && to_zval != NULL) {
		if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
			php_stream_from_zval_no_verify(stream, &to_zval);
			if (stream == NULL) {
				RETURN_FALSE;
			}
		} else if (Z_TYPE_P(to_zval) == IS_STRING) {
			stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
			if (stream == NULL) {
				RETURN_FALSE;
			}
		} else {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid 2nd parameter, it must a filename or a stream");
			RETURN_FALSE;
		}
	} else {
		ctx = emalloc(sizeof(gdIOCtx));
		ctx->putC = _php_image_output_putc;
		ctx->putBuf = _php_image_output_putbuf;
		ctx->gd_free = _php_image_output_ctxfree;

#if APACHE && defined(CHARSET_EBCDIC)
		/* XXX this is unlikely to work any more [email protected] */
		/* This is a binary file already: avoid EBCDIC->ASCII conversion */
		ap_bsetflag(php3_rqst->connection->client, B_EBCDIC2ASCII, 0);
#endif
	}

	if (!ctx)	{
		ctx = emalloc(sizeof(gdIOCtx));
		ctx->putC = _php_image_stream_putc;
		ctx->putBuf = _php_image_stream_putbuf;
		ctx->gd_free = _php_image_stream_ctxfree;
		ctx->data = (void *)stream;
	}

	switch(image_type) {
		case PHP_GDIMG_CONVERT_WBM:
			if(q<0||q>255) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid threshold value '%d'. It must be between 0 and 255", q);
			}
		case PHP_GDIMG_TYPE_JPG:
			(*func_p)(im, ctx, q);
			break;
		case PHP_GDIMG_TYPE_WEBP:
			if (q == -1) {
				q = 80;
			}
			(*func_p)(im, ctx, q);
			break;
		case PHP_GDIMG_TYPE_PNG:
			(*func_p)(im, ctx, q, f);
			break;
		case PHP_GDIMG_TYPE_XBM:
		case PHP_GDIMG_TYPE_WBM:
			if (argc < 3) {
				for(i=0; i < gdImageColorsTotal(im); i++) {
					if(!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) break;
				}
				q = i;
			}
			if (image_type == PHP_GDIMG_TYPE_XBM) {
				(*func_p)(im, file, q, ctx);
			} else {
				(*func_p)(im, q, ctx);
			}
			break;
		default:
			(*func_p)(im, ctx);
			break;
	}

	ctx->gd_free(ctx);

	RETURN_TRUE;
}
Esempio n. 8
0
// Generates the count image from the count string, returns true if all ok
bool CreateImage(const char *pcCount, const char *pcFont, int iDigits) {
	// Set the spare value 
	int iCountLen = strlen(pcCount);
	if (iDigits < iCountLen)
		iDigits = iCountLen;
	int iSpare = 0;
	if (iDigits > iCountLen)
		iSpare = iDigits - iCountLen;
	// Loop vars
	char pcDigitName[STR_SIZE] = "";
	gdImagePtr pImg = NULL;
	FILE *pPic = NULL;
	// Load the zero digit image
	sprintf(pcDigitName, COUNTER_ZERO, pcFont);
	pPic = fopen(pcDigitName, "rb+");
	if (pPic == NULL)
		return false;
	pImg = gdImageCreateFromGif(pPic);
	fclose(pPic);
	if (pImg == NULL)
		return false;
	// Create the output image
	gdImagePtr pOutImg = NULL;
	pOutImg = gdImageCreate(iDigits * pImg->sx, pImg->sy);
	if (pOutImg == NULL) {
		gdImageDestroy(pImg);
		return false;
	}
	// Copy the palette info from one to the other...
	int iColTotal = gdImageColorsTotal(pImg);
	for (int i = 0; i < iColTotal; i++) {
		gdImageColorAllocate(pOutImg, gdImageRed(pImg, i), gdImageGreen(pImg, i), gdImageBlue(pImg, i));
	}
	int iTransCol = gdImageGetTransparent(pImg);
	if (iTransCol >= 0) {
		gdImageColorTransparent(pOutImg, iTransCol);
		gdImageFill(pOutImg, 0, 0, iTransCol);
	}
	// Loop through each leading zero
	int iPos = 0;
	while (iSpare-- > 0) {
		// paste in the image
		gdImageCopy(pOutImg, pImg, iPos, 0, 0, 0, pImg->sx, pImg->sy);
		iPos += pImg->sx;
	}
	// Delete the zero image
	gdImageDestroy(pImg);
	// Loop through each counter character
	const char *pcPos = pcCount;
	while (*pcPos != '\0') {
		sprintf(pcDigitName, COUNTER_PIC, pcFont, *pcPos);
		// Load the image
		pPic = fopen(pcDigitName, "rb+");
		if (pPic == NULL) {
			gdImageDestroy(pOutImg);
			return false;
		}
		pImg = gdImageCreateFromGif(pPic);
		if (pImg == NULL) {
			gdImageDestroy(pOutImg);
			return false;
		}
		// Paste in the image
		gdImageCopy(pOutImg, pImg, iPos, 0, 0, 0, pImg->sx, pImg->sy);
		iPos += pImg->sx;
		// Delete the image
		gdImageDestroy(pImg);
		// Update the position counter
		pcPos++;
	}
	// Write out the output image
	if (g_oCGI.Debug()) {
		char pcGIFName[STR_SIZE] = COUNTER_ROOT;
		strcat(pcGIFName, "out.gif");
		FILE *pGIFFile = NULL;
		pGIFFile = fopen(pcGIFName, "wb");
		if (pGIFFile) {
			gdImageGif(pOutImg, pGIFFile);
			fclose(pGIFFile);
		}
	}
	else {
		gdImageInterlace(pOutImg, 1);
#ifdef WIN32
		_setmode(_fileno(stdout), _O_BINARY);
#endif
		printf("Content-type: image/gif\n\n");
		gdImageGif(pOutImg, stdout);
	}
	// Destroy the image
	gdImageDestroy(pOutImg);

	return true;
} // CreateImage
Esempio n. 9
0
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)()) 
{
	zval **imgind, **file, **quality;
	gdImagePtr im;
	char *fn = NULL;
	FILE *fp = NULL;
	int argc = ZEND_NUM_ARGS();
	int q = -1, i;
	gdIOCtx *ctx;

	/* The quality parameter for Wbmp stands for the threshold when called from image2wbmp() */
	
	if (argc < 1 || argc > 3 || zend_get_parameters_ex(argc, &imgind, &file, &quality) == FAILURE) 
	{
		WRONG_PARAM_COUNT;
	}

	ZEND_FETCH_RESOURCE(im, gdImagePtr, imgind, -1, "Image", phpi_get_le_gd());

	if (argc > 1) {
		convert_to_string_ex(file);
		fn = Z_STRVAL_PP(file);
		if (argc == 3) {
			convert_to_long_ex(quality);
			q = Z_LVAL_PP(quality);
		}
	}

	if ((argc == 2) || (argc > 2 && Z_STRLEN_PP(file))) {
		PHP_GD_CHECK_OPEN_BASEDIR(fn, "Invalid filename");

		fp = VCWD_FOPEN(fn, "wb");
		if (!fp) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open '%s' for writing", fn);
			RETURN_FALSE;
		}

		ctx = gdNewFileCtx(fp);
	} else {
		ctx = emalloc(sizeof(gdIOCtx));
		ctx->putC = _php_image_output_putc;
		ctx->putBuf = _php_image_output_putbuf;
#if HAVE_LIBGD204
		ctx->gd_free = _php_image_output_ctxfree;
#else
		ctx->free = _php_image_output_ctxfree;
#endif		

#if APACHE && defined(CHARSET_EBCDIC)
		/* XXX this is unlikely to work any more [email protected] */
		/* This is a binary file already: avoid EBCDIC->ASCII conversion */
		ap_bsetflag(php3_rqst->connection->client, B_EBCDIC2ASCII, 0);
#endif
	}

	switch(image_type) {
		case PHP_GDIMG_CONVERT_WBM:
			if(q<0||q>255) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid threshold value '%d'. It must be between 0 and 255", q);
			}
		case PHP_GDIMG_TYPE_JPG:
			(*func_p)(im, ctx, q);
			break;
		case PHP_GDIMG_TYPE_WBM:
			for(i=0; i < gdImageColorsTotal(im); i++) {
				if(gdImageRed(im, i) == 0) break;
			} 
			(*func_p)(im, i, ctx);
			break;
		default:
			(*func_p)(im, ctx);
			break;
	}

#if HAVE_LIBGD204	
	ctx->gd_free(ctx);
#else
	ctx->free(ctx);
#endif		

	if(fp) {
		fflush(fp);
		fclose(fp);
	}
	
    RETURN_TRUE;
}
static ngx_buf_t *
ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
{
    int                            sx, sy, dx, dy, ox, oy, size,
                                   colors, palette, transparent,
                                   red, green, blue;
    u_char                        *out;
    ngx_buf_t                     *b;
    ngx_uint_t                     resize;
    gdImagePtr                     src, dst;
    ngx_pool_cleanup_t            *cln;
    ngx_http_image_filter_conf_t  *conf;

    src = ngx_http_image_source(r, ctx);

    if (src == NULL) {
        return NULL;
    }

    sx = gdImageSX(src);
    sy = gdImageSY(src);

    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);

    if (!ctx->force
        && (ngx_uint_t) sx <= ctx->max_width
        && (ngx_uint_t) sy <= ctx->max_height)
    {
        gdImageDestroy(src);
        return ngx_http_image_asis(r, ctx);
    }

    colors = gdImageColorsTotal(src);

    if (colors && conf->transparency) {
        transparent = gdImageGetTransparent(src);

        if (transparent != -1) {
            palette = colors;
            red = gdImageRed(src, transparent);
            green = gdImageGreen(src, transparent);
            blue = gdImageBlue(src, transparent);

            goto transparent;
        }
    }

    palette = 0;
    transparent = -1;
    red = 0;
    green = 0;
    blue = 0;

transparent:

    gdImageColorTransparent(src, -1);

    dx = sx;
    dy = sy;

    if (conf->filter == NGX_HTTP_IMAGE_RESIZE) {

        if ((ngx_uint_t) dx > ctx->max_width) {
            dy = dy * ctx->max_width / dx;
            dy = dy ? dy : 1;
            dx = ctx->max_width;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            dx = dx * ctx->max_height / dy;
            dx = dx ? dx : 1;
            dy = ctx->max_height;
        }

        resize = 1;

    } else { /* NGX_HTTP_IMAGE_CROP */

        resize = 0;

        if ((ngx_uint_t) (dx * 100 / dy)
            < ctx->max_width * 100 / ctx->max_height)
        {
            if ((ngx_uint_t) dx > ctx->max_width) {
                dy = dy * ctx->max_width / dx;
                dy = dy ? dy : 1;
                dx = ctx->max_width;
                resize = 1;
            }

        } else {
            if ((ngx_uint_t) dy > ctx->max_height) {
                dx = dx * ctx->max_height / dy;
                dx = dx ? dx : 1;
                dy = ctx->max_height;
                resize = 1;
            }
        }
    }

    if (resize) {
        dst = ngx_http_image_new(r, dx, dy, palette);
        if (dst == NULL) {
            gdImageDestroy(src);
            return NULL;
        }

        if (colors == 0) {
            gdImageSaveAlpha(dst, 1);
            gdImageAlphaBlending(dst, 0);
        }

        gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);

        if (colors) {
            gdImageTrueColorToPalette(dst, 1, 256);
        }

        gdImageDestroy(src);

    } else {
        dst = src;
    }

    if (conf->filter == NGX_HTTP_IMAGE_CROP) {

        src = dst;

        if ((ngx_uint_t) dx > ctx->max_width) {
            ox = dx - ctx->max_width;

        } else {
            ox = 0;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            oy = dy - ctx->max_height;

        } else {
            oy = 0;
        }

        if (ox || oy) {

            dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);

            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }

            ox /= 2;
            oy /= 2;

            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "image crop: %d x %d @ %d x %d",
                           dx, dy, ox, oy);

            if (colors == 0) {
                gdImageSaveAlpha(dst, 1);
                gdImageAlphaBlending(dst, 0);
            }

            gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);

            if (colors) {
                gdImageTrueColorToPalette(dst, 1, 256);
            }

            gdImageDestroy(src);
        }
    }

    if (transparent != -1 && colors) {
        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
    }

    out = ngx_http_image_out(r, ctx->type, dst, &size);

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "image: %d x %d %d", sx, sy, colors);

    gdImageDestroy(dst);
    ngx_pfree(r->pool, ctx->image);

    if (out == NULL) {
        return NULL;
    }

    cln = ngx_pool_cleanup_add(r->pool, 0);
    if (cln == NULL) {
        gdFree(out);
        return NULL;
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        gdFree(out);
        return NULL;
    }

    cln->handler = ngx_http_image_cleanup;
    cln->data = out;

    b->pos = out;
    b->last = out + size;
    b->memory = 1;
    b->last_buf = 1;

    ngx_http_image_length(r, b);

    return b;
}
Esempio n. 11
0
int main(int argc, char **argv)
{
	FILE *in;
	FILE *out;
	/* Declare our image pointer */
	gdImagePtr im = 0;
	int i;
       /* We'll clear 'no' once we know the user has made a
		reasonable request. */
	int no = 1;
	/* We'll set 'write' once we know the user's request
		requires that the image be written back to disk. */
	int write = 0;
	/* C programs always get at least one argument; we want at
		least one more (the image), more in practice. */
	if (argc < 2) {
		no = 1;	
		goto usage;
	}
	/* The last argument should be the image. Open the file. */
	in = fopen(argv[argc-1], "rb");	
	if (!in) {
		fprintf(stderr,
			"Error: can't open file %s.\n", argv[argc-1]);
	}
	/* Now load the image. */	
	im = gdImageCreateFromGif(in);
	fclose(in);
	/* If the load failed, it must not be a GIF file. */
	if (!im) {
		fprintf(stderr,
			"Error: %s is not a valid gif file.\n", argv[1]);
		exit(1);	
	}
	/* Consider each argument in turn. */
	for (i=1; (i < (argc-1)); i++) {
		/* -i turns on and off interlacing. */
		if (!strcmp(argv[i], "-i")) {
			if (i == (argc-2)) {
				fprintf(stderr, 
				"Error: -i specified without y or n.\n");
				no = 1;
				goto usage;
			}
			if (!strcmp(argv[i+1], "y")) {
				/* Set interlace. */
				gdImageInterlace(im, 1);
			} else if (!strcmp(argv[i+1], "n")) {
				/* Clear interlace. */
				gdImageInterlace(im, 0);
			} else {
				fprintf(stderr,
				"Error: -i specified without y or n.\n");
				no = 1;
				goto usage;
			}
			i++;
			no = 0;
			write = 1;
		} else if (!strcmp(argv[i], "-t")) {
			/* Set transparent index (or none). */
			int index;
			if (i == (argc-2)) {
				fprintf(stderr,
		"Error: -t specified without a color table index.\n");
				no = 1;
				goto usage;
			}
			if (!strcmp(argv[i+1], "none")) {
				/* -1 means not transparent. */
				gdImageColorTransparent(im, -1);
			} else {
				/* OK, get an integer and set the index. */
				index = atoi(argv[i+1]);
				gdImageColorTransparent(im, index);
			}
			i++;
			write = 1;
			no = 0;
		} else if (!strcmp(argv[i], "-l")) {
			/* List the colors in the color table. */
			int j;
			/* Tabs used below. */
			printf("Index	Red	Green	Blue\n");
			for (j=0; (j < gdImageColorsTotal(im)); j++) {
				/* Use access macros to learn colors. */
				printf("%d	%d	%d	%d\n",
					j, 
					gdImageRed(im, j),
					gdImageGreen(im, j),
					gdImageBlue(im, j));
			}
			no = 0;
		} else if (!strcmp(argv[i], "-d")) {
			/* Output dimensions, etc. */
			int t;
			printf("Width: %d Height: %d Colors: %d\n",
				gdImageSX(im), gdImageSY(im),
				gdImageColorsTotal(im));
			t = gdImageGetTransparent(im);
			if (t != (-1)) {
				printf("Transparent index: %d\n", t);
			} else {
				/* -1 means the image is not transparent. */
				printf("Transparent index: none\n");
			}
			if (gdImageGetInterlaced(im)) {
				printf("Interlaced: yes\n");	
			} else {
				printf("Interlaced: no\n");	
			}
			no = 0;
		} else {
			fprintf(stderr, "Unknown argument: %s\n", argv[i]);
			break;	
		}
	}
usage:
	if (no) {
		/* If the command failed, output an explanation. */
		fprintf(stderr, 
	"Usage: webgif [-i y|n ] [-l] [-t index|off ] [-d] gifname.gif\n");
		fprintf(stderr, 
	"Where -i controls interlace (specify y or n for yes or no),\n");
		fprintf(stderr, 
	"-l outputs a table of color indexes, -t sets the specified\n");
		fprintf(stderr, 
	"color index (0-255 or none) to be the transparent color, and\n");
		fprintf(stderr,
	"-d reports the dimensions and other characteristics of the image.\n");
		fprintf(stderr, 
	"Note: you may wish to pipe to \"more\" when using the -l option.\n");
	} 
	if (write) {
		/* Open a temporary file. */
		out = fopen("temp.tmp", "wb");
		if (!out) {
			fprintf(stderr,
				"Unable to write to temp.tmp -- exiting\n");
			exit(1);
		}
		/* Write the new gif. */
		gdImageGif(im, out);
		fclose(out);
		/* Erase the old gif. */
		unlink(argv[argc-1]);
		/* Rename the new to the old. */
		rename("temp.tmp", argv[argc-1]);
	}
	/* Delete the image from memory. */
	if (im) {
		gdImageDestroy(im);
	}
	/* All's well that ends well. */
	return 0;
}
Esempio n. 12
0
/**
 * Function: gdImageCropThreshold
 *
 * Crop an image using a given color
 *
 * The _threshold_ defines the tolerance to be used while comparing the image
 * color and the color to crop. The method used to calculate the color
 * difference is based on the color distance in the RGB(A) cube.
 *
 * Parameters:
 *   im        - The image.
 *   color     - The crop color.
 *   threshold - The crop threshold.
 *
 * Returns:
 *   The newly created cropped image, or NULL on failure.
 *
 * See also:
 *   - <gdImageCrop>
 *   - <gdImageCropAuto>
 */
BGD_DECLARE(gdImagePtr) gdImageCropThreshold(gdImagePtr im, const unsigned int color, const float threshold)
{
	const int width = gdImageSX(im);
	const int height = gdImageSY(im);

	int x,y;
	int match;
	gdRect crop;

	crop.x = 0;
	crop.y = 0;
	crop.width = 0;
	crop.height = 0;

	/* Pierre: crop everything sounds bad */
	if (threshold > 100.0) {
		return NULL;
	}

	if (!gdImageTrueColor(im) && color >= gdImageColorsTotal(im)) {
		return NULL;
	}

	/* TODO: Add gdImageGetRowPtr and works with ptr at the row level
	 * for the true color and palette images
	 * new formats will simply work with ptr
	 */
	match = 1;
	for (y = 0; match && y < height; y++) {
		for (x = 0; match && x < width; x++) {
			match = (gdColorMatch(im, color, gdImageGetPixel(im, x,y), threshold)) > 0;
		}
	}

	/* Whole image would be cropped > bye */
	if (match) {
		return NULL;
	}

	crop.y = y - 1;

	match = 1;
	for (y = height - 1; match && y >= 0; y--) {
		for (x = 0; match && x < width; x++) {
			match = (gdColorMatch(im, color, gdImageGetPixel(im, x, y), threshold)) > 0;
		}
	}
	crop.height = y - crop.y + 2;

	match = 1;
	for (x = 0; match && x < width; x++) {
		for (y = 0; match && y < crop.y + crop.height; y++) {
			match = (gdColorMatch(im, color, gdImageGetPixel(im, x,y), threshold)) > 0;
		}
	}
	crop.x = x - 1;

	match = 1;
	for (x = width - 1; match && x >= 0; x--) {
		for (y = 0; match &&  y < crop.y + crop.height; y++) {
			match = (gdColorMatch(im, color, gdImageGetPixel(im, x,y), threshold)) > 0;
		}
	}
	crop.width = x - crop.x + 2;

	return gdImageCrop(im, &crop);
}
ngx_int_t ngx_http_small_light_gd_process(ngx_http_request_t *r, ngx_http_small_light_ctx_t *ctx)
{
    ngx_http_small_light_gd_ctx_t     *ictx;
    ngx_http_small_light_image_size_t  sz;
    gdImagePtr                         src, dst, canvas;
    ngx_int_t                          colors, transparent, palette, red, green, blue;
    ngx_int_t                          ax, ay, ox, oy, type;
    int                                iw, ih, radius, ccolor, bcolor;
    char                              *sharpen, *of;
    u_char                            *out;
    int                                size;
    double                             q;

    ictx = (ngx_http_small_light_gd_ctx_t *)ctx->ictx;
    src  = ngx_http_small_light_gd_src(ictx);
    if (src == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to get image source %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    /* adjust image size */
    iw = gdImageSX(src);
    ih = gdImageSY(src);
    ngx_http_small_light_calc_image_size(r, ctx, &sz, iw, ih);

    colors      = gdImageColorsTotal(src);
    palette     = 0;
    transparent = -1;
    red         = 0;
    green       = 0;
    blue        = 0;

    if (colors) {
        transparent = gdImageGetTransparent(src);

        if (transparent != -1) {
            palette = colors;
            red     = gdImageRed(src,   transparent);
            green   = gdImageGreen(src, transparent);
            blue    = gdImageBlue(src,  transparent);
        }
    }

    gdImageColorTransparent(src, -1);

    /* rotate. */
    if (sz.angle) {
        dst = src;
        ax  = (iw % 2 == 0) ? 1 : 0;
        ay  = (ih % 2 == 0) ? 1 : 0;
        switch (sz.angle) {
        case 90:
        case 270:
            dst = ngx_http_small_light_gd_new(ih, iw, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NGX_ERROR;
            }

            if (sz.angle == 90) {
                ox = ih / 2 - ay;
                oy = iw / 2 + ax;
            } else {
                ox = ih / 2 + ay;
                oy = iw / 2 - ax;
            }

            gdImageCopyRotated(dst, src, ox, oy, 0, 0,
                               iw, ih, -sz.angle);
            gdImageDestroy(src);

            break;
        case 180:
            dst = ngx_http_small_light_gd_new(iw, ih, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NGX_ERROR;
            }
            gdImageCopyRotated(dst, src, iw / 2 - ax, ih / 2 - ay, 0, 0,
                               iw + ax, ih + ay, sz.angle);
            gdImageDestroy(src);
            break;
        default:
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "image not rotated. 'angle'(%ui) must be 90 or 180 or 270. %s:%d",
                          sz.angle,
                          __FUNCTION__,
                          __LINE__);
            break;
        }
        src = dst;
    }

    /* calc size. */
    iw = gdImageSX(src);
    ih = gdImageSY(src);
    ngx_http_small_light_calc_image_size(r, ctx, &sz, iw, ih);

    /* pass through. */
    if (sz.pt_flg != 0) {
        gdImageDestroy(src);
        ctx->of = ctx->inf;
        return NGX_OK;
    }

    /* crop, scale. */
    if (sz.scale_flg != 0) {
        dst = ngx_http_small_light_gd_new(sz.dw, sz.dh, palette);
        if (dst == NULL) {
            gdImageDestroy(src);
            return NGX_ERROR;
        }

        if (colors == 0) {
            gdImageSaveAlpha(dst, 1);
            gdImageAlphaBlending(dst, 0);
        }

        gdImageCopyResampled(dst, src, 0, 0, sz.sx, sz.sy, sz.dw, sz.dh, sz.sw, sz.sh);

        if (colors) {
            gdImageTrueColorToPalette(dst, 1, 256);
        }

        gdImageDestroy(src);
    } else {
        dst = src;
    }

    if (transparent != -1 && colors) {
        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
    }

    /* effects. */
    sharpen = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "sharpen");
    if (sharpen != NULL) {
        radius = ngx_http_small_light_parse_int(sharpen);
        if (radius > 0) {
            gdImageSharpen(dst, radius);
        }
    }

    /* interlace */
    gdImageInterlace(dst, 1);

    /* create canvas then draw image to the canvas. */
    if (sz.cw > 0.0 && sz.ch > 0.0) {
        canvas = gdImageCreateTrueColor(sz.cw, sz.ch);
        if (canvas == NULL) {
            gdImageDestroy(dst);
            return NGX_ERROR;
        }
        ccolor = gdImageColorAllocateAlpha(canvas, sz.cc.r, sz.cc.g, sz.cc.b, sz.cc.a);
        gdImageFilledRectangle(canvas, 0, 0, sz.cw, sz.ch, ccolor);
        gdImageCopy(canvas, dst, sz.dx, sz.dy, 0, 0, sz.dw, sz.dh);
        gdImageDestroy(dst);
        dst = canvas;
    }

    /* border. */
    if (sz.bw > 0.0 || sz.bh > 0.0) {
        bcolor = gdImageColorAllocateAlpha(dst, sz.bc.r, sz.bc.g, sz.bc.b, sz.bc.a);
        if (sz.cw > 0.0 && sz.ch > 0.0) {
            gdImageFilledRectangle(dst, 0, 0, sz.cw, sz.bh, bcolor);
            gdImageFilledRectangle(dst, 0, 0, sz.bw, sz.ch, bcolor);
            gdImageFilledRectangle(dst, 0, sz.ch - sz.bh, sz.cw - 1, sz.ch - 1, bcolor);
            gdImageFilledRectangle(dst, sz.cw - sz.bw, 0, sz.cw - 1, sz.ch - 1, bcolor);
        } else {
            gdImageFilledRectangle(dst, 0, 0, sz.dw, sz.bh, bcolor);
            gdImageFilledRectangle(dst, 0, 0, sz.bw, sz.dh, bcolor);
            gdImageFilledRectangle(dst, 0, sz.dh - sz.bh, sz.dw - 1, sz.dh - 1, bcolor);
            gdImageFilledRectangle(dst, sz.dw - sz.bw, 0, sz.dw - 1, sz.dh - 1, bcolor);
        }
    }

    of = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "of");
    if (ngx_strlen(of) > 0) {
        type = ngx_http_small_light_type(of);
        if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_NONE) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "of is invalid(%s) %s:%d",
                          of,
                          __FUNCTION__,
                          __LINE__);
        } else if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_WEBP) {
#ifdef NGX_HTTP_SMALL_LIGHT_GD_WEBP_ENABLED
            ictx->type = type;
#else
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "WebP is not supported %s:%d",
                          __FUNCTION__,
                          __LINE__);
#endif
        } else {
            ictx->type = type;
        }
    }

    ctx->of = ngx_http_small_light_image_types[ictx->type - 1];

    q = ngx_http_small_light_parse_double(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "q"));
    if (q == 0) {
        q = 100;
    }
    out = ngx_http_small_light_gd_out(dst, ictx->type, (int *)&size, q);
    gdImageDestroy(dst);

    if (out == NULL) {
        return NGX_ERROR;
    }

    /* get small_lighted image as binary. */
    ctx->content        = out;
    ctx->content_length = size;

    ngx_pfree(r->pool, ctx->content_orig);

    ictx->complete = 1;

    return NGX_OK;
}
Esempio n. 14
0
int main(int argc, char **argv)
{
	FILE *in;
	FILE *out;
	char outFn[20];
	int useStdinStdout=0;

	/* Declare our image pointer */
	gdImagePtr im = 0;
	int i;
       /* We'll clear 'no' once we know the user has made a
		reasonable request. */
	int no = 1;
	/* We'll set 'write' once we know the user's request
		requires that the image be written back to disk. */
	int write = 0;
	/* C programs always get at least one argument; we want at
		least one more (the image), more in practice. */
	if (argc < 2 || !strcmp(argv[1], "--help")) {
		no = 1;	
		goto usage;
	}

	/* The last argument should be the image. Open the file. */
	if (strcmp("-", argv[argc-1])==0) { /* - is synonymous with STDIN */
	  useStdinStdout = 1;
	  in = stdin;
	} else {
	  in = fopen(argv[argc-1], "rb");	
	}
	if (!in) {
		fprintf(stderr,
			"Error: can't open file %s.\n", argv[argc-1]);
		exit(1);
	}
	/* Now load the image. */	
	im = gdImageCreateFromPng(in);
	fclose(in);
	/* If the load failed, it must not be a PNG file. */
	if (!im) {
		fprintf(stderr,
			"Error: %s is not a valid PNG file.\n", argv[argc-1]);
		exit(1);	
	}
	/* Consider each argument in turn. */
	for (i=1; (i < (argc-1)); i++) {
		/* -i turns on and off interlacing. */
		if (!strcmp(argv[i], "--help")) { 
		  /* Every program should use this for help! :) */
		  no = 1;
		  goto usage;
		} else if (!strcmp(argv[i], "-i")) {
			if (i == (argc-2)) {
				fprintf(stderr, 
				"Error: -i specified without y or n.\n");
				no = 1;
				goto usage;
			}
			if (!strcmp(argv[i+1], "y")) {
				/* Set interlace. */
				gdImageInterlace(im, 1);
			} else if (!strcmp(argv[i+1], "n")) {
				/* Clear interlace. */
				gdImageInterlace(im, 0);
			} else {
				fprintf(stderr,
				"Error: -i specified without y or n.\n");
				no = 1;
				goto usage;
			}
			i++;
			no = 0;
			write = 1;
		} else if (!strcmp(argv[i], "-t")) {
			/* Set transparent index (or none). */
			int index;
			if (i == (argc-2)) {
				fprintf(stderr,
		"Error: -t specified without a color table index.\n");
				no = 1;
				goto usage;
			}
			if (!strcmp(argv[i+1], "none")) {
				/* -1 means not transparent. */
				gdImageColorTransparent(im, -1);
			} else {
				/* OK, get an integer and set the index. */
				index = atoi(argv[i+1]);
				gdImageColorTransparent(im, index);
			}
			i++;
			write = 1;
			no = 0;
		} else if (!strcmp(argv[i], "-l")) {
			/* List the colors in the color table. */
			int j;
			/* Tabs used below. */
			printf("Index	Red	Green	Blue\n");
			for (j=0; (j < gdImageColorsTotal(im)); j++) {
				/* Use access macros to learn colors. */
				printf("%d	%d	%d	%d\n",
					j, 
					gdImageRed(im, j),
					gdImageGreen(im, j),
					gdImageBlue(im, j));
			}
			no = 0;
		} else if (!strcmp(argv[i], "-d")) {
			/* Output dimensions, etc. */
			int t;
			printf("Width: %d Height: %d Colors: %d\n",
				gdImageSX(im), gdImageSY(im),
				gdImageColorsTotal(im));
			t = gdImageGetTransparent(im);
			if (t != (-1)) {
				printf("Transparent index: %d\n", t);
			} else {
				/* -1 means the image is not transparent. */
				printf("Transparent index: none\n");
			}
			if (gdImageGetInterlaced(im)) {
				printf("Interlaced: yes\n");	
			} else {
				printf("Interlaced: no\n");	
			}
			no = 0;
		} else {
			fprintf(stderr, "Unknown argument: %s\n", argv[i]);
			break;	
		}
	}
usage:
	if (no) {
		/* If the command failed, output an explanation. */
		fprintf(stderr, 
"Usage: webpng [-i y|n ] [-l] [-t index|none ] [-d] pngname.png\n"

"  -i [y|n]   Turns on/off interlace\n"
"  -l         Prints the table of color indexes\n"
"  -t [index] Set the transparent color to the specified index (0-255 or \"none\")\n"
"  -d         Reports the dimensions and other characteristics of the image.\n"
"\n"
"If you specify '-' as the input file, stdin/stdout will be used input/output.\n"
);
	} 
	if (write) {
	  if (useStdinStdout) {
	    out = stdout;
	  } else {
	    /* Open a temporary file. */

	    /* "temp.tmp" is not good temporary filename. */
	    sprintf(outFn, "webpng.tmp%d", getpid());
	    out = fopen(outFn, "wb"); 

	    if (!out) {
	      fprintf(stderr,
		      "Unable to write to %s -- exiting\n", outFn);
	      exit(1);
	    }
	  }

	  /* Write the new PNG. */
	  gdImagePng(im, out);

	  if (!useStdinStdout) {
	    fclose(out);
	    /* Erase the old PNG. */
	    unlink(argv[argc-1]);
	    /* Rename the new to the old. */
	    if (rename(outFn, argv[argc-1])!=0) {
	      perror("rename");
	      exit(1);
	    }
	  }
	}
	/* Delete the image from memory. */
	if (im) {
		gdImageDestroy(im);
	}
	/* All's well that ends well. */
	return 0;
}
Esempio n. 15
0
/* {{{ _php_image_output_ctx */
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
{
	zval *imgind;
	char *file = NULL;
	size_t file_len = 0;
	zend_long quality, basefilter;
	zend_bool compressed = 1;
	gdImagePtr im;
	int argc = ZEND_NUM_ARGS();
	int q = -1, i;
	int f = -1;
	gdIOCtx *ctx = NULL;
	zval *to_zval = NULL;
	php_stream *stream;
	int close_stream = 1;

	/* The third (quality) parameter for Wbmp stands for the foreground when called from image2wbmp().
	 * The third (quality) parameter for Wbmp and Xbm stands for the foreground color index when called
	 * from imagey<type>().
	 */
	switch (image_type) {
		case PHP_GDIMG_TYPE_XBM:
			if (zend_parse_parameters(argc, "rp!|ll", &imgind, &file, &file_len, &quality, &basefilter) == FAILURE) {
				return;
			}
			break;
		case PHP_GDIMG_TYPE_BMP:
			if (zend_parse_parameters(argc, "r|z!b", &imgind, &to_zval, &compressed) == FAILURE) {
				return;
			}
			break;
		default:
			/* PHP_GDIMG_TYPE_GIF
			 * PHP_GDIMG_TYPE_PNG
			 * PHP_GDIMG_TYPE_JPG
			 * PHP_GDIMG_TYPE_WBM
			 * PHP_GDIMG_TYPE_WEBP
			 * */
			if (zend_parse_parameters(argc, "r|z!ll", &imgind, &to_zval, &quality, &basefilter) == FAILURE) {
				return;
			}
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(imgind), "Image", phpi_get_le_gd())) == NULL) {
		RETURN_FALSE;
	}

	if (image_type != PHP_GDIMG_TYPE_BMP && argc >= 3) {
		q = quality; /* or colorindex for foreground of BW images (defaults to black) */
		if (argc == 4) {
			f = basefilter;
		}
	}

	if (argc > 1 && to_zval != NULL) {
		if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
			php_stream_from_zval_no_verify(stream, to_zval);
			if (stream == NULL) {
				RETURN_FALSE;
			}
			close_stream = 0;
		} else if (Z_TYPE_P(to_zval) == IS_STRING) {
			if (CHECK_ZVAL_NULL_PATH(to_zval)) {
				php_error_docref(NULL, E_WARNING, "Invalid 2nd parameter, filename must not contain null bytes");
				RETURN_FALSE;
			}

			stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
			if (stream == NULL) {
				RETURN_FALSE;
			}
		} else {
			php_error_docref(NULL, E_WARNING, "Invalid 2nd parameter, it must a filename or a stream");
			RETURN_FALSE;
		}
	} else if (argc > 1 && file != NULL) {
		stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
		if (stream == NULL) {
			RETURN_FALSE;
		}
	} else {
		ctx = ecalloc(1, sizeof(gdIOCtx));
		ctx->putC = _php_image_output_putc;
		ctx->putBuf = _php_image_output_putbuf;
		ctx->gd_free = _php_image_output_ctxfree;
	}

	if (!ctx)	{
		ctx = ecalloc(1, sizeof(gdIOCtx));
		ctx->putC = _php_image_stream_putc;
		ctx->putBuf = _php_image_stream_putbuf;
		if (close_stream) {
			ctx->gd_free = _php_image_stream_ctxfreeandclose;
		} else {
			ctx->gd_free = _php_image_stream_ctxfree;
		}
		ctx->data = (void *)stream;
	}

	switch(image_type) {
		case PHP_GDIMG_CONVERT_WBM:
			if(q<0||q>255) {
				php_error_docref(NULL, E_WARNING, "Invalid threshold value '%d'. It must be between 0 and 255", q);
			}
		case PHP_GDIMG_TYPE_JPG:
			(*func_p)(im, ctx, q);
			break;
		case PHP_GDIMG_TYPE_WEBP:
			if (q == -1) {
				q = 80;
			}
			(*func_p)(im, ctx, q);
			break;
		case PHP_GDIMG_TYPE_PNG:
			(*func_p)(im, ctx, q, f);
			break;
		case PHP_GDIMG_TYPE_XBM:
		case PHP_GDIMG_TYPE_WBM:
			if (argc < 3) {
				for(i=0; i < gdImageColorsTotal(im); i++) {
					if(!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) break;
				}
				q = i;
			}
			if (image_type == PHP_GDIMG_TYPE_XBM) {
				(*func_p)(im, file ? file : "", q, ctx);
			} else {
				(*func_p)(im, q, ctx);
			}
			break;
		case PHP_GDIMG_TYPE_BMP:
			(*func_p)(im, ctx, (int) compressed);
			break;
		default:
			(*func_p)(im, ctx);
			break;
	}

	ctx->gd_free(ctx);

	RETURN_TRUE;
}
Esempio n. 16
0
/* {{{ _php_image_output_ctx */
static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
{
	zval *imgind;
	char *file = NULL;
	int file_len = 0;
	long quality, basefilter;
	gdImagePtr im;
	FILE *fp = NULL;
	int argc = ZEND_NUM_ARGS();
	int q = -1, i;
	int f = -1;
	gdIOCtx *ctx;

	/* The third (quality) parameter for Wbmp stands for the threshold when called from image2wbmp().
	 * The third (quality) parameter for Wbmp and Xbm stands for the foreground color index when called
	 * from imagey<type>().
	 */

	if (image_type == PHP_GDIMG_TYPE_XBM) {
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs!|ll", &imgind, &file, &file_len, &quality, &basefilter) == FAILURE) {
			return;
		}
	} else {
		/* PHP_GDIMG_TYPE_GIF
		 * PHP_GDIMG_TYPE_PNG 
		 * PHP_GDIMG_TYPE_JPG 
		 * PHP_GDIMG_TYPE_WBM */
		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|s!ll", &imgind, &file, &file_len, &quality, &basefilter) == FAILURE) {
			return;
		}		
	}

	ZEND_FETCH_RESOURCE(im, gdImagePtr, &imgind, -1, "Image", phpi_get_le_gd());

	if (argc > 1) {
		if (argc >= 3) {
			q = quality; /* or colorindex for foreground of BW images (defaults to black) */
			if (argc == 4) {
				f = basefilter;
			}
		}
	}

    if (argc > 1 && file_len) {
		PHP_GD_CHECK_OPEN_BASEDIR(file, "Invalid filename");

		fp = VCWD_FOPEN(file, "wb");
		if (!fp) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open '%s' for writing: %s", file, strerror(errno));
			RETURN_FALSE;
		}

		ctx = gdNewFileCtx(fp);
	} else {
		ctx = emalloc(sizeof(gdIOCtx));
		ctx->putC = _php_image_output_putc;
		ctx->putBuf = _php_image_output_putbuf;
		ctx->gd_free = _php_image_output_ctxfree;
	}

	switch(image_type) {
		case PHP_GDIMG_CONVERT_WBM:
			if(q<0||q>255) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid threshold value '%d'. It must be between 0 and 255", q);
			}
		case PHP_GDIMG_TYPE_JPG:
			(*func_p)(im, ctx, q);
			break;
		case PHP_GDIMG_TYPE_PNG:
			(*func_p)(im, ctx, q, f);
			break;
		case PHP_GDIMG_TYPE_XBM:
		case PHP_GDIMG_TYPE_WBM:
			if (argc < 3) {
				for(i=0; i < gdImageColorsTotal(im); i++) {
					if(!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) break;
				}
				q = i;
			}
			if (image_type == PHP_GDIMG_TYPE_XBM) {
				(*func_p)(im, file, q, ctx);
			} else {
				(*func_p)(im, q, ctx);
			}
			break;
		default:
			(*func_p)(im, ctx);
			break;
	}

	ctx->gd_free(ctx);

	if(fp) {
		fflush(fp);
		fclose(fp);
	}

    RETURN_TRUE;
}
Esempio n. 17
0
int
main (int argc, char **argv)
{
#ifdef HAVE_LIBPNG
  gdImagePtr im, ref, im2, im3;
  FILE *in, *out;
  void *iptr;
  int sz;
  char of[256];
  int colRed, colBlu;
  gdSource imgsrc;
  gdSink imgsnk;
  int foreground;
  int i;
  if (argc != 2)
    {
      fprintf (stderr, "Usage: gdtest filename.png\n");
      exit (1);
    }
  in = fopen (argv[1], "rb");
  if (!in)
    {
      fprintf (stderr, "Input file does not exist!\n");
      exit (1);
    }
  im = gdImageCreateFromPng (in);

  rewind (in);
  ref = gdImageCreateFromPng (in);

  fclose (in);

  printf ("Reference File has %d Palette entries\n", ref->colorsTotal);

  CompareImages ("Initial Versions", ref, im);


  /* */
  /* Send to PNG File then Ptr */
  /* */
#ifdef VMS
  sprintf (of, "%s-png", argv[1]);
#else
  sprintf (of, "%s.png", argv[1]);
#endif
  out = fopen (of, "wb");
  gdImagePng (im, out);
  fclose (out);

  in = fopen (of, "rb");
  if (!in)
    {
      fprintf (stderr, "PNG Output file does not exist!\n");
      exit (1);
    }
  im2 = gdImageCreateFromPng (in);
  fclose (in);

  CompareImages ("GD->PNG File->GD", ref, im2);

  unlink (of);
  gdImageDestroy (im2);

  /* 2.0.21: use the new From*Ptr functions */
  iptr = gdImagePngPtr (im, &sz);
  im2 = gdImageCreateFromPngPtr (sz, iptr);
  gdFree (iptr);
  CompareImages ("GD->PNG ptr->GD", ref, im2);

  gdImageDestroy (im2);

  /* */
  /* Send to GD2 File then Ptr */
  /* */
#ifdef VMS
  sprintf (of, "%s-gd2", argv[1]);
#else
  sprintf (of, "%s.gd2", argv[1]);
#endif
  out = fopen (of, "wb");
  gdImageGd2 (im, out, 128, 2);
  fclose (out);

  in = fopen (of, "rb");
  if (!in)
    {
      fprintf (stderr, "GD2 Output file does not exist!\n");
      exit (1);
    }
  im2 = gdImageCreateFromGd2 (in);
  fclose (in);

  CompareImages ("GD->GD2 File->GD", ref, im2);

  unlink (of);
  gdImageDestroy (im2);

  iptr = gdImageGd2Ptr (im, 128, 2, &sz);
  /*printf("Got ptr %d (size %d)\n",iptr, sz); */
  im2 = gdImageCreateFromGd2Ptr (sz, iptr);
  gdFree (iptr);
  /*printf("Got img2 %d\n",im2); */

  CompareImages ("GD->GD2 ptr->GD", ref, im2);

  gdImageDestroy (im2);

  /* */
  /* Send to GD File then Ptr */
  /* */
#ifdef VMS
  sprintf (of, "%s-gd", argv[1]);
#else
  sprintf (of, "%s.gd", argv[1]);
#endif
  out = fopen (of, "wb");
  gdImageGd (im, out);
  fclose (out);

  in = fopen (of, "rb");
  if (!in)
    {
      fprintf (stderr, "GD Output file does not exist!\n");
      exit (1);
    }
  im2 = gdImageCreateFromGd (in);
  fclose (in);

  CompareImages ("GD->GD File->GD", ref, im2);

  unlink (of);
  gdImageDestroy (im2);

  iptr = gdImageGdPtr (im, &sz);
  /*printf("Got ptr %d (size %d)\n",iptr, sz); */
  im2 = gdImageCreateFromGdPtr (sz, iptr);
  gdFree (iptr);
  /*printf("Got img2 %d\n",im2); */

  CompareImages ("GD->GD ptr->GD", ref, im2);

  gdImageDestroy (im2);

  /*
   * Test gdImageCreateFromPngSource'
   */

  in = fopen (argv[1], "rb");

  imgsrc.source = freadWrapper;
  imgsrc.context = in;
  im2 = gdImageCreateFromPngSource (&imgsrc);
  fclose (in);

  if (im2 == NULL)
    {
      printf
	("GD Source: ERROR Null returned by gdImageCreateFromPngSource\n");
    }
  else
    {
      CompareImages ("GD Source", ref, im2);
      gdImageDestroy (im2);
    };


  /*
   * Test gdImagePngToSink'
   */
#ifdef VMS
  sprintf (of, "%s-snk", argv[1]);
#else
  sprintf (of, "%s.snk", argv[1]);
#endif
  out = fopen (of, "wb");
  imgsnk.sink = fwriteWrapper;
  imgsnk.context = out;
  gdImagePngToSink (im, &imgsnk);
  fclose (out);
  in = fopen (of, "rb");
  if (!in)
    {
      fprintf (stderr,
	       "GD Sink: ERROR - GD Sink Output file does not exist!\n");
    }
  else
    {
      im2 = gdImageCreateFromPng (in);
      fclose (in);

      CompareImages ("GD Sink", ref, im2);
      gdImageDestroy (im2);
    };

  unlink (of);

  /* */
  /*  Test Extraction */
  /* */
  in = fopen ("test/gdtest_200_300_150_100.png", "rb");
  if (!in)
    {
      fprintf (stderr, "gdtest_200_300_150_100.png does not exist!\n");
      exit (1);
    }
  im2 = gdImageCreateFromPng (in);
  fclose (in);


  in = fopen ("test/gdtest.gd2", "rb");
  if (!in)
    {
      fprintf (stderr, "gdtest.gd2 does not exist!\n");
      exit (1);
    }
  im3 = gdImageCreateFromGd2Part (in, 200, 300, 150, 100);
  fclose (in);

  CompareImages ("GD2Part (gdtest_200_300_150_100.png, gdtest.gd2(part))",
		 im2, im3);

  gdImageDestroy (im2);
  gdImageDestroy (im3);

  /* */
  /*  Copy Blend */
  /* */
  in = fopen ("test/gdtest.png", "rb");
  if (!in)
    {
      fprintf (stderr, "gdtest.png does not exist!\n");
      exit (1);
    }
  im2 = gdImageCreateFromPng (in);
  fclose (in);

  im3 = gdImageCreate (100, 60);
  colRed = gdImageColorAllocate (im3, 255, 0, 0);
  colBlu = gdImageColorAllocate (im3, 0, 0, 255);
  gdImageFilledRectangle (im3, 0, 0, 49, 30, colRed);
  gdImageFilledRectangle (im3, 50, 30, 99, 59, colBlu);

  gdImageCopyMerge (im2, im3, 150, 200, 10, 10, 90, 50, 50);
  gdImageCopyMerge (im2, im3, 180, 70, 10, 10, 90, 50, 50);

  gdImageCopyMergeGray (im2, im3, 250, 160, 10, 10, 90, 50, 50);
  gdImageCopyMergeGray (im2, im3, 80, 70, 10, 10, 90, 50, 50);

  gdImageDestroy (im3);

  in = fopen ("test/gdtest_merge.png", "rb");
  if (!in)
    {
      fprintf (stderr, "gdtest_merge.png does not exist!\n");
      exit (1);
    }
  im3 = gdImageCreateFromPng (in);
  fclose (in);

  printf ("[Merged Image has %d colours]\n", im2->colorsTotal);
  CompareImages ("Merged (gdtest.png, gdtest_merge.png)", im2, im3);

  gdImageDestroy (im2);
  gdImageDestroy (im3);

#ifdef HAVE_LIBJPEG
  out = fopen ("test/gdtest.jpg", "wb");
  if (!out)
    {
      fprintf (stderr, "Can't create file test/gdtest.jpg.\n");
      exit (1);
    }
  gdImageJpeg (im, out, -1);
  fclose (out);
  in = fopen ("test/gdtest.jpg", "rb");
  if (!in)
    {
      fprintf (stderr, "Can't open file test/gdtest.jpg.\n");
      exit (1);
    }
  im2 = gdImageCreateFromJpeg (in);
  fclose (in);
  if (!im2)
    {
      fprintf (stderr, "gdImageCreateFromJpeg failed.\n");
      exit (1);
    }
  gdImageDestroy (im2);
  printf ("Created test/gdtest.jpg successfully. Compare this image\n"
	  "to the input image manually. Some difference must be\n"
	  "expected as JPEG is a lossy file format.\n");
#endif /* HAVE_LIBJPEG */
  /* Assume the color closest to black is the foreground
     color for the B&W wbmp image. */
  fprintf (stderr,
	   "NOTE: the WBMP output image will NOT match the original unless the original\n"
	   "is also black and white. This is OK!\n");
  foreground = gdImageColorClosest (im, 0, 0, 0);
  fprintf (stderr, "Foreground index is %d\n", foreground);
  if (foreground == -1)
    {
      fprintf (stderr, "Source image has no colors, skipping wbmp test.\n");
    }
  else
    {
      out = fopen ("test/gdtest.wbmp", "wb");
      if (!out)
	{
	  fprintf (stderr, "Can't create file test/gdtest.wbmp.\n");
	  exit (1);
	}
      gdImageWBMP (im, foreground, out);
      fclose (out);
      in = fopen ("test/gdtest.wbmp", "rb");
      if (!in)
	{
	  fprintf (stderr, "Can't open file test/gdtest.wbmp.\n");
	  exit (1);
	}
      im2 = gdImageCreateFromWBMP (in);
      fprintf (stderr, "WBMP has %d colors\n", gdImageColorsTotal (im2));
      fprintf (stderr, "WBMP colors are:\n");
      for (i = 0; (i < gdImageColorsTotal (im2)); i++)
	{
	  fprintf (stderr, "%02X%02X%02X\n",
		   gdImageRed (im2, i),
		   gdImageGreen (im2, i), gdImageBlue (im2, i));
	}
      fclose (in);
      if (!im2)
	{
	  fprintf (stderr, "gdImageCreateFromWBMP failed.\n");
	  exit (1);
	}
      CompareImages ("WBMP test (gdtest.png, gdtest.wbmp)", ref, im2);
      out = fopen ("test/gdtest_wbmp_to_png.png", "wb");
      if (!out)
	{
	  fprintf (stderr,
		   "Can't create file test/gdtest_wbmp_to_png.png.\n");
	  exit (1);
	}
      gdImagePng (im2, out);
      fclose (out);
      gdImageDestroy (im2);
    }
  gdImageDestroy (im);
  gdImageDestroy (ref);
#else
  fprintf (stderr, "No PNG library support.\n");
#endif /* HAVE_LIBPNG */

  return 0;
}
Esempio n. 18
0
static ngx_buf_t *
ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
{
    int                            sx, sy, dx, dy, ox, oy, ax, ay, size,
                                   colors, palette, transparent, sharpen,
                                   red, green, blue, t;
    u_char                        *out;
    ngx_buf_t                     *b;
    ngx_uint_t                     resize;
    gdImagePtr                     src, dst;
    ngx_pool_cleanup_t            *cln;
    ngx_http_image_filter_conf_t  *conf;

    src = ngx_http_image_source(r, ctx);

    if (src == NULL) {
        return NULL;
    }

    sx = gdImageSX(src);
    sy = gdImageSY(src);

    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);

    if (!ctx->force
        && ctx->angle == 0
        && (ngx_uint_t) sx <= ctx->max_width
        && (ngx_uint_t) sy <= ctx->max_height)
    {
        gdImageDestroy(src);
        return ngx_http_image_asis(r, ctx);
    }

    colors = gdImageColorsTotal(src);

    if (colors && conf->transparency) {
        transparent = gdImageGetTransparent(src);

        if (transparent != -1) {
            palette = colors;
            red = gdImageRed(src, transparent);
            green = gdImageGreen(src, transparent);
            blue = gdImageBlue(src, transparent);

            goto transparent;
        }
    }

    palette = 0;
    transparent = -1;
    red = 0;
    green = 0;
    blue = 0;

transparent:

    gdImageColorTransparent(src, -1);

    dx = sx;
    dy = sy;

    if (conf->filter == NGX_HTTP_IMAGE_RESIZE) {

        if ((ngx_uint_t) dx > ctx->max_width) {
            dy = dy * ctx->max_width / dx;
            dy = dy ? dy : 1;
            dx = ctx->max_width;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            dx = dx * ctx->max_height / dy;
            dx = dx ? dx : 1;
            dy = ctx->max_height;
        }

        resize = 1;

    } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {

        resize = 0;

    } else if (conf->filter == NGX_HTTP_IMAGE_WATERMARK) {

        resize = 0;

    } else { /* NGX_HTTP_IMAGE_CROP */

        resize = 0;

        if ((double) dx / dy < (double) ctx->max_width / ctx->max_height) {
            if ((ngx_uint_t) dx > ctx->max_width) {
                dy = dy * ctx->max_width / dx;
                dy = dy ? dy : 1;
                dx = ctx->max_width;
                resize = 1;
            }

        } else {
            if ((ngx_uint_t) dy > ctx->max_height) {
                dx = dx * ctx->max_height / dy;
                dx = dx ? dx : 1;
                dy = ctx->max_height;
                resize = 1;
            }
        }
    }

    if (resize) {
        dst = ngx_http_image_new(r, dx, dy, palette);
        if (dst == NULL) {
            gdImageDestroy(src);
            return NULL;
        }

        if (colors == 0) {
            gdImageSaveAlpha(dst, 1);
            gdImageAlphaBlending(dst, 0);
        }

        gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);

        if (colors) {
            gdImageTrueColorToPalette(dst, 1, 256);
        }

        gdImageDestroy(src);

    } else {
        dst = src;
    }

    if (ctx->angle) {
        src = dst;

        ax = (dx % 2 == 0) ? 1 : 0;
        ay = (dy % 2 == 0) ? 1 : 0;

        switch (ctx->angle) {

        case 90:
        case 270:
            dst = ngx_http_image_new(r, dy, dx, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }
            if (ctx->angle == 90) {
                ox = dy / 2 + ay;
                oy = dx / 2 - ax;

            } else {
                ox = dy / 2 - ay;
                oy = dx / 2 + ax;
            }

            gdImageCopyRotated(dst, src, ox, oy, 0, 0,
                               dx + ax, dy + ay, ctx->angle);
            gdImageDestroy(src);

            t = dx;
            dx = dy;
            dy = t;
            break;

        case 180:
            dst = ngx_http_image_new(r, dx, dy, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }
            gdImageCopyRotated(dst, src, dx / 2 - ax, dy / 2 - ay, 0, 0,
                               dx + ax, dy + ay, ctx->angle);
            gdImageDestroy(src);
            break;
        }
    }

    if (conf->filter == NGX_HTTP_IMAGE_CROP) {

        src = dst;

        if ((ngx_uint_t) dx > ctx->max_width) {
            ox = dx - ctx->max_width;

        } else {
            ox = 0;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            oy = dy - ctx->max_height;

        } else {
            oy = 0;
        }

        if (ox || oy) {

            dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);

            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }

            ox /= 2;
            oy /= 2;

            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "image crop: %d x %d @ %d x %d",
                           dx, dy, ox, oy);

            if (colors == 0) {
                gdImageSaveAlpha(dst, 1);
                gdImageAlphaBlending(dst, 0);
            }

            gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);

            if (colors) {
                gdImageTrueColorToPalette(dst, 1, 256);
            }

            gdImageDestroy(src);
        }
    }

    if (transparent != -1 && colors) {
        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
    }

    if (conf->filter == NGX_HTTP_IMAGE_WATERMARK && conf->watermark.data) {
        FILE *watermark_file = fopen((const char *)conf->watermark.data, "r");

        if (watermark_file) {
            gdImagePtr watermark, watermark_mix;
            ngx_int_t wdx = 0, wdy = 0;

            watermark = gdImageCreateFromPng(watermark_file);

            if(watermark != NULL) {
                watermark_mix = gdImageCreateTrueColor(watermark->sx, watermark->sy);

                if (ngx_strcmp(conf->watermark_position.data, "bottom-right") == 0) {
                    wdx = dx - watermark->sx - 10;
                    wdy = dy - watermark->sy - 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "top-left") == 0) {
                    wdx = wdy = 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "top-right") == 0) {
                    wdx = dx - watermark->sx - 10;
                    wdy = 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "bottom-left") == 0) {
                    wdx = 10;
                    wdy = dy - watermark->sy - 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "center") == 0) {
                    wdx = dx / 2 - watermark->sx / 2;
                    wdy = dy / 2 - watermark->sy / 2;
                }

                gdImageCopy(watermark_mix, dst, 0, 0, wdx, wdy, watermark->sx, watermark->sy);
                gdImageCopy(watermark_mix, watermark, 0, 0, 0, 0, watermark->sx, watermark->sy);
                gdImageCopyMerge(dst, watermark_mix, wdx, wdy, 0, 0, watermark->sx, watermark->sy, 75);
                gdFree(watermark);
                gdFree(watermark_mix);

            } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "watermark file '%s' is not PNG", conf->watermark.data);}

        } else {

            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "watermark file '%s' not found", conf->watermark.data);
        }
    }

    sharpen = ngx_http_image_filter_get_value(r, conf->shcv, conf->sharpen);
    if (sharpen > 0) {
        gdImageSharpen(dst, sharpen);
    }

    gdImageInterlace(dst, (int) conf->interlace);

    out = ngx_http_image_out(r, ctx->type, dst, &size);

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "image: %d x %d %d", sx, sy, colors);

    gdImageDestroy(dst);
    ngx_pfree(r->pool, ctx->image);

    if (out == NULL) {
        return NULL;
    }

    cln = ngx_pool_cleanup_add(r->pool, 0);
    if (cln == NULL) {
        gdFree(out);
        return NULL;
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        gdFree(out);
        return NULL;
    }

    cln->handler = ngx_http_image_cleanup;
    cln->data = out;

    b->pos = out;
    b->last = out + size;
    b->memory = 1;
    b->last_buf = 1;

    ngx_http_image_length(r, b);

    return b;
}