15 #define NGX_HTTP_IMAGE_OFF 0
16 #define NGX_HTTP_IMAGE_TEST 1
17 #define NGX_HTTP_IMAGE_SIZE 2
18 #define NGX_HTTP_IMAGE_RESIZE 3
19 #define NGX_HTTP_IMAGE_CROP 4
20 #define NGX_HTTP_IMAGE_ROTATE 5
23 #define NGX_HTTP_IMAGE_START 0
24 #define NGX_HTTP_IMAGE_READ 1
25 #define NGX_HTTP_IMAGE_PROCESS 2
26 #define NGX_HTTP_IMAGE_PASS 3
27 #define NGX_HTTP_IMAGE_DONE 4
30 #define NGX_HTTP_IMAGE_NONE 0
31 #define NGX_HTTP_IMAGE_JPEG 1
32 #define NGX_HTTP_IMAGE_GIF 2
33 #define NGX_HTTP_IMAGE_PNG 3
36 #define NGX_HTTP_IMAGE_BUFFERED 0x08
98 gdImagePtr img,
int *size);
99 static void ngx_http_image_cleanup(
void *data);
105 static void *ngx_http_image_filter_create_conf(
ngx_conf_t *cf);
106 static char *ngx_http_image_filter_merge_conf(
ngx_conf_t *cf,
void *parent,
110 static char *ngx_http_image_filter_jpeg_quality(
ngx_conf_t *cf,
121 ngx_http_image_filter,
128 ngx_http_image_filter_jpeg_quality,
135 ngx_http_image_filter_sharpen,
167 ngx_http_image_filter_init,
175 ngx_http_image_filter_create_conf,
176 ngx_http_image_filter_merge_conf
182 &ngx_http_image_filter_module_ctx,
183 ngx_http_image_filter_commands,
200 static ngx_str_t ngx_http_image_types[] = {
215 return ngx_http_next_header_filter(r);
222 return ngx_http_next_header_filter(r);
228 return ngx_http_next_header_filter(r);
232 >=
sizeof(
"multipart/x-mixed-replace") - 1
234 (u_char *)
"multipart/x-mixed-replace",
235 sizeof(
"multipart/x-mixed-replace") - 1)
239 "image filter: multipart/x-mixed-replace response");
253 if (len != -1 && len > (off_t) conf->
buffer_size) {
255 "image filter: too big response: %O", len);
264 ctx->
length = (size_t) len;
290 return ngx_http_next_body_filter(r, in);
296 return ngx_http_next_body_filter(r, in);
299 switch (ctx->
phase) {
303 ctx->
type = ngx_http_image_test(r, in);
310 out.
buf = ngx_http_image_json(r, NULL);
316 return ngx_http_image_send(r, ctx, &out);
321 &ngx_http_image_filter_module,
327 ct = &ngx_http_image_types[ctx->
type - 1];
335 return ngx_http_image_send(r, ctx, in);
344 rc = ngx_http_image_read(r, in);
352 &ngx_http_image_filter_module,
360 out.
buf = ngx_http_image_process(r);
362 if (out.
buf == NULL) {
364 &ngx_http_image_filter_module,
371 return ngx_http_image_send(r, ctx, &out);
375 return ngx_http_next_body_filter(r, in);
379 rc = ngx_http_next_body_filter(r, NULL);
393 rc = ngx_http_next_header_filter(r);
399 rc = ngx_http_next_body_filter(r, in);
422 "image filter: \"%c%c\"", p[0], p[1]);
424 if (p[0] == 0xff && p[1] == 0xd8) {
430 }
else if (p[0] ==
'G' && p[1] ==
'I' && p[2] ==
'F' && p[3] ==
'8'
433 if (p[4] ==
'9' || p[4] ==
'7') {
438 }
else if (p[0] == 0x89 && p[1] ==
'P' && p[2] ==
'N' && p[3] ==
'G'
439 && p[4] == 0x0d && p[5] == 0x0a && p[6] == 0x1a && p[7] == 0x0a)
461 if (ctx->
image == NULL) {
463 if (ctx->
image == NULL) {
472 for (cl = in; cl; cl = cl->
next) {
478 "image buf: %uz", size);
481 size = (rest < size) ? rest : size;
510 rc = ngx_http_image_size(r, ctx);
515 return ngx_http_image_json(r, rc ==
NGX_OK ? ctx : NULL);
518 ctx->
angle = ngx_http_image_filter_get_value(r, conf->
acv, conf->
angle);
526 return ngx_http_image_resize(r, ctx);
534 ctx->
max_height = ngx_http_image_filter_get_value(r, conf->
hcv,
546 return ngx_http_image_asis(r, ctx);
549 return ngx_http_image_resize(r, ctx);
577 ngx_http_image_length(r, b);
582 len =
sizeof(
"{ \"img\" : "
583 "{ \"width\": , \"height\": , \"type\": \"jpeg\" } }" CRLF) - 1
587 if (b->
pos == NULL) {
595 " \"type\": \"%s\" } }" CRLF,
597 ngx_http_image_types[ctx->
type - 1].
data + 6);
599 ngx_http_image_length(r, b);
620 ngx_http_image_length(r, b);
660 if (p[0] == 0xff && p[1] != 0xff) {
663 "JPEG: %02xd %02xd", p[0], p[1]);
667 if ((*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3
668 || *p == 0xc9 || *p == 0xca || *p == 0xcb)
669 && (width == 0 || height == 0))
671 width = p[6] * 256 + p[7];
672 height = p[4] * 256 + p[5];
676 "JPEG: %02xd %02xd", p[1], p[2]);
678 len = p[1] * 256 + p[2];
680 if (*p >= 0xe1 && *p <= 0xef) {
693 if (width == 0 || height == 0) {
697 if (ctx->
length / 20 < app) {
701 "app data size: %uz", app);
712 width = p[7] * 256 + p[6];
713 height = p[9] * 256 + p[8];
723 width = p[18] * 256 + p[19];
724 height = p[22] * 256 + p[23];
734 "image size: %d x %d", width, height);
746 int sx, sy, dx, dy, ox, oy, ax, ay, size,
747 colors, palette, transparent, sharpen,
756 src = ngx_http_image_source(r, ctx);
773 return ngx_http_image_asis(r, ctx);
776 colors = gdImageColorsTotal(src);
779 transparent = gdImageGetTransparent(src);
781 if (transparent != -1) {
783 red = gdImageRed(src, transparent);
784 green = gdImageGreen(src, transparent);
785 blue = gdImageBlue(src, transparent);
799 gdImageColorTransparent(src, -1);
847 dst = ngx_http_image_new(r, dx, dy, palette);
854 gdImageSaveAlpha(dst, 1);
855 gdImageAlphaBlending(dst, 0);
858 gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);
861 gdImageTrueColorToPalette(dst, 1, 256);
873 ax = (dx % 2 == 0) ? 1 : 0;
874 ay = (dy % 2 == 0) ? 1 : 0;
876 switch (ctx->
angle) {
880 dst = ngx_http_image_new(r, dy, dx, palette);
885 if (ctx->
angle == 90) {
894 gdImageCopyRotated(dst, src, ox, oy, 0, 0,
895 dx + ax, dy + ay, ctx->
angle);
904 dst = ngx_http_image_new(r, dx, dy, palette);
909 gdImageCopyRotated(dst, src, dx / 2 - ax, dy / 2 - ay, 0, 0,
910 dx + ax, dy + ay, ctx->
angle);
936 dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);
947 "image crop: %d x %d @ %d x %d",
951 gdImageSaveAlpha(dst, 1);
952 gdImageAlphaBlending(dst, 0);
955 gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);
958 gdImageTrueColorToPalette(dst, 1, 256);
965 if (transparent != -1 && colors) {
966 gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
969 sharpen = ngx_http_image_filter_get_value(r, conf->
shcv, conf->
sharpen);
971 gdImageSharpen(dst, sharpen);
974 gdImageInterlace(dst, (
int) conf->
interlace);
976 out = ngx_http_image_out(r, ctx->
type, dst, &size);
979 "image: %d x %d %d", sx, sy, colors);
1000 cln->
handler = ngx_http_image_cleanup;
1004 b->
last = out + size;
1008 ngx_http_image_length(r, b);
1022 switch (ctx->
type) {
1025 img = gdImageCreateFromJpegPtr(ctx->
length, ctx->
image);
1026 failed =
"gdImageCreateFromJpegPtr() failed";
1030 img = gdImageCreateFromGifPtr(ctx->
length, ctx->
image);
1031 failed =
"gdImageCreateFromGifPtr() failed";
1035 img = gdImageCreateFromPngPtr(ctx->
length, ctx->
image);
1036 failed =
"gdImageCreateFromPngPtr() failed";
1040 failed =
"unknown image type";
1058 img = gdImageCreateTrueColor(w, h);
1062 "gdImageCreateTrueColor() failed");
1067 img = gdImageCreate(w, h);
1071 "gdImageCreate() failed");
1101 out = gdImageJpegPtr(img, size, jq);
1102 failed =
"gdImageJpegPtr() failed";
1106 out = gdImageGifPtr(img, size);
1107 failed =
"gdImageGifPtr() failed";
1111 out = gdImagePngPtr(img, size);
1112 failed =
"gdImagePngPtr() failed";
1116 failed =
"unknown image type";
1129 ngx_http_image_cleanup(
void *data)
1149 return ngx_http_image_filter_value(&val);
1154 ngx_http_image_filter_value(
ngx_str_t *value)
1158 if (value->
len == 1 && value->
data[0] ==
'-') {
1173 ngx_http_image_filter_create_conf(
ngx_conf_t *cf)
1207 ngx_http_image_filter_merge_conf(
ngx_conf_t *cf,
void *parent,
void *child)
1233 if (conf->
jqcv == NULL) {
1241 if (conf->
shcv == NULL) {
1276 }
else if (
ngx_strcmp(value[i].data,
"test") == 0) {
1279 }
else if (
ngx_strcmp(value[i].data,
"size") == 0) {
1290 if (
ngx_strcmp(value[i].data,
"rotate") == 0) {
1308 n = ngx_http_image_filter_value(&value[i]);
1310 if (n != 90 && n != 180 && n != 270) {
1319 if (imcf->
acv == NULL) {
1333 if (
ngx_strcmp(value[i].data,
"resize") == 0) {
1336 }
else if (
ngx_strcmp(value[i].data,
"crop") == 0) {
1354 n = ngx_http_image_filter_value(&value[i]);
1364 if (imcf->
wcv == NULL) {
1382 n = ngx_http_image_filter_value(&value[i]);
1392 if (imcf->
hcv == NULL) {
1426 ccv.
value = &value[1];
1434 n = ngx_http_image_filter_value(&value[1]);
1438 "invalid value \"%V\"", &value[1]);
1446 if (imcf->
jqcv == NULL) {
1473 ccv.
value = &value[1];
1481 n = ngx_http_image_filter_value(&value[1]);
1485 "invalid value \"%V\"", &value[1]);
1493 if (imcf->
shcv == NULL) {