Mercurial > hg > nginx-vendor-0-7
diff src/http/modules/ngx_http_image_filter_module.c @ 502:89dc5654117c NGINX_0_7_63
nginx 0.7.63
*) Security: now "/../" are disabled in "Destination" request header
line.
*) Change: minimum supported OpenSSL version is 0.9.7.
*) Change: the "ask" parameter of the "ssl_verify_client" directive was
changed to the "optional" parameter and now it checks a client
certificate if it was offered.
Thanks to Brice Figureau.
*) Feature: now the "-V" switch shows TLS SNI support.
*) Feature: the $ssl_client_verify variable.
Thanks to Brice Figureau.
*) Feature: the "ssl_crl" directive.
Thanks to Brice Figureau.
*) Bugfix: the $ssl_client_cert variable usage corrupted memory; the
bug had appeared in 0.7.7.
Thanks to Sergey Zhuravlev.
*) Feature: now the start cache loader runs in a separate process; this
should improve large caches handling.
*) Feature: now temporary files and permanent storage area may reside
at different file systems.
*) Bugfix: nginx counted incorrectly disk cache size.
*) Change: now directive "gzip_disable msie6" does not disable gzipping
for MSIE 6.0 SV1.
*) Bugfix: nginx always added "Vary: Accept-Encoding" response header
line, if both "gzip_static" and "gzip_vary" were on.
*) Feature: the "proxy" parameter of the "geo" directive.
*) Feature: the ngx_http_geoip_module.
*) Feature: the "limit_rate_after" directive.
Thanks to Ivan Debnar.
*) Feature: the "limit_req_log_level" and "limit_conn_log_level"
directives.
*) Bugfix: now "limit_req" directive conforms to the leaky bucket
algorithm.
Thanks to Maxim Dounin.
*) Bugfix: in ngx_http_limit_req_module.
Thanks to Maxim Dounin.
*) Bugfix: now nginx allows underscores in a request method.
*) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did
not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate",
"X-Accel-Buffering", and "X-Accel-Charset" lines from backend
response header.
Thanks to Maxim Dounin.
*) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend
response header lines; the bug had appeared in 0.7.44.
Thanks to Maxim Dounin.
*) Feature: the "image_filter_transparency" directive.
*) Feature: the "image_filter" directive supports variables for setting
size.
*) Bugfix: in PNG alpha-channel support in the
ngx_http_image_filter_module.
*) Bugfix: in transparency support in the ngx_http_image_filter_module.
*) Feature: now several "perl_modules" directives may be used.
*) Bugfix: ngx_http_perl_module responses did not work in subrequests.
*) Bugfix: nginx sent '\0' in a "Location" response header line on
MKCOL request.
Thanks to Xie Zhenye.
*) Bugfix: an "error_page" directive did not redirect a 413 error; the
bug had appeared in 0.6.10.
*) Bugfix: in memory allocation error handling.
Thanks to Maxim Dounin and Kirill A. Korinskiy.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 26 Oct 2009 00:00:00 +0300 |
parents | 116d5de7cbb6 |
children | 68c0ae0a4959 |
line wrap: on
line diff
--- 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 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_fil 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 * 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_ 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); + return 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); + ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width); + if (ctx->max_width == 0) { + return NULL; } - return b; + 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 * 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 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 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 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 "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) { @@ -948,11 +1056,12 @@ ngx_http_image_filter_create_conf(ngx_co conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_image_filter_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } 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_con 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, ng { 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, ng goto failed; } - i++; + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[++i]; + ccv.complex_value = &cv; - if (value[i].len == 1 && value[i].data[0] == '-') { - imcf->width = (ngx_uint_t) -1; + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } - } else { - n = ngx_atoi(value[i].data, value[i].len); - if (n == NGX_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)); + + ccv.cf = cf; + ccv.value = &value[++i]; + ccv.complex_value = &cv; - if (value[i].len == 1 && value[i].data[0] == '-') { - imcf->height = (ngx_uint_t) -1; + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } - } else { - n = ngx_atoi(value[i].data, value[i].len); - if (n == NGX_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;