Skip to content

proposal: x/image/webp: support for WebP Encoding #45121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ainsleyclark opened this issue Mar 19, 2021 · 44 comments
Open

proposal: x/image/webp: support for WebP Encoding #45121

ainsleyclark opened this issue Mar 19, 2021 · 44 comments
Labels
Milestone

Comments

@ainsleyclark
Copy link

Hi there,

Currently we are able to decode webp images, which is great. But why can't we encode them?

Given that PSI is such a crucial factor for getting websites to rank, it's important that any server should be able to convert and serve webp images.

I have to jump through hoops at the moment and use the webp executable which is far from ideal.

Please please add an encoder!

Many many thanks.

@ainsleyclark ainsleyclark changed the title Support for WebP Encoding x/image Support for WebP Encoding Mar 19, 2021
@gopherbot gopherbot added this to the Unreleased milestone Mar 19, 2021
@ALTree ALTree added the FeatureRequest Issues asking for a new feature that does not need a proposal. label Mar 19, 2021
@ALTree ALTree changed the title x/image Support for WebP Encoding x/image: support for WebP Encoding Mar 19, 2021
@ALTree ALTree added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Mar 19, 2021
@ALTree
Copy link
Member

ALTree commented Mar 19, 2021

cc @nigeltao

@ianlancetaylor
Copy link
Member

A WebP encoder would be a lot of work. If someone wants to write one, that would be great. But as far as I know nobody is working on that.

@ainsleyclark
Copy link
Author

That's a shame, whilst I understand that it may be a bit of work, it feels like it should be out of the box considering webp and go are both made by you guys!

Adding C bindings when converting to webp using third party packages can be messy, as well as using the executables.

I would love to offer a hand to contribute to the /x/image library but wouldn't know where to start.

@nigeltao
Copy link
Contributor

I understand that it may be a bit of work

It's not a bit of work. As Ian said, it's a lot of work. :-)

@DemiMarie
Copy link
Contributor

That's a shame, whilst I understand that it may be a bit of work, it feels like it should be out of the box considering webp and go are both made by you guys!

Adding C bindings when converting to webp using third party packages can be messy, as well as using the executables.

The good news is that image encoding is much less of a security minefield than image decoding is, simply because the input format (a bitmap) is far, far simpler.

That said, have you considered ImageFlow? It’s free software (AGPL) available as both a daemon and a library. Commercial licenses are also available.

@ainsleyclark

This comment was marked as duplicate.

@ivanjaros

This comment was marked as duplicate.

@FlavioCFOliveira

This comment was marked as spam.

@ivanjaros

This comment was marked as duplicate.

@NinoFoxx
Copy link

NinoFoxx commented Sep 23, 2022

