comparison src/http/modules/ngx_http_image_filter_module.c @ 661:b9763778e212 NGINX_0_9_7

nginx 0.9.7 *) Feature: now keepalive connections may be closed premature, if there are no free worker connections. Thanks to Maxim Dounin. *) Feature: the "rotate" parameter of the "image_filter" directive. Thanks to Adam Bocim. *) Bugfix: a case when a backend in "fastcgi_pass", "scgi_pass", or "uwsgi_pass" directives is given by expression and refers to a defined upstream.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Apr 2011 00:00:00 +0400
parents 3436cf38d59e
children b4dcae568a2a
comparison
equal deleted inserted replaced
660:fcda3d3eb4ff 661:b9763778e212
14 #define NGX_HTTP_IMAGE_OFF 0 14 #define NGX_HTTP_IMAGE_OFF 0
15 #define NGX_HTTP_IMAGE_TEST 1 15 #define NGX_HTTP_IMAGE_TEST 1
16 #define NGX_HTTP_IMAGE_SIZE 2 16 #define NGX_HTTP_IMAGE_SIZE 2
17 #define NGX_HTTP_IMAGE_RESIZE 3 17 #define NGX_HTTP_IMAGE_RESIZE 3
18 #define NGX_HTTP_IMAGE_CROP 4 18 #define NGX_HTTP_IMAGE_CROP 4
19 #define NGX_HTTP_IMAGE_ROTATE 5
19 20
20 21
21 #define NGX_HTTP_IMAGE_START 0 22 #define NGX_HTTP_IMAGE_START 0
22 #define NGX_HTTP_IMAGE_READ 1 23 #define NGX_HTTP_IMAGE_READ 1
23 #define NGX_HTTP_IMAGE_PROCESS 2 24 #define NGX_HTTP_IMAGE_PROCESS 2
36 37
37 typedef struct { 38 typedef struct {
38 ngx_uint_t filter; 39 ngx_uint_t filter;
39 ngx_uint_t width; 40 ngx_uint_t width;
40 ngx_uint_t height; 41 ngx_uint_t height;
42 ngx_uint_t angle;
41 ngx_uint_t jpeg_quality; 43 ngx_uint_t jpeg_quality;
42 44
43 ngx_flag_t transparency; 45 ngx_flag_t transparency;
44 46
45 ngx_http_complex_value_t *wcv; 47 ngx_http_complex_value_t *wcv;
46 ngx_http_complex_value_t *hcv; 48 ngx_http_complex_value_t *hcv;
49 ngx_http_complex_value_t *acv;
47 ngx_http_complex_value_t *jqcv; 50 ngx_http_complex_value_t *jqcv;
48 51
49 size_t buffer_size; 52 size_t buffer_size;
50 } ngx_http_image_filter_conf_t; 53 } ngx_http_image_filter_conf_t;
51 54
56 59
57 size_t length; 60 size_t length;
58 61
59 ngx_uint_t width; 62 ngx_uint_t width;
60 ngx_uint_t height; 63 ngx_uint_t height;
61
62 ngx_uint_t max_width; 64 ngx_uint_t max_width;
63 ngx_uint_t max_height; 65 ngx_uint_t max_height;
66 ngx_uint_t angle;
64 67
65 ngx_uint_t phase; 68 ngx_uint_t phase;
66 ngx_uint_t type; 69 ngx_uint_t type;
67 ngx_uint_t force; 70 ngx_uint_t force;
68 } ngx_http_image_filter_ctx_t; 71 } ngx_http_image_filter_ctx_t;
106 109
107 110
108 static ngx_command_t ngx_http_image_filter_commands[] = { 111 static ngx_command_t ngx_http_image_filter_commands[] = {
109 112
110 { ngx_string("image_filter"), 113 { ngx_string("image_filter"),
111 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13, 114 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13|NGX_CONF_TAKE2,
112 ngx_http_image_filter, 115 ngx_http_image_filter,
113 NGX_HTTP_LOC_CONF_OFFSET, 116 NGX_HTTP_LOC_CONF_OFFSET,
114 0, 117 0,
115 NULL }, 118 NULL },
116 119
490 493
491 if (conf->filter == NGX_HTTP_IMAGE_SIZE) { 494 if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
492 return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL); 495 return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
493 } 496 }
494 497
498 ctx->angle = ngx_http_image_filter_get_value(r, conf->acv, conf->angle);
499
500 if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
501
502 if (ctx->angle != 90 && ctx->angle != 180 && ctx->angle != 270) {
503 return NULL;
504 }
505
506 return ngx_http_image_resize(r, ctx);
507 }
508
495 ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width); 509 ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
496 if (ctx->max_width == 0) { 510 if (ctx->max_width == 0) {
497 return NULL; 511 return NULL;
498 } 512 }
499 513
504 } 518 }
505 519
506 if (rc == NGX_OK 520 if (rc == NGX_OK
507 && ctx->width <= ctx->max_width 521 && ctx->width <= ctx->max_width
508 && ctx->height <= ctx->max_height 522 && ctx->height <= ctx->max_height
523 && ctx->angle == 0
509 && !ctx->force) 524 && !ctx->force)
510 { 525 {
511 return ngx_http_image_asis(r, ctx); 526 return ngx_http_image_asis(r, ctx);
512 } 527 }
513 528
708 static ngx_buf_t * 723 static ngx_buf_t *
709 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) 724 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
710 { 725 {
711 int sx, sy, dx, dy, ox, oy, size, 726 int sx, sy, dx, dy, ox, oy, size,
712 colors, palette, transparent, 727 colors, palette, transparent,
713 red, green, blue; 728 red, green, blue, t;
714 u_char *out; 729 u_char *out;
715 ngx_buf_t *b; 730 ngx_buf_t *b;
716 ngx_uint_t resize; 731 ngx_uint_t resize;
717 gdImagePtr src, dst; 732 gdImagePtr src, dst;
718 ngx_pool_cleanup_t *cln; 733 ngx_pool_cleanup_t *cln;
728 sy = gdImageSY(src); 743 sy = gdImageSY(src);
729 744
730 conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); 745 conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
731 746
732 if (!ctx->force 747 if (!ctx->force
748 && ctx->angle == 0
733 && (ngx_uint_t) sx <= ctx->max_width 749 && (ngx_uint_t) sx <= ctx->max_width
734 && (ngx_uint_t) sy <= ctx->max_height) 750 && (ngx_uint_t) sy <= ctx->max_height)
735 { 751 {
736 gdImageDestroy(src); 752 gdImageDestroy(src);
737 return ngx_http_image_asis(r, ctx); 753 return ngx_http_image_asis(r, ctx);
778 dx = dx ? dx : 1; 794 dx = dx ? dx : 1;
779 dy = ctx->max_height; 795 dy = ctx->max_height;
780 } 796 }
781 797
782 resize = 1; 798 resize = 1;
799
800 } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
801
802 resize = 0;
783 803
784 } else { /* NGX_HTTP_IMAGE_CROP */ 804 } else { /* NGX_HTTP_IMAGE_CROP */
785 805
786 resize = 0; 806 resize = 0;
787 807
827 847
828 } else { 848 } else {
829 dst = src; 849 dst = src;
830 } 850 }
831 851
832 if (conf->filter == NGX_HTTP_IMAGE_CROP) { 852 if (ctx->angle) {
833
834 src = dst; 853 src = dst;
835 854
836 if ((ngx_uint_t) dx > ctx->max_width) { 855 switch (ctx->angle) {
837 ox = dx - ctx->max_width; 856
838 857 case 90:
839 } else { 858 case 270:
840 ox = 0; 859 dst = ngx_http_image_new(r, dy, dx, palette);
841 }
842
843 if ((ngx_uint_t) dy > ctx->max_height) {
844 oy = dy - ctx->max_height;
845
846 } else {
847 oy = 0;
848 }
849
850 if (ox || oy) {
851
852 dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);
853
854 if (dst == NULL) { 860 if (dst == NULL) {
855 gdImageDestroy(src); 861 gdImageDestroy(src);
856 return NULL; 862 return NULL;
857 } 863 }
864 gdImageCopyRotated(dst, src, dy/2, dx/2, 0, 0, dx, dy, ctx->angle);
865 gdImageDestroy(src);
866 break;
867
868 case 180:
869 dst = ngx_http_image_new(r, dx, dy, palette);
870 if (dst == NULL) {
871 gdImageDestroy(src);
872 return NULL;
873 }
874 gdImageCopyRotated(dst, src, dx/2, dy/2, 0, 0, dx, dy, ctx->angle);
875 gdImageDestroy(src);
876 break;
877 }
878
879 t = dx;
880 dx = dy;
881 dy = t;
882 }
883
884 if (conf->filter == NGX_HTTP_IMAGE_CROP) {
885
886 src = dst;
887
888 if ((ngx_uint_t) dx > ctx->max_width) {
889 ox = dx - ctx->max_width;
890
891 } else {
892 ox = 0;
893 }
894
895 if ((ngx_uint_t) dy > ctx->max_height) {
896 oy = dy - ctx->max_height;
897
898 } else {
899 oy = 0;
900 }
901
902 if (ox || oy) {
903
904 dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);
905
906 if (dst == NULL) {
907 gdImageDestroy(src);
908 return NULL;
909 }
858 910
859 ox /= 2; 911 ox /= 2;
860 oy /= 2; 912 oy /= 2;
861 913
862 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 914 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1088 return NULL; 1140 return NULL;
1089 } 1141 }
1090 1142
1091 conf->filter = NGX_CONF_UNSET_UINT; 1143 conf->filter = NGX_CONF_UNSET_UINT;
1092 conf->jpeg_quality = NGX_CONF_UNSET_UINT; 1144 conf->jpeg_quality = NGX_CONF_UNSET_UINT;
1145 conf->angle = NGX_CONF_UNSET_UINT;
1093 conf->transparency = NGX_CONF_UNSET; 1146 conf->transparency = NGX_CONF_UNSET;
1094 conf->buffer_size = NGX_CONF_UNSET_SIZE; 1147 conf->buffer_size = NGX_CONF_UNSET_SIZE;
1095 1148
1096 return conf; 1149 return conf;
1097 } 1150 }
1122 1175
1123 if (conf->jqcv == NULL) { 1176 if (conf->jqcv == NULL) {
1124 conf->jqcv = prev->jqcv; 1177 conf->jqcv = prev->jqcv;
1125 } 1178 }
1126 1179
1180 ngx_conf_merge_uint_value(conf->angle, prev->angle, 0);
1181 if (conf->acv == NULL) {
1182 conf->acv = prev->acv;
1183 }
1184
1127 ngx_conf_merge_value(conf->transparency, prev->transparency, 1); 1185 ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
1128 1186
1129 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 1187 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
1130 1 * 1024 * 1024); 1188 1 * 1024 * 1024);
1131 1189
1161 } else { 1219 } else {
1162 goto failed; 1220 goto failed;
1163 } 1221 }
1164 1222
1165 return NGX_CONF_OK; 1223 return NGX_CONF_OK;
1224
1225 } else if (cf->args->nelts == 3) {
1226
1227 if (ngx_strcmp(value[i].data, "rotate") == 0) {
1228 imcf->filter = NGX_HTTP_IMAGE_ROTATE;
1229
1230 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1231
1232 ccv.cf = cf;
1233 ccv.value = &value[++i];
1234 ccv.complex_value = &cv;
1235
1236 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1237 return NGX_CONF_ERROR;
1238 }
1239
1240 if (cv.lengths == NULL) {
1241 n = ngx_http_image_filter_value(&value[i]);
1242
1243 if (n != 90 && n != 180 && n != 270) {
1244 goto failed;
1245 }
1246
1247 imcf->angle = (ngx_uint_t) n;
1248
1249 } else {
1250 imcf->acv = ngx_palloc(cf->pool,
1251 sizeof(ngx_http_complex_value_t));
1252 if (imcf->acv == NULL) {
1253 return NGX_CONF_ERROR;
1254 }
1255
1256 *imcf->acv = cv;
1257 }
1258
1259 return NGX_CONF_OK;
1260
1261 } else {
1262 goto failed;
1263 }
1166 } 1264 }
1167 1265
1168 if (ngx_strcmp(value[i].data, "resize") == 0) { 1266 if (ngx_strcmp(value[i].data, "resize") == 0) {
1169 imcf->filter = NGX_HTTP_IMAGE_RESIZE; 1267 imcf->filter = NGX_HTTP_IMAGE_RESIZE;
1170 1268