Mercurial > hg > nginx
comparison src/http/modules/ngx_http_image_filter_module.c @ 3878:7562ee4feb74
image filter rotate
patch by Adam Bocim
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 04 Apr 2011 09:57:32 +0000 |
parents | f5fa9d2e09b6 |
children | ea712f4dc030 |
comparison
equal
deleted
inserted
replaced
3877:ff3620a6b92e | 3878:7562ee4feb74 |
---|---|
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 |