Starting a new website project with a Go backend and was planning on using WebP for image thumbnails and it's really sad to see that there's no native encoder.. :(

I would really like to avoid using C bindings (due to performance and memory safety concerns), but it seems that's the only option at the moment, except for executing the official webp binary, which is also not the best idea, since you'd have to either write the file to disk or come up with a complicated virtual FS just for it.

I also considered using Rust, but that's way too advanced for me.

Edit: I found https://github.com/nickalie/go-webpbin which seems quite decent. haven't tested it yet though.

@ainsleyclark

This comment was marked as duplicate.

@ivanjaros

This comment was marked as duplicate.

@ex-tag

This comment was marked as duplicate.

@ex-tag

This comment was marked as duplicate.

@ex-tag

This comment was marked as off-topic.

@ainsleyclark
Copy link
Author

@ex-tag considering the shift with Intel and Nvidia recently and major providers using AV1 and particularly AVIF for websites, future steps for supporting these fantastic encoders would be hugely beneficial for the stdlib. But can appreciate its not a small job.

@seankhliao seankhliao changed the title x/image: support for WebP Encoding x/image/webp: support for WebP Encoding Jan 30, 2023
@wjkoh
Copy link

wjkoh commented Jan 6, 2024

Could go-libwebp by Jack Mordaunt offer a potential solution? I'm aware that rewriting libwebp in Go would be quite time-consuming, but Jack Mordaunt utilized ccgo and was able to port the libwebp C code to native Go code, making it functional, if I understand correctly. I'm not an expert, and I'm unsure of any potential risks this approach may present, but I wanted to share the idea. @JackMordaunt

@dastanaron
Copy link

dastanaron commented Jan 6, 2024

I think there is a better solution. Example may use c-bindings from library on C language.

@JackMordaunt
Copy link

JackMordaunt commented Jan 8, 2024

Could go-libwebp by Jack Mordaunt offer a potential solution? I'm aware that rewriting libwebp in Go would be quite time-consuming, but Jack Mordaunt utilized ccgo and was able to port the libwebp C code to native Go code, making it functional, if I understand correctly. I'm not an expert, and I'm unsure of any potential risks this approach may present, but I wanted to share the idea. @JackMordaunt

Thanks for the reference!

Yes, it's functional. However there's a lot of downside to the transpilation approach which bars it from being anything official.

  • it relies on ccgo for transpilation, an experimental tool under active development
  • it generates Go code semantically identical to the C source, everything is a uintptr and thus totally unsafe
  • no support for vectorized instructions, or any inline assembly. This makes it a decent amount slower (without benchmarks its hard to say how much slower, but it definitely is)

For anyone interested, go-libwebp also allows calling into dynamic libraries if available. However this uses purego to make those calls without requiring cgo. purego is also an experimental tool.

@HrachMD
Copy link

HrachMD commented Jan 4, 2025

Finally! The native solution - https://github.com/HugoSmits86/nativewebp
Thanks @HugoSmits86 for a huge work done!
FYI @ainsleyclark

@ivanjaros
Copy link

Finally! The native solution - https://github.com/HugoSmits86/nativewebp Thanks @HugoSmits86 for a huge work done! FYI @ainsleyclark

It's not a bit of work. As Ian said, it's a lot of work. :-)

looks like few lines of code one could write over the weekend. so it was not about a lot of work but rather just reading the spec, i assume... gj.

@wjkoh
Copy link

wjkoh commented Jan 5, 2025

Awesome! Is there a chance that nativewebp could become x/image/webp? Thanks for the great work, @HugoSmits86!

@HugoSmits86
Copy link

@wjkoh I’m not sure how to go about making that happen. If there’s a process or interest from the Go team, I’d be happy to explore it!

@wjkoh
Copy link

wjkoh commented Jan 5, 2025

@nigeltao @dmitshur @rolandshoemaker could you please advise on how to submit a new feature to x/image/webp?

@ALTree
Copy link
Member

ALTree commented Jan 5, 2025

I don't think it would make sense to integrate this until it also supports the lossy part of the spec (which is what makes webp a viable jpeg replacement, and incidentally is 95% of the complexity of the format. There's a reason libwebp is 50k lines of code).

@HugoSmits86
Copy link

@ALTree Fair point, but WebP is also a container format supporting VP8I, VP8X, and VP8L. Partial support is better than nothing, especially for specific use cases. For instance, one client required WebP output, and while most accept JPEG or PNG, nativewebp let me meet their needs without overhauling my pipeline. Even limited functionality can solve real-world problems.

@HrachMD
Copy link

HrachMD commented Jan 5, 2025

@ALTree Fair point, but WebP is also a container format supporting VP8I, VP8X, and VP8L. Partial support is better than nothing, especially for specific use cases. For instance, one client required WebP output, and while most accept JPEG or PNG, nativewebp let me meet their needs without overhauling my pipeline. Even limited functionality can solve real-world problems.

Exactly. My use-case.

@DemiMarie
Copy link
Contributor

@ALTree Why is lossy support needed? Are lossless files too large?

