1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-02-02 11:34:20 +02:00

Add option to keep metadata/tags in output image (#329)

* add env var to disable stripping metadata

by default, all metadata will be stripped (as before)

* always strip orientation tags when rotating the image

in case IMGPROXY_STRIP_METADATA is false

* document IMGPROXY_STRIP_METADATA env var

* remove ICC profile after importing it

needed, in case metadata aren't stripped from the output image
This commit is contained in:
sauerbraten 2020-01-30 16:43:08 +01:00 committed by GitHub
parent aa8cff62f4
commit 89f8a4e11c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 43 deletions

View File

@ -166,6 +166,7 @@ type config struct {
PngQuantizationColors int PngQuantizationColors int
Quality int Quality int
GZipCompression int GZipCompression int
StripMetadata bool
EnableWebpDetection bool EnableWebpDetection bool
EnforceWebp bool EnforceWebp bool
@ -242,6 +243,7 @@ var conf = config{
SignatureSize: 32, SignatureSize: 32,
PngQuantizationColors: 256, PngQuantizationColors: 256,
Quality: 80, Quality: 80,
StripMetadata: true,
UserAgent: fmt.Sprintf("imgproxy/%s", version), UserAgent: fmt.Sprintf("imgproxy/%s", version),
Presets: make(presets), Presets: make(presets),
WatermarkOpacity: 1, WatermarkOpacity: 1,
@ -300,6 +302,7 @@ func configure() {
intEnvConfig(&conf.PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS") intEnvConfig(&conf.PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS")
intEnvConfig(&conf.Quality, "IMGPROXY_QUALITY") intEnvConfig(&conf.Quality, "IMGPROXY_QUALITY")
intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION") intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION")
boolEnvConfig(&conf.StripMetadata, "IMGPROXY_STRIP_METADATA")
boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION") boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP") boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP")

View File

@ -253,3 +253,4 @@ imgproxy can send logs to syslog, but this feature is disabled by default. To en
* `IMGPROXY_USE_LINEAR_COLORSPACE`: when `true`, imgproxy will process images in linear colorspace. This will slow down processing. Note that images won't be fully processed in linear colorspace while shrink-on-load is enabled (see below). * `IMGPROXY_USE_LINEAR_COLORSPACE`: when `true`, imgproxy will process images in linear colorspace. This will slow down processing. Note that images won't be fully processed in linear colorspace while shrink-on-load is enabled (see below).
* `IMGPROXY_DISABLE_SHRINK_ON_LOAD`: when `true`, disables shrink-on-load for JPEG and WebP. Allows to process the whole image in linear colorspace but dramatically slows down resizing and increases memory usage when working with large images. * `IMGPROXY_DISABLE_SHRINK_ON_LOAD`: when `true`, disables shrink-on-load for JPEG and WebP. Allows to process the whole image in linear colorspace but dramatically slows down resizing and increases memory usage when working with large images.
* `IMGPROXY_APPLY_UNSHARPEN_MASKING`: <img class="pro-badge" src="assets/pro.svg" alt="pro" /> when `true`, imgproxy will apply unsharpen masking to the resulting image if one is smaller than the source. Default: `true`. * `IMGPROXY_APPLY_UNSHARPEN_MASKING`: <img class="pro-badge" src="assets/pro.svg" alt="pro" /> when `true`, imgproxy will apply unsharpen masking to the resulting image if one is smaller than the source. Default: `true`.
* `IMGPROXY_STRIP_METADATA`: whether to strip all metadata (EXIF, IPTC, etc.) from JPEG and WebP output images. Default: `true`.

View File

@ -609,7 +609,7 @@ func saveImageToFitBytes(po *processingOptions, img *vipsImage) ([]byte, context
img.CopyMemory() img.CopyMemory()
for { for {
result, cancel, err := img.Save(po.Format, quality) result, cancel, err := img.Save(po.Format, quality, po.StripMetadata)
if len(result) <= po.MaxBytes || quality <= 10 || err != nil { if len(result) <= po.MaxBytes || quality <= 10 || err != nil {
return result, cancel, err return result, cancel, err
} }
@ -737,5 +737,5 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
return saveImageToFitBytes(po, img) return saveImageToFitBytes(po, img)
} }
return img.Save(po.Format, po.Quality) return img.Save(po.Format, po.Quality, po.StripMetadata)
} }

View File

@ -114,22 +114,23 @@ type watermarkOptions struct {
} }
type processingOptions struct { type processingOptions struct {
ResizingType resizeType ResizingType resizeType
Width int Width int
Height int Height int
Dpr float64 Dpr float64
Gravity gravityOptions Gravity gravityOptions
Enlarge bool Enlarge bool
Extend extendOptions Extend extendOptions
Crop cropOptions Crop cropOptions
Trim trimOptions Trim trimOptions
Format imageType Format imageType
Quality int Quality int
MaxBytes int StripMetadata bool
Flatten bool MaxBytes int
Background rgbColor Flatten bool
Blur float32 Background rgbColor
Sharpen float32 Blur float32
Sharpen float32
CacheBuster string CacheBuster string
@ -198,21 +199,22 @@ var (
func newProcessingOptions() *processingOptions { func newProcessingOptions() *processingOptions {
newProcessingOptionsOnce.Do(func() { newProcessingOptionsOnce.Do(func() {
_newProcessingOptions = processingOptions{ _newProcessingOptions = processingOptions{
ResizingType: resizeFit, ResizingType: resizeFit,
Width: 0, Width: 0,
Height: 0, Height: 0,
Gravity: gravityOptions{Type: gravityCenter}, Gravity: gravityOptions{Type: gravityCenter},
Enlarge: false, Enlarge: false,
Extend: extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}}, Extend: extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}},
Trim: trimOptions{Enabled: false, Threshold: 10}, Trim: trimOptions{Enabled: false, Threshold: 10},
Quality: conf.Quality, Quality: conf.Quality,
MaxBytes: 0, StripMetadata: conf.StripMetadata,
Format: imageTypeUnknown, MaxBytes: 0,
Background: rgbColor{255, 255, 255}, Format: imageTypeUnknown,
Blur: 0, Background: rgbColor{255, 255, 255},
Sharpen: 0, Blur: 0,
Dpr: 1, Sharpen: 0,
Watermark: watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityOptions{Type: gravityCenter}}, Dpr: 1,
Watermark: watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityOptions{Type: gravityCenter}},
} }
}) })

