diff --git a/Dockerfile b/Dockerfile index 3ea44889..2f10ce4e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ WORKDIR /go/src/github.com/DarthSim/imgproxy RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \ && apk --no-cache upgrade \ && apk add --no-cache curl ca-certificates go gcc g++ make musl-dev fftw-dev glib-dev expat-dev \ - libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev librsvg-dev libexif-dev lcms2-dev + libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev librsvg-dev libexif-dev lcms2-dev libimagequant-dev # Build ImageMagick RUN cd /root \ @@ -76,7 +76,7 @@ LABEL maintainer="Sergey Alexandrovich " RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \ && apk --no-cache upgrade \ && apk add --no-cache bash ca-certificates fftw glib expat libjpeg-turbo libpng \ - libwebp giflib librsvg libgsf libexif lcms2 \ + libwebp giflib librsvg libgsf libexif lcms2 libimagequant\ && rm -rf /var/cache/apk* COPY --from=0 /usr/local/bin/imgproxy /usr/local/bin/ diff --git a/config.go b/config.go index 41f416e0..1c3bdeb1 100644 --- a/config.go +++ b/config.go @@ -143,10 +143,12 @@ type config struct { MaxSrcFileSize int MaxGifFrames int - JpegProgressive bool - PngInterlaced bool - Quality int - GZipCompression int + JpegProgressive bool + PngInterlaced bool + PngQuantize bool + PngQuantizationColors int + Quality int + GZipCompression int EnableWebpDetection bool EnforceWebp bool @@ -215,6 +217,7 @@ var conf = config{ MaxGifFrames: 1, AllowInsecure: false, SignatureSize: 32, + PngQuantizationColors: 256, Quality: 80, GZipCompression: 5, UserAgent: fmt.Sprintf("imgproxy/%s", version), @@ -263,6 +266,8 @@ func init() { boolEnvConfig(&conf.JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE") boolEnvConfig(&conf.PngInterlaced, "IMGPROXY_PNG_INTERLACED") + boolEnvConfig(&conf.PngQuantize, "IMGPROXY_PNG_QUANTIZE") + intEnvConfig(&conf.PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS") intEnvConfig(&conf.Quality, "IMGPROXY_QUALITY") intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION") @@ -388,6 +393,12 @@ func init() { logFatal("Max GIF frames should be greater than 0, now - %d\n", conf.MaxGifFrames) } + if conf.PngQuantizationColors < 2 { + logFatal("Png quantization colors should be greater than 1, now - %d\n", conf.PngQuantizationColors) + } else if conf.PngQuantizationColors > 256 { + logFatal("Png quantization colors can't be greater than 256, now - %d\n", conf.PngQuantizationColors) + } + if conf.Quality <= 0 { logFatal("Quality should be greater than 0, now - %d\n", conf.Quality) } else if conf.Quality > 100 { diff --git a/docs/configuration.md b/docs/configuration.md index 3c593199..10f2545f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -67,6 +67,8 @@ When you use imgproxy in a development environment, it can be useful to ignore S * `IMGPROXY_GZIP_COMPRESSION`: GZip compression level. Default: `5`; * `IMGPROXY_JPEG_PROGRESSIVE` : when true, enables progressive JPEG compression. Default: false; * `IMGPROXY_PNG_INTERLACED`: when true, enables interlaced PNG compression. Default: false; +* `IMGPROXY_PNG_QUANTIZE`: when true, enables PNG quantization. libvips should be built with libimagequant support. Default: false; +* `IMGPROXY_PNG_QUANTIZATION_COLORS`: maximum number of quantization palette entries. Should be between 2 and 256. Default: 256; ## WebP support detection diff --git a/process.go b/process.go index f3334727..536e578b 100644 --- a/process.go +++ b/process.go @@ -31,9 +31,11 @@ var ( ) type cConfig struct { - JpegProgressive C.int - PngInterlaced C.int - WatermarkOpacity C.double + JpegProgressive C.int + PngInterlaced C.int + PngQuantize C.int + PngQuantizationColors C.int + WatermarkOpacity C.double } var cConf cConfig @@ -109,6 +111,12 @@ func initVips() { cConf.PngInterlaced = C.int(1) } + if conf.PngQuantize { + cConf.PngQuantize = C.int(1) + } + + cConf.PngQuantizationColors = C.int(conf.PngQuantizationColors) + cConf.WatermarkOpacity = C.double(conf.WatermarkOpacity) if err := vipsPrepareWatermark(); err != nil { @@ -667,7 +675,7 @@ func vipsSaveImage(img *C.VipsImage, imgtype imageType, quality int) ([]byte, co case imageTypeJPEG: err = C.vips_jpegsave_go(img, &ptr, &imgsize, C.int(quality), cConf.JpegProgressive) case imageTypePNG: - err = C.vips_pngsave_go(img, &ptr, &imgsize, cConf.PngInterlaced) + err = C.vips_pngsave_go(img, &ptr, &imgsize, cConf.PngInterlaced, cConf.PngQuantize, cConf.PngQuantizationColors) case imageTypeWEBP: err = C.vips_webpsave_go(img, &ptr, &imgsize, C.int(quality)) case imageTypeGIF: diff --git a/vips.c b/vips.c index 85d1a01d..a976e540 100644 --- a/vips.c +++ b/vips.c @@ -15,6 +15,9 @@ #define VIPS_SUPPORT_MAGICK \ (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 7)) +#define VIPS_SUPPORT_PNG_QUANTIZATION \ + (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 7)) + #define EXIF_ORIENTATION "exif-ifd0-Orientation" int @@ -456,8 +459,17 @@ vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interl } int -vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace) { - return vips_pngsave_buffer(in, buf, len, "profile", "none", "filter", VIPS_FOREIGN_PNG_FILTER_NONE, "interlace", interlace, NULL); +vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors) { + return vips_pngsave_buffer( + in, buf, len, + "profile", "none", + "filter", VIPS_FOREIGN_PNG_FILTER_NONE, + "interlace", interlace, +#if VIPS_SUPPORT_PNG_QUANTIZATION + "palette", quantize, + "colours", colors, +#endif // VIPS_SUPPORT_PNG_QUANTIZATION + NULL); } int diff --git a/vips.h b/vips.h index a4c6d3c5..4bba488c 100644 --- a/vips.h +++ b/vips.h @@ -73,7 +73,7 @@ int vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, d int vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n); int vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace); -int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace); +int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors); int vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality); int vips_gifsave_go(VipsImage *in, void **buf, size_t *len); int vips_icosave_go(VipsImage *in, void **buf, size_t *len);