@agnivade
Copy link
Contributor

agnivade commented Jan 6, 2025

For instance, one client required WebP output, and while most accept JPEG or PNG, nativewebp let me meet their needs without overhauling my pipeline.

I am curious to know more about this. What client is this that requires only webp output, but does not support jpeg/png? How popular is it?

@ALTree
Copy link
Member

ALTree commented Jan 6, 2025

@ALTree Why is lossy support needed? Are lossless files too large?

Take this 3.0MB jpg image of Castello Estense in Ferrara.

Converting it to a webp file in lossy mode with quality=90 using libwebp yields a 1.5MB webp file (a 50% saving over the original file):

$ cwebp castello-estense.jpg -q 90 -o lossy.webp
$ ls -sh lossy.webp 
1.5M lossy.webp

Converting it to a lossless webp (again at quality=90 ) yields a 7.1MB webp image:

$ cwebp castello-estense.jpg -q 90 -lossless -o lossless.webp
$ ls -sh lossless.webp 
7.1M lossless.webp

One may argue that a lossless conversion makes no sense in this scenario, since webp in lossless mode is supposed to be a png replacement and here we have a jpg image, but that's my point: it makes no sense to serve a VP8L webp in this case.

If a client asks for a webp image hoping to save some bandwidth over jpeg, he won't be happy to receive a lossless webp that is more than 2 times the size of what a jpeg would have been. In fact, if lossless webp is all you support, in this scenario you'd be better off ignoring the webp preference and serving the jpg image itself.

webp is intended to be both a png and a jpg replacement, with its lossless and lossy modes respectively. Someone interested in using the format will expect an encoder in the standard library to support both.

@HrachMD
Copy link

HrachMD commented Jan 6, 2025

For instance, one client required WebP output, and while most accept JPEG or PNG, nativewebp let me meet their needs without overhauling my pipeline.

I am curious to know more about this. What client is this that requires only webp output, but does not support jpeg/png? How popular is it?

I have tried with a PNG file (1,1Mb)
Got ~500Kb when making lossless WEBP, while with lossy conversion and still keeping quality - it is ~90Kb.

@HugoSmits86
Copy link

I am curious to know more about this. What client is this that requires only webp output, but does not support jpeg/png? How popular is it?

@agnivade The client is an enterprise with a complex pipeline of 100+ scripts and tools for after-production image processing. They use lossless WebP to avoid quality loss from repeated saves across steps. My tool integrates into this on-premise setup, where file size and/or network traffic isn’t an issue. Switching to PNG or another format would require major changes, including custom metadata handling, needing approval from multiple departments; a lengthy process that could risk the deal. Therefore it was easier for me to just build nativewebp and meet their needs directly and avoid these complications.

webp is intended to be both a png and a jpg replacement, with its lossless and lossy modes respectively. Someone interested in using the format will expect an encoder in the standard library to support both.

@ALTree Your argument overlooks the timeline. While full support for all WebP modes would be ideal, after 14 years of Go and WebP, there’s still no support at all(!), and no signs of it changing. At this point, some support is far better than none.

Those expecting support for all modes likely also expect Google’s language to have native WebP support by now. In both cases, they’ll be equally disappointed but not worse off. Meanwhile, there’s a significant group for whom VP8L support alone provides a viable solution. It’s about addressing current gaps rather than waiting indefinitely for a perfect solution.

@wjkoh
Copy link

wjkoh commented Jan 6, 2025

People don't seem to be asking the right question. There is only one question we need to ask: If we add a lossless WebP encoder to x/image/webp, who will be hurt, and who will benefit? The answer to the first question is no one, and to the second is everyone.

Lossless WebP is already a better alternative to PNG and, in some cases, a deal-closer for Go users, as @HugoSmits86 mentioned above. At what cost? Only about 1,000 lines added to x/image/webp.

Also, the more people see the new encoder, the greater the possibility that they will try to bring a lossy WebP encoder to fruition as well.

