Skip to content

Commit

Permalink
Add option to keep metadata/tags in output image (#329)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
sauerbraten committed Jan 30, 2020
1 parent aa8cff6 commit 89f8a4e
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 43 deletions.
3 changes: 3 additions & 0 deletions config.go
Expand Up @@ -166,6 +166,7 @@ type config struct {
PngQuantizationColors int
Quality int
GZipCompression int
StripMetadata bool

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

boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
Expand Down
1 change: 1 addition & 0 deletions docs/configuration.md
Expand Up @@ -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_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_STRIP_METADATA`: whether to strip all metadata (EXIF, IPTC, etc.) from JPEG and WebP output images. Default: `true`.
4 changes: 2 additions & 2 deletions process.go
Expand Up @@ -609,7 +609,7 @@ func saveImageToFitBytes(po *processingOptions, img *vipsImage) ([]byte, context
img.CopyMemory()

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 {
return result, cancel, err
}
Expand Down Expand Up @@ -737,5 +737,5 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
return saveImageToFitBytes(po, img)
}

return img.Save(po.Format, po.Quality)
return img.Save(po.Format, po.Quality, po.StripMetadata)
}
64 changes: 33 additions & 31 deletions processing_options.go
Expand Up @@ -114,22 +114,23 @@ type watermarkOptions 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

Expand Down Expand Up @@ -198,21 +199,22 @@ var (
func newProcessingOptions() *processingOptions {
newProcessingOptionsOnce.Do(func() {
_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}},
}
})

Expand Down
15 changes: 10 additions & 5 deletions vips.c
Expand Up @@ -338,7 +338,12 @@ vips_support_builtin_icc() {

int
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
Expand Down Expand Up @@ -512,8 +517,8 @@ vips_arrayjoin_go(VipsImage **in, VipsImage **out, int n) {
}

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
Expand All @@ -531,8 +536,8 @@ vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quant
}

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
Expand Down
15 changes: 12 additions & 3 deletions vips.go
Expand Up @@ -130,6 +130,13 @@ func vipsLoadWatermark() (err error) {
return
}

func gbool(b bool) C.gboolean {
if b {
return C.gboolean(1)
}
return C.gboolean(0)
}

func (img *vipsImage) Width() int {
return int(img.VipsImage.Xsize)
}
Expand Down Expand Up @@ -170,7 +177,7 @@ func (img *vipsImage) Load(data []byte, imgtype imageType, shrink int, scale flo
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

cancel := func() {
Expand All @@ -183,11 +190,11 @@ func (img *vipsImage) Save(imgtype imageType, quality int) ([]byte, context.Canc

switch imgtype {
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:
err = C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, vipsConf.PngInterlaced, vipsConf.PngQuantize, vipsConf.PngQuantizationColors)
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:
err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
case imageTypeICO:
Expand Down Expand Up @@ -312,6 +319,8 @@ func (img *vipsImage) Rotate(angle int) error {
return vipsError()
}

C.vips_autorot_remove_angle(tmp)

C.swap_and_clear(&img.VipsImage, tmp)
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions vips.h
Expand Up @@ -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_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_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_icosave_go(VipsImage *in, void **buf, size_t *len);
int vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality);
Expand Down

0 comments on commit 89f8a4e

Please sign in to comment.