Mercurial > hg > nginx-ranges
comparison src/http/modules/ngx_http_image_filter_module.c @ 578:f3a9e57d2e17
Merge with current.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 11 Mar 2010 21:27:17 +0300 |
parents | 2da4537168f8 |
children | 8246d8a2c2be |
comparison
equal
deleted
inserted
replaced
539:5f4de8cf0d9d | 578:f3a9e57d2e17 |
---|---|
38 ngx_uint_t filter; | 38 ngx_uint_t filter; |
39 ngx_uint_t width; | 39 ngx_uint_t width; |
40 ngx_uint_t height; | 40 ngx_uint_t height; |
41 ngx_int_t jpeg_quality; | 41 ngx_int_t jpeg_quality; |
42 | 42 |
43 ngx_flag_t transparency; | |
44 | |
43 ngx_http_complex_value_t *wcv; | 45 ngx_http_complex_value_t *wcv; |
44 ngx_http_complex_value_t *hcv; | 46 ngx_http_complex_value_t *hcv; |
45 | 47 |
46 size_t buffer_size; | 48 size_t buffer_size; |
47 } ngx_http_image_filter_conf_t; | 49 } ngx_http_image_filter_conf_t; |
59 ngx_uint_t max_width; | 61 ngx_uint_t max_width; |
60 ngx_uint_t max_height; | 62 ngx_uint_t max_height; |
61 | 63 |
62 ngx_uint_t phase; | 64 ngx_uint_t phase; |
63 ngx_uint_t type; | 65 ngx_uint_t type; |
66 ngx_uint_t force; | |
64 } ngx_http_image_filter_ctx_t; | 67 } ngx_http_image_filter_ctx_t; |
65 | 68 |
66 | 69 |
67 static ngx_int_t ngx_http_image_send(ngx_http_request_t *r, | 70 static ngx_int_t ngx_http_image_send(ngx_http_request_t *r, |
68 ngx_http_image_filter_ctx_t *ctx, ngx_chain_t *in); | 71 ngx_http_image_filter_ctx_t *ctx, ngx_chain_t *in); |
111 { ngx_string("image_filter_jpeg_quality"), | 114 { ngx_string("image_filter_jpeg_quality"), |
112 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | 115 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
113 ngx_conf_set_num_slot, | 116 ngx_conf_set_num_slot, |
114 NGX_HTTP_LOC_CONF_OFFSET, | 117 NGX_HTTP_LOC_CONF_OFFSET, |
115 offsetof(ngx_http_image_filter_conf_t, jpeg_quality), | 118 offsetof(ngx_http_image_filter_conf_t, jpeg_quality), |
119 NULL }, | |
120 | |
121 { ngx_string("image_filter_transparency"), | |
122 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
123 ngx_conf_set_flag_slot, | |
124 NGX_HTTP_LOC_CONF_OFFSET, | |
125 offsetof(ngx_http_image_filter_conf_t, transparency), | |
116 NULL }, | 126 NULL }, |
117 | 127 |
118 { ngx_string("image_filter_buffer"), | 128 { ngx_string("image_filter_buffer"), |
119 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | 129 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
120 ngx_conf_set_size_slot, | 130 ngx_conf_set_size_slot, |
490 return NULL; | 500 return NULL; |
491 } | 501 } |
492 | 502 |
493 if (rc == NGX_OK | 503 if (rc == NGX_OK |
494 && ctx->width <= ctx->max_width | 504 && ctx->width <= ctx->max_width |
495 && ctx->height <= ctx->max_height) | 505 && ctx->height <= ctx->max_height |
506 && !ctx->force) | |
496 { | 507 { |
497 return ngx_http_image_asis(r, ctx); | 508 return ngx_http_image_asis(r, ctx); |
498 } | 509 } |
499 | 510 |
500 return ngx_http_image_resize(r, ctx); | 511 return ngx_http_image_resize(r, ctx); |
590 | 601 |
591 static ngx_int_t | 602 static ngx_int_t |
592 ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) | 603 ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) |
593 { | 604 { |
594 u_char *p, *last; | 605 u_char *p, *last; |
606 size_t len, app; | |
595 ngx_uint_t width, height; | 607 ngx_uint_t width, height; |
596 | 608 |
597 p = ctx->image; | 609 p = ctx->image; |
598 | 610 |
599 switch (ctx->type) { | 611 switch (ctx->type) { |
600 | 612 |
601 case NGX_HTTP_IMAGE_JPEG: | 613 case NGX_HTTP_IMAGE_JPEG: |
602 | 614 |
603 p += 2; | 615 p += 2; |
604 last = ctx->image + ctx->length - 10; | 616 last = ctx->image + ctx->length - 10; |
617 width = 0; | |
618 height = 0; | |
619 app = 0; | |
605 | 620 |
606 while (p < last) { | 621 while (p < last) { |
607 | 622 |
608 if (p[0] == 0xff && p[1] != 0xff) { | 623 if (p[0] == 0xff && p[1] != 0xff) { |
609 | 624 |
610 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 625 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
611 "JPEG: %02xd %02xd", *p, *(p + 1)); | 626 "JPEG: %02xd %02xd", p[0], p[1]); |
612 | 627 |
613 p++; | 628 p++; |
614 | 629 |
615 if (*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3 | 630 if ((*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3 |
616 || *p == 0xc9 || *p == 0xca || *p == 0xcb) | 631 || *p == 0xc9 || *p == 0xca || *p == 0xcb) |
632 && (width == 0 || height == 0)) | |
617 { | 633 { |
618 goto found; | 634 width = p[6] * 256 + p[7]; |
635 height = p[4] * 256 + p[5]; | |
619 } | 636 } |
620 | 637 |
621 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 638 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
622 "JPEG: %02xd %02xd", p[1], p[2]); | 639 "JPEG: %02xd %02xd", p[1], p[2]); |
623 | 640 |
624 p += p[1] * 256 + p[2]; | 641 len = p[1] * 256 + p[2]; |
642 | |
643 if (*p >= 0xe1 && *p <= 0xef) { | |
644 /* application data, e.g., EXIF, Adobe XMP, etc. */ | |
645 app += len; | |
646 } | |
647 | |
648 p += len; | |
625 | 649 |
626 continue; | 650 continue; |
627 } | 651 } |
628 | 652 |
629 p++; | 653 p++; |
630 } | 654 } |
631 | 655 |
632 return NGX_DECLINED; | 656 if (width == 0 || height == 0) { |
633 | 657 return NGX_DECLINED; |
634 found: | 658 } |
635 | 659 |
636 width = p[6] * 256 + p[7]; | 660 if (ctx->length / 20 < app) { |
637 height = p[4] * 256 + p[5]; | 661 /* force conversion if application data consume more than 5% */ |
662 ctx->force = 1; | |
663 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
664 "app data size: %uz", app); | |
665 } | |
638 | 666 |
639 break; | 667 break; |
640 | 668 |
641 case NGX_HTTP_IMAGE_GIF: | 669 case NGX_HTTP_IMAGE_GIF: |
642 | 670 |
676 | 704 |
677 | 705 |
678 static ngx_buf_t * | 706 static ngx_buf_t * |
679 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) | 707 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) |
680 { | 708 { |
681 int sx, sy, dx, dy, ox, oy, | 709 int sx, sy, dx, dy, ox, oy, size, |
682 colors, transparent, red, green, blue, size; | 710 colors, palette, transparent, |
711 red, green, blue; | |
683 u_char *out; | 712 u_char *out; |
684 ngx_buf_t *b; | 713 ngx_buf_t *b; |
685 ngx_uint_t resize; | 714 ngx_uint_t resize; |
686 gdImagePtr src, dst; | 715 gdImagePtr src, dst; |
687 ngx_pool_cleanup_t *cln; | 716 ngx_pool_cleanup_t *cln; |
696 sx = gdImageSX(src); | 725 sx = gdImageSX(src); |
697 sy = gdImageSY(src); | 726 sy = gdImageSY(src); |
698 | 727 |
699 conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); | 728 conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); |
700 | 729 |
701 if ((ngx_uint_t) sx <= ctx->max_width | 730 if (!ctx->force |
731 && (ngx_uint_t) sx <= ctx->max_width | |
702 && (ngx_uint_t) sy <= ctx->max_height) | 732 && (ngx_uint_t) sy <= ctx->max_height) |
703 { | 733 { |
704 gdImageDestroy(src); | 734 gdImageDestroy(src); |
705 return ngx_http_image_asis(r, ctx); | 735 return ngx_http_image_asis(r, ctx); |
706 } | 736 } |
707 | 737 |
708 colors = gdImageColorsTotal(src); | 738 colors = gdImageColorsTotal(src); |
709 transparent = gdImageGetTransparent(src); | 739 |
710 | 740 if (colors && conf->transparency) { |
711 if (transparent != -1 && colors) { | 741 transparent = gdImageGetTransparent(src); |
712 red = gdImageRed(src, transparent); | 742 |
713 green = gdImageGreen(src, transparent); | 743 if (transparent != -1) { |
714 blue = gdImageBlue(src, transparent); | 744 palette = colors; |
715 gdImageColorTransparent(src, -1); | 745 red = gdImageRed(src, transparent); |
716 | 746 green = gdImageGreen(src, transparent); |
717 } else { | 747 blue = gdImageBlue(src, transparent); |
718 red = 0; green = 0; blue = 0; | 748 |
719 } | 749 goto transparent; |
750 } | |
751 } | |
752 | |
753 palette = 0; | |
754 transparent = -1; | |
755 red = 0; | |
756 green = 0; | |
757 blue = 0; | |
758 | |
759 transparent: | |
760 | |
761 gdImageColorTransparent(src, -1); | |
720 | 762 |
721 dx = sx; | 763 dx = sx; |
722 dy = sy; | 764 dy = sy; |
723 | 765 |
724 if (conf->filter == NGX_HTTP_IMAGE_RESIZE) { | 766 if (conf->filter == NGX_HTTP_IMAGE_RESIZE) { |
760 } | 802 } |
761 } | 803 } |
762 } | 804 } |
763 | 805 |
764 if (resize) { | 806 if (resize) { |
765 dst = ngx_http_image_new(r, dx, dy, colors); | 807 dst = ngx_http_image_new(r, dx, dy, palette); |
766 if (dst == NULL) { | 808 if (dst == NULL) { |
767 gdImageDestroy(src); | 809 gdImageDestroy(src); |
768 return NULL; | 810 return NULL; |
769 } | 811 } |
770 | 812 |
813 if (colors == 0) { | |
814 gdImageSaveAlpha(dst, 1); | |
815 gdImageAlphaBlending(dst, 0); | |
816 } | |
817 | |
771 gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy); | 818 gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy); |
819 | |
820 if (colors) { | |
821 gdImageTrueColorToPalette(dst, 1, 256); | |
822 } | |
772 | 823 |
773 gdImageDestroy(src); | 824 gdImageDestroy(src); |
774 | 825 |
775 } else { | 826 } else { |
776 dst = src; | 827 dst = src; |
808 | 859 |
809 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 860 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
810 "image crop: %d x %d @ %d x %d", | 861 "image crop: %d x %d @ %d x %d", |
811 dx, dy, ox, oy); | 862 dx, dy, ox, oy); |
812 | 863 |
864 if (colors == 0) { | |
865 gdImageSaveAlpha(dst, 1); | |
866 gdImageAlphaBlending(dst, 0); | |
867 } | |
868 | |
813 gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy); | 869 gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy); |
870 | |
871 if (colors) { | |
872 gdImageTrueColorToPalette(dst, 1, 256); | |
873 } | |
814 | 874 |
815 gdImageDestroy(src); | 875 gdImageDestroy(src); |
816 } | 876 } |
817 } | 877 } |
818 | 878 |
1019 return NULL; | 1079 return NULL; |
1020 } | 1080 } |
1021 | 1081 |
1022 conf->filter = NGX_CONF_UNSET_UINT; | 1082 conf->filter = NGX_CONF_UNSET_UINT; |
1023 conf->jpeg_quality = NGX_CONF_UNSET; | 1083 conf->jpeg_quality = NGX_CONF_UNSET; |
1084 conf->transparency = NGX_CONF_UNSET; | |
1024 conf->buffer_size = NGX_CONF_UNSET_SIZE; | 1085 conf->buffer_size = NGX_CONF_UNSET_SIZE; |
1025 | 1086 |
1026 return conf; | 1087 return conf; |
1027 } | 1088 } |
1028 | 1089 |
1048 } | 1109 } |
1049 | 1110 |
1050 /* 75 is libjpeg default quality */ | 1111 /* 75 is libjpeg default quality */ |
1051 ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75); | 1112 ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75); |
1052 | 1113 |
1114 ngx_conf_merge_value(conf->transparency, prev->transparency, 1); | |
1115 | |
1053 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, | 1116 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, |
1054 1 * 1024 * 1024); | 1117 1 * 1024 * 1024); |
1055 | 1118 |
1056 return NGX_CONF_OK; | 1119 return NGX_CONF_OK; |
1057 } | 1120 } |