gographics / imagick

Go binding to ImageMagick's MagickWand C API
https://godoc.org/github.com/gographics/imagick/imagick
Other
1.77k stars 184 forks source link

Converting JPEG to WEBP increases the size of the photo #294

Closed 4Marvin2 closed 1 year ago

4Marvin2 commented 1 year ago

Hi, I am trying to use imagick to convert photos and it works great. But when I try to convert big photos larger than 10MB, the size of the resulting photo is larger than the original photo.

My code:

imagick.Initialize()
defer imagick.Terminate()

mw := imagick.NewMagickWand()
defer mw.Destroy()

err := mw.ReadImage("e.jpeg")
fmt.Println(err)

err = mw.WriteImage("e.webp")
fmt.Println(err)

Also I try this:

imagick.Initialize()
defer imagick.Terminate()

mw := imagick.NewMagickWand()
defer mw.Destroy()

err := mw.ReadImage("e.jpeg")
fmt.Println(err)

err = mw.SetImageFormat("webp")
fmt.Println(err)

b := mw.GetImageBlob()

f, err := os.Create("e.webp")
if err != nil {
    log.Fatal(err)
}

_, err = f.Write(b)
if err != nil {
    log.Fatal(err)
}

I use gopkg.in/gographics/imagick.v3/imagick on MacOS Ventura 13.3.1 and gopkg.in/gographics/imagick.v2/imagick on Ubuntu 22.04.2 LTS.

Images that are larger after conversion: https://www.freepik.com/free-photo/galaxy-nature-aesthetic-background-starry-sky-mountain-remixed-media_17226410.htm#query=4k&position=0&from_view=keyword&track=sph

https://www.freepik.com/free-photo/grassy-hills-with-flowers-mountains_9655791.htm#page=4&query=4k&position=4&from_view=keyword&track=sph

Please explain to me, maybe I'm doing something wrong? With image, for example, 5MB size, everything works well.

justinfx commented 1 year ago

You cannot assume that the default settings for an output will always be the best option. The act of converting from jpeg to webp will not guarantee a smaller file unless you select a lossy option for the output file. Consider the following ImageMagick convert command, using your first example image:

$ convert input.jpg output.webp
$ du -h input.jpg output.webp
 17M    input.jpg
 25M    output.webp

With no options provided, the webp ends up larger than the input jpeg.

But if we tell the output to use compression of 50%:

$ convert input.jpg -quality 50 output.webp
$ du -h input.jpg output.webp
 17M    input.jpg
5.2M    output.webp

Stick with your first approach if using Read/Write unless you really need to read the entire blob into memory first, and use SetCompressionQuality

Please also refer here for webp options availabe using SetOption: https://imagemagick.org/script/webp.php

4Marvin2 commented 1 year ago

SetImageCompressionQuality seems to be what I need. Now everything works correctly. Thank you!

Do I understand correctly that to convert to webp I need to use SetImageCompressionQuality, and to convert to other formats I need to use SetCompressionQuality?

justinfx commented 1 year ago

Are you saying that using SetCompressionQuality did not work in this case?

If you search the history of the issues on this project you will find similar questions. The SetImage* methods are for applying settings to individual images in the wand. Usually you want the Set* methods to control the output settings.

4Marvin2 commented 1 year ago

Yes, I tried to do like this:

err := mw.ReadImage("c.jpeg")
fmt.Println(err)

err = mw.SetCompressionQuality(50)
fmt.Println(err)

err = mw.WriteImage("c.webp")
fmt.Println(err)

And got the result as before.

If I use SetImageCompressionQuality:

err := mw.ReadImage("c.jpeg")
fmt.Println(err)

err = mw.SetImageCompressionQuality(50)
fmt.Println(err)

err = mw.WriteImage("c.webp")
fmt.Println(err)

result is correct.

I found this issue https://github.com/gographics/imagick/issues/204 and if I understood correctly, then SetCompressionQuality does not work for webp.

But maybe I'm doing something wrong?

justinfx commented 1 year ago

Cool. I guess that is specific to the webp delegate implementation. If it works, go with it.