@wjkoh
Copy link

wjkoh commented Feb 17, 2025

One of the many applications of this new WebP lossless encoding for Go is Hugo. I only need to install ImageMagick to convert PNG files to WebP files for my Hugo-based website. I think this WebP encoding can allow Hugo to automatically transcode all PNG files to WebP without manual intervention, saving a ton of network traffic for all Hugo users worldwide. @bep @spf13

@bep
Copy link
Contributor

bep commented Feb 17, 2025

As to Hugo; Hugo's extended version (built with -tags extended and requires CGO) supports WebP encoding (using libwebp). The CGO is a hassle, though, so I'm planning to replace the WebP encoder with WASM/WASI, which I suspect would be fast enough considering how we cache things. The AVIF file format is what people on the Hugo issue tracker asks about these days, and with these moving targets, I'm not as bombastic about "demanding" encoder support for these in the Go stdlib.

@ivanjaros
Copy link

ivanjaros commented Feb 17, 2025

Probably OT but wouldn't it be better to just ship hugo with platform-native imagemagic/vips instead of cgo? Personally, I use vips cli to convert images into avif in my projects nowadays. And it is no different than using the old school imagemagic in php, for example, because you still need those libraries to be present in the machine and call them on one way or another, so why not just add one binary to handle all of the work and avoid cgo altogether? Not sure if imagemagic supports pipes, vips does not, but doing the work on file system seems a non-factor to me any way. In the end, Go is has GC and trying to use non-GC code will never not be a problem.

@DemiMarie
Copy link
Contributor

@ivanjaros Image processing libraries are a security nightmare, which is probably why @bep is going to use WebAssembly.

@golang golang deleted a comment from jimwei Feb 18, 2025
@rolandshoemaker
Copy link
Member

Trying to get discussion back on track, it seems like this should be a proposal, specifically to add func Encode(w io.Writer, img image.Image, opt *Options) error and a Options type to x/image/webp, matching the encoders for other formats.

If @HugoSmits86 is willing to contribute their implementation to the standard library under the Go license, I'm not sure there would be objections from the Go team. If the lossless encoder provides value to users, which based on discussion here it seems like it would, adding initial support for only the lossless mode, but with the ability to extend it in the future, seems reasonable.

One thing worth considering though is that the x/image module is relatively lightly maintained. We do not have anyone on the core Go team who actively develops these packages, and they receive sporadic attention (my involvement has been entirely focused on fixing security issues.) It is worth thinking about whether this would provide significant value as an x/image package, or if it can be more valuable (and receive more attention) remaining as a third-party module.

@rolandshoemaker rolandshoemaker changed the title x/image/webp: support for WebP Encoding proposal: x/image/webp: support for WebP Encoding Feb 21, 2025
@gopherbot gopherbot added Proposal and removed NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. labels Feb 21, 2025
@dmitshur dmitshur removed the FeatureRequest Issues asking for a new feature that does not need a proposal. label Feb 21, 2025
@dmitshur dmitshur modified the milestones: Unreleased, Proposal Feb 21, 2025
@HugoSmits86
Copy link

Thanks! I'd love to contribute my encoder to the standard library. Now that nativeWebP has reached version 1.0 with full support for VP8L, updates are going to slow down anyway, mostly optimizations for speed and compression. libwebp still outperforms it in compression efficiency, but at least we're already significantly better than the PNG encoder in the Go image package.

I agree that this should be a formal proposal to add func Encode(w io.Writer, img image.Image, opt *Options) error and an Options type to x/image/webp, following the pattern of other format encoders.

Regarding maintenance, since nativeWebP is stabilizing, I’d expect fewer major updates, which makes it easier to maintain. I understand that x/image doesn’t get as much attention, but if there's interest, I’m happy to contribute and help maintain it. If it makes more sense to keep it as a third-party module for now, I’m open to that as well; whatever best serves Go developers.