15
vips.c
View File

@ -338,7 +338,12 @@ vips_support_builtin_icc() {
int int
vips_icc_import_go(VipsImage *in, VipsImage **out, char *profile) { vips_icc_import_go(VipsImage *in, VipsImage **out, char *profile) {
return vips_icc_import(in, out, "input_profile", profile, "embedded", TRUE, "pcs", VIPS_PCS_XYZ, NULL); if (vips_icc_import(in, out, "input_profile", profile, "embedded", TRUE, "pcs", VIPS_PCS_XYZ, NULL))
return 1;
vips_image_remove(*out, VIPS_META_ICC_NAME);
return 0;
} }
int int
@ -512,8 +517,8 @@ vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n) {
} }
int int
vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace) { vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace, gboolean strip) {
return vips_jpegsave_buffer(in, buf, len, "profile", "none", "Q", quality, "strip", TRUE, "optimize_coding", TRUE, "interlace", interlace, NULL); return vips_jpegsave_buffer(in, buf, len, "profile", "none", "Q", quality, "strip", strip, "optimize_coding", TRUE, "interlace", interlace, NULL);
} }
int int
@ -531,8 +536,8 @@ vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quant
} }
int int
vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality) { vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, gboolean strip) {
return vips_webpsave_buffer(in, buf, len, "Q", quality, "strip", TRUE, NULL); return vips_webpsave_buffer(in, buf, len, "Q", quality, "strip", strip, NULL);
} }
int int

15
vips.go
View File

@ -130,6 +130,13 @@ func vipsLoadWatermark() (err error) {
return return
} }
func gbool(b bool) C.gboolean {
if b {
return C.gboolean(1)
}
return C.gboolean(0)
}
func (img *vipsImage) Width() int { func (img *vipsImage) Width() int {
return int(img.VipsImage.Xsize) return int(img.VipsImage.Xsize)
} }
@ -170,7 +177,7 @@ func (img *vipsImage) Load(data []byte, imgtype imageType, shrink int, scale flo
return nil return nil
} }
func (img *vipsImage) Save(imgtype imageType, quality int) ([]byte, context.CancelFunc, error) { func (img *vipsImage) Save(imgtype imageType, quality int, stripMeta bool) ([]byte, context.CancelFunc, error) {
var ptr unsafe.Pointer var ptr unsafe.Pointer
cancel := func() { cancel := func() {
@ -183,11 +190,11 @@ func (img *vipsImage) Save(imgtype imageType, quality int) ([]byte, context.Canc
switch imgtype { switch imgtype {
case imageTypeJPEG: case imageTypeJPEG:
err = C.vips_jpegsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.JpegProgressive) err = C.vips_jpegsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.JpegProgressive, gbool(stripMeta))
case imageTypePNG: case imageTypePNG:
err = C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, vipsConf.PngInterlaced, vipsConf.PngQuantize, vipsConf.PngQuantizationColors) err = C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, vipsConf.PngInterlaced, vipsConf.PngQuantize, vipsConf.PngQuantizationColors)
case imageTypeWEBP: case imageTypeWEBP:
err = C.vips_webpsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality)) err = C.vips_webpsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), gbool(stripMeta))
case imageTypeGIF: case imageTypeGIF:
err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize) err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
case imageTypeICO: case imageTypeICO:
@ -312,6 +319,8 @@ func (img *vipsImage) Rotate(angle int) error {
return vipsError() return vipsError()
} }
C.vips_autorot_remove_angle(tmp)
C.swap_and_clear(&img.VipsImage, tmp) C.swap_and_clear(&img.VipsImage, tmp)
return nil return nil
} }

4
vips.h
View File

@ -82,9 +82,9 @@ int vips_apply_watermark(VipsImage *in, VipsImage *watermark, VipsImage **out, d
int vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n); 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_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int interlace, gboolean strip);
int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors); 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_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, gboolean strip);
int vips_gifsave_go(VipsImage *in, void **buf, size_t *len); int vips_gifsave_go(VipsImage *in, void **buf, size_t *len);
int vips_icosave_go(VipsImage *in, void **buf, size_t *len); int vips_icosave_go(VipsImage *in, void **buf, size_t *len);
int vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality); int vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality);