summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2009-10-26 16:56:49 +0000
committerIgor Sysoev <igor@sysoev.ru>2009-10-26 16:56:49 +0000
commitf3c5789e7d3ad2e124079c388ee90c6d54c18495 (patch)
treecdd258b3b3a40923405dd99f958707f4987919d4
parent99daa8e5d4e83174b9a8c0360d4e52a8a9dac4c5 (diff)
downloadnginx-f3c5789e7d3ad2e124079c388ee90c6d54c18495.tar.gz
nginx-f3c5789e7d3ad2e124079c388ee90c6d54c18495.tar.bz2
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
-rw-r--r--src/http/modules/ngx_http_image_filter_module.c241
1 files changed, 192 insertions, 49 deletions
diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c
index 469d703f6..9a4dafe05 100644
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -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) {
+ return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
+ }
- b = ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
+ ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
+ if (ctx->max_width == 0) {
+ return NULL;
+ }
- } else if (rc == NGX_OK
- && ctx->width <= conf->width
- && ctx->height <= conf->height)
- {
- b = ngx_http_image_asis(r, ctx);
+ ctx->max_height = ngx_http_image_filter_get_value(r, conf->hcv,
+ conf->height);
+ if (ctx->max_height == 0) {
+ return NULL;
+ }
- } else {
- b = ngx_http_image_resize(r, ctx);
+ if (rc == NGX_OK
+ && ctx->width <= ctx->max_width
+ && ctx->height <= ctx->max_height)
+ {
+ return ngx_http_image_asis(r, ctx);
}
- return b;
+ 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;
+
+ } else {
+ imcf->wcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+ if (imcf->wcv == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *imcf->wcv = cv;
}
- i++;
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
- if (value[i].len == 1 && value[i].data[0] == '-') {
- imcf->height = (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->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;