merge r2999, r3118, r3134, r3135:

various image filter fixes and features:

*) variables support in image_filter
*) fix transparency in GIF
*) fix alpha-channel transparency in PNG
*) image_filter_transparency
This commit is contained in:
Igor Sysoev 2009-10-26 16:56:49 +00:00
parent 66e573174e
commit 8d1d7b5aaa
1 changed files with 197 additions and 54 deletions

View File

@ -40,6 +40,11 @@ typedef struct {
ngx_uint_t height;
ngx_int_t jpeg_quality;
ngx_flag_t transparency;
ngx_http_complex_value_t *wcv;
ngx_http_complex_value_t *hcv;
size_t buffer_size;
} ngx_http_image_filter_conf_t;
@ -53,6 +58,9 @@ typedef struct {
ngx_uint_t width;
ngx_uint_t height;
ngx_uint_t max_width;
ngx_uint_t max_height;
ngx_uint_t phase;
ngx_uint_t type;
} ngx_http_image_filter_ctx_t;
@ -80,6 +88,9 @@ static gdImagePtr ngx_http_image_new(ngx_http_request_t *r, int w, int h,
static u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type,
gdImagePtr img, int *size);
static void ngx_http_image_cleanup(void *data);
static ngx_uint_t ngx_http_image_filter_get_value(ngx_http_request_t *r,
ngx_http_complex_value_t *cv, ngx_uint_t v);
static ngx_uint_t ngx_http_image_filter_value(ngx_str_t *value);
static void *ngx_http_image_filter_create_conf(ngx_conf_t *cf);
@ -106,6 +117,13 @@ static ngx_command_t ngx_http_image_filter_commands[] = {
offsetof(ngx_http_image_filter_conf_t, jpeg_quality),
NULL },
{ ngx_string("image_filter_transparency"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_image_filter_conf_t, transparency),
NULL },
{ ngx_string("image_filter_buffer"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
@ -454,7 +472,6 @@ ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in)
static ngx_buf_t *
ngx_http_image_process(ngx_http_request_t *r)
{
ngx_buf_t *b;
ngx_int_t rc;
ngx_http_image_filter_ctx_t *ctx;
ngx_http_image_filter_conf_t *conf;
@ -468,20 +485,28 @@ ngx_http_image_process(ngx_http_request_t *r)
conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
b = ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
} else if (rc == NGX_OK
&& ctx->width <= conf->width
&& ctx->height <= conf->height)
{
b = ngx_http_image_asis(r, ctx);
} else {
b = ngx_http_image_resize(r, ctx);
return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
}
return b;
ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
if (ctx->max_width == 0) {
return NULL;
}
ctx->max_height = ngx_http_image_filter_get_value(r, conf->hcv,
conf->height);
if (ctx->max_height == 0) {
return NULL;
}
if (rc == NGX_OK
&& ctx->width <= ctx->max_width
&& ctx->height <= ctx->max_height)
{
return ngx_http_image_asis(r, ctx);
}
return ngx_http_image_resize(r, ctx);
}
@ -662,8 +687,9 @@ ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
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,
colors, transparent, size;
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;
@ -682,29 +708,53 @@ ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
if ((ngx_uint_t) sx <= conf->width && (ngx_uint_t) sy <= conf->height) {
if ((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);
transparent = gdImageGetTransparent(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 > conf->width) {
dy = dy * conf->width / dx;
if ((ngx_uint_t) dx > ctx->max_width) {
dy = dy * ctx->max_width / dx;
dy = dy ? dy : 1;
dx = conf->width;
dx = ctx->max_width;
}
if ((ngx_uint_t) dy > conf->height) {
dx = dx * conf->height / dy;
if ((ngx_uint_t) dy > ctx->max_height) {
dx = dx * ctx->max_height / dy;
dx = dx ? dx : 1;
dy = conf->height;
dy = ctx->max_height;
}
resize = 1;
@ -713,34 +763,44 @@ ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
resize = 0;
if ((ngx_uint_t) (dx * 100 / dy) < conf->width * 100 / conf->height) {
if ((ngx_uint_t) dx > conf->width) {
dy = dy * conf->width / dx;
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 = conf->width;
dx = ctx->max_width;
resize = 1;
}
} else {
if ((ngx_uint_t) dy > conf->height) {
dx = dx * conf->height / dy;
if ((ngx_uint_t) dy > ctx->max_height) {
dx = dx * ctx->max_height / dy;
dx = dx ? dx : 1;
dy = conf->height;
dy = ctx->max_height;
resize = 1;
}
}
}
if (resize) {
dst = ngx_http_image_new(r, dx, dy, colors);
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 {
@ -751,15 +811,15 @@ ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
src = dst;
if ((ngx_uint_t) dx > conf->width) {
ox = dx - conf->width;
if ((ngx_uint_t) dx > ctx->max_width) {
ox = dx - ctx->max_width;
} else {
ox = 0;
}
if ((ngx_uint_t) dy > conf->height) {
oy = dy - conf->height;
if ((ngx_uint_t) dy > ctx->max_height) {
oy = dy - ctx->max_height;
} else {
oy = 0;
@ -781,13 +841,24 @@ ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
"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);
}
}
gdImageColorTransparent(dst, transparent);
if (transparent != -1 && colors) {
gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
}
out = ngx_http_image_out(r, ctx->type, dst, &size);
@ -941,6 +1012,43 @@ ngx_http_image_cleanup(void *data)
}
static ngx_uint_t
ngx_http_image_filter_get_value(ngx_http_request_t *r,
ngx_http_complex_value_t *cv, ngx_uint_t v)
{
ngx_str_t val;
if (cv == NULL) {
return v;
}
if (ngx_http_complex_value(r, cv, &val) != NGX_OK) {
return 0;
}
return ngx_http_image_filter_value(&val);
}
static ngx_uint_t
ngx_http_image_filter_value(ngx_str_t *value)
{
ngx_int_t n;
if (value->len == 1 && value->data[0] == '-') {
return (ngx_uint_t) -1;
}
n = ngx_atoi(value->data, value->len);
if (n > 0) {
return (ngx_uint_t) n;
}
return 0;
}
static void *
ngx_http_image_filter_create_conf(ngx_conf_t *cf)
{
@ -953,6 +1061,7 @@ ngx_http_image_filter_create_conf(ngx_conf_t *cf)
conf->filter = NGX_CONF_UNSET_UINT;
conf->jpeg_quality = NGX_CONF_UNSET;
conf->transparency = NGX_CONF_UNSET;
conf->buffer_size = NGX_CONF_UNSET_SIZE;
return conf;
@ -974,12 +1083,16 @@ ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
conf->filter = prev->filter;
conf->width = prev->width;
conf->height = prev->height;
conf->wcv = prev->wcv;
conf->hcv = prev->hcv;
}
}
/* 75 is libjpeg default quality */
ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75);
ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
1 * 1024 * 1024);
@ -992,9 +1105,11 @@ ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_image_filter_conf_t *imcf = conf;
ngx_str_t *value;
ngx_int_t n;
ngx_uint_t i;
ngx_str_t *value;
ngx_int_t n;
ngx_uint_t i;
ngx_http_complex_value_t cv;
ngx_http_compile_complex_value_t ccv;
value = cf->args->elts;
@ -1027,32 +1142,60 @@ ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
goto failed;
}
i++;
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
if (value[i].len == 1 && value[i].data[0] == '-') {
imcf->width = (ngx_uint_t) -1;
ccv.cf = cf;
ccv.value = &value[++i];
ccv.complex_value = &cv;
} else {
n = ngx_atoi(value[i].data, value[i].len);
if (n == NGX_ERROR) {
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (cv.lengths == NULL) {
n = ngx_http_image_filter_value(&value[i]);
if (n == 0) {
goto failed;
}
imcf->width = (ngx_uint_t) n;
}
i++;
if (value[i].len == 1 && value[i].data[0] == '-') {
imcf->height = (ngx_uint_t) -1;
} else {
n = ngx_atoi(value[i].data, value[i].len);
if (n == NGX_ERROR) {
imcf->wcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (imcf->wcv == NULL) {
return NGX_CONF_ERROR;
}
*imcf->wcv = cv;
}
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[++i];
ccv.complex_value = &cv;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (cv.lengths == NULL) {
n = ngx_http_image_filter_value(&value[i]);
if (n == 0) {
goto failed;
}
imcf->height = (ngx_uint_t) n;
} else {
imcf->hcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (imcf->hcv == NULL) {
return NGX_CONF_ERROR;
}
*imcf->hcv = cv;
}
return NGX_CONF_OK;