Looking forward to thoughts from the team!

@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Feb 23, 2025
@nigeltao
Copy link
Contributor

nigeltao commented Mar 3, 2025

If we add a lossless WebP encoder to x/image/webp, who will be hurt, and who will benefit? The answer to the first question is no one, and to the second is everyone.

The answer to the first question is not "no one". Code has a maintenance cost and image codecs have historically been a rich source of security issues. @HugoSmits86 may have the best of intentions re helping maintain it, but there's no guarantee that he'll still be around 10 years from now. The golang.org/x/image/bmp, golang.org/x/image/tiff and golang.org/x/image/webp packages were all started over 10 years ago but they still need maintenance today. I had great intentions 10 years ago but my work-life and personal-life has changed since then.

IIUC, these 'x' packages were also all started from before we had go get and before GitHub was popular. These days, if people want a Go WebP encoder, running go get github.com/HugoSmits86/nativewebp is just as easy as go get golang.org/x/image/webp but the former doesn't add a maintenance burden to the core Go team.

golang.org/x/etc isn't exactly the standard library, so it isn't as strict about backwards compatibility, but we'd still like it to be "back-compat changes only" if we can. Any new API (that we have to support forever) is a constraint on how the package can evolve. In terms of the quoted comment, it's a "hurt".

For example, the current nativewebp has an Options type. Suppose a future proposal adds a lossy encoder and an Options.Quality field. But if someone further in the future wants to use some unified abstraction over the quality-size-speed trade-off, we may not be able to change the Options.Quality field in a way that's both easy and backwards compatible.

@HugoSmits86
Copy link

If we add a lossless WebP encoder to x/image/webp, who will be hurt, and who will benefit? The answer to the first question is no one, and to the second is everyone.

The answer to the first question is not "no one".

To be fair the "who would be hurt" comment was about releasing an incomplete encoder; one that supports only VP8L at first, instead of waiting until VP8L, VP8, and VP8X (which the decoder also lacks, by the way) are all supported. The point was that supporting VP8L alone wouldn’t negatively impact anyone, so why not make it available sooner?

Nobody is denying that maintaining a codec requires effort. However, I don’t think it’s fair to demand a 10-year commitment upfront. If that were the standard, the Go team itself wouldn’t be able to release anything; unless they exclusively recruited monks who never left their monastery (Ensuring they wouldn’t get hit by a bus and break their decade-long open-source vow).

That said, I understand the concerns around API stability and long-term maintenance. The original discussion wasn’t about implementing a full encoder from the start but rather about adding VP8L support in the absence of VP8. To balance these concerns with maintainability, my proposal is to rework my codec in the style of the existing VP8L decoder.

This approach ensures that potential evolutions, such as lossy encoding, remain outside of the VP8L package, preventing future modifications to the VP8L encoder and keeping the design clean and stable.

Code has a maintenance cost and image codecs have historically been a rich source of security issues.

This argument actually strengthens the case for including an encoder. If security is a concern, relying on third-party libraries outside the Go ecosystem seems like an even greater risk. Expecting users to depend on external, potentially unvetted libraries for a core image format (without a reliable way to assess their security) raises questions about responsibility.

If we acknowledge that image codecs require careful maintenance due to security risks, it seems more responsible to provide a well-maintained, in-house solution rather than pushing users toward potentially unsafe alternatives.

@firelizzard18
Copy link
Contributor

firelizzard18 commented Apr 14, 2025

One issue is discoverability. Searching 'webp' on pkg.go.dev, x/image/webp is the first result, (at least) the next two are C library wrappers, and I have to scroll down to see @HugoSmits86's package at number 10. I didn't know there was a native encoding implementation until I searched for this issue. Is it worth updating x/image/webp's package documentation to link to Hugo's package? Also it would be nice if I could filter out CGO projects when searching, but that's a separate issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests