Explorar el Código

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
sauerbraten hace 5 años
padre
commit
89f8a4e11c
Se han modificado 7 ficheros con 63 adiciones y 43 borrados
  1. 3 0
      config.go
  2. 1 0
      docs/configuration.md
  3. 2 2
      process.go
  4. 33 31
      processing_options.go
  5. 10 5
      vips.c
  6. 12 3
      vips.go
  7. 2 2
      vips.h

+ 3 - 0
config.go

@@ -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")

+ 1 - 0
docs/configuration.md

@@ -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`.

+ 2 - 2
process.go

@@ -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)
 }
 }

+ 33 - 31
processing_options.go

@@ -114,22 +114,23 @@ type watermarkOptions struct {
 }
 }
 
 
 type processingOptions struct {
 type processingOptions struct {
-	ResizingType resizeType
-	Width        int
-	Height       int
-	Dpr          float64
-	Gravity      gravityOptions
-	Enlarge      bool
-	Extend       extendOptions
-	Crop         cropOptions
-	Trim         trimOptions
-	Format       imageType
-	Quality      int
-	MaxBytes     int
-	Flatten      bool
-	Background   rgbColor
-	Blur         float32
-	Sharpen      float32
+	ResizingType  resizeType
+	Width         int
+	Height        int
+	Dpr           float64
+	Gravity       gravityOptions
+	Enlarge       bool
+	Extend        extendOptions
+	Crop          cropOptions
+	Trim          trimOptions
+	Format        imageType
+	Quality       int
+	StripMetadata bool
+	MaxBytes      int
+	Flatten       bool
+	Background    rgbColor
+	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,
-			Width:        0,
-			Height:       0,
-			Gravity:      gravityOptions{Type: gravityCenter},
-			Enlarge:      false,
-			Extend:       extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}},
-			Trim:         trimOptions{Enabled: false, Threshold: 10},
-			Quality:      conf.Quality,
-			MaxBytes:     0,
-			Format:       imageTypeUnknown,
-			Background:   rgbColor{255, 255, 255},
-			Blur:         0,
-			Sharpen:      0,
-			Dpr:          1,
-			Watermark:    watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityOptions{Type: gravityCenter}},
+			ResizingType:  resizeFit,
+			Width:         0,
+			Height:        0,
+			Gravity:       gravityOptions{Type: gravityCenter},
+			Enlarge:       false,
+			Extend:        extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}},
+			Trim:          trimOptions{Enabled: false, Threshold: 10},
+			Quality:       conf.Quality,
+			StripMetadata: conf.StripMetadata,
+			MaxBytes:      0,
+			Format:        imageTypeUnknown,
+			Background:    rgbColor{255, 255, 255},
+			Blur:          0,
+			Sharpen:       0,
+			Dpr:           1,
+			Watermark:     watermarkOptions{Opacity: 1, Replicate: false, Gravity: gravityOptions{Type: gravityCenter}},
 		}
 		}
 	})
 	})
 
 

+ 10 - 5
vips.c

@@ -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) {
-  return vips_jpegsave_buffer(in, buf, len, "profile", "none", "Q", quality, "strip", TRUE, "optimize_coding", TRUE, "interlace", interlace, NULL);
+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", 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) {
-  return vips_webpsave_buffer(in, buf, len, "Q", quality, "strip", TRUE, NULL);
+vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, gboolean strip) {
+  return vips_webpsave_buffer(in, buf, len, "Q", quality, "strip", strip, NULL);
 }
 }
 
 
 int
 int

+ 12 - 3
vips.go

@@ -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
 }
 }

+ 2 - 2
vips.h

@@ -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);