Golang的image/gif EncodeAll函数有很多黑点。

huangapple go评论104阅读模式
英文:

Golang image/gif EncodeAll have many black dots

问题

我有许多PNG图像,想要将它们编码为GIF动画。

这些PNG图像没有任何黑点,但是GIF结果中有很多黑点。

    g := new(gif.GIF)
	frames := len(images)
	g.Image = make([]*image.Paletted, frames)
	g.Delay = make([]int, frames)
	eg := errgroup.Group{}
	var cl color.Palette = palette.Plan9
	for k, img := range images {
		img := img
		k := k
		eg.Go(func() error {
			Paletted := image.NewPaletted(img.Bounds(), cl)
			draw.FloydSteinberg.Draw(Paletted, img.Bounds(), img, image.Point{})
			g.Image[k] = Paletted
			g.Delay[k] = deply
			return nil
		})
	}
	if err := eg.Wait(); err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	err := gif.EncodeAll(&buf, g)

原始PNG图像:
Golang的image/gif EncodeAll函数有很多黑点。

带有编号的图像:
Golang的image/gif EncodeAll函数有很多黑点。

我的PNG图像信息:

  • 文件类型:PNG
  • 文件扩展名:png
  • MIME类型:image/png
  • 位深度:8
  • 颜色类型:带有Alpha通道的RGB
  • 压缩:Deflate/Inflate
  • 滤波器:自适应
  • 交错:非交错
  • SRGB渲染:感知渲染
  • Exif字节顺序:大端序(Motorola,MM)
  • 色彩空间:sRGB

带有黑点的GIF图像:
Golang的image/gif EncodeAll函数有很多黑点。

使用palgen.Generate(img, 256)生成的图像:
Golang的image/gif EncodeAll函数有很多黑点。

英文:

I have many png images and want encode them to a gif animation.

These png images dont have any black dots ,but the gif result have many dots.

    g := new(gif.GIF)
	frames := len(images)
	g.Image = make([]*image.Paletted, frames)
	g.Delay = make([]int, frames)
	eg := errgroup.Group{}
	var cl color.Palette = palette.Plan9
	for k, img := range images {
		img := img
		k := k
		eg.Go(func() error {
			Paletted := image.NewPaletted(img.Bounds(), cl)
			draw.FloydSteinberg.Draw(Paletted, img.Bounds(), img, image.Point{})
			g.Image[k] = Paletted
			g.Delay[k] = deply
			return nil
		})
	}
	if err := eg.Wait(); err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	err := gif.EncodeAll(&buf, g)

origin png:
Golang的image/gif EncodeAll函数有很多黑点。

with num:
Golang的image/gif EncodeAll函数有很多黑点。

my png info:

> File Type : PNG
File Type Extension : png
MIME Type : image/png
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
SRGB Rendering : Perceptual
Exif Byte Order : Big-endian (Motorola, MM)
Color Space : sRGB

gif with black dots:
Golang的image/gif EncodeAll函数有很多黑点。

used palgen.Generate(img, 256):

Golang的image/gif EncodeAll函数有很多黑点。

答案1

得分: 2

GIF使用256色调色板,而PNG通常是RGBA格式,每个颜色通道至少有8位(包括透明度)。在你提供的不完整示例代码中,你使用了预定义的palette.Plan9调色板。从原始PNG中选择至少最显著的颜色,显示为RGB颜色#f08740。但是在Plan9调色板中没有匹配的颜色,所以FloydSteinberg将不得不使用Plan9调色板中的“最近”颜色进行抖动处理。显然,这并不起作用。

你需要使用适应的调色板来避免抖动,要么完全避免,要么至少将其最小化。由于你提供的示例不完整,我不得不自己编写一个最小示例,根据给定的唯一PNG源图像创建一个自定义调色板的GIF(下次请上传单独的图像,不要将所有内容放在一个图像中,这样非常不方便)。

快速搜索发现Go模块github.com/xyproto/palgen可以根据输入图像和指定的颜色数量创建自定义的color.Palette调色板;这个模块似乎在积极维护,并且我在使用它时立即成功:

img, _, err := image.Decode(f)
pal, err := palgen.Generate(img, 256)

以下是一个完整的示例,根据source.png源PNG图像生成一个适合的GIF(gif.gif),并且没有抖动:

package main

import (
	"image"
	"image/draw"
	"image/gif"
	_ "image/png"
	"os"

	"github.com/xyproto/palgen"
)

func main() {
	g := new(gif.GIF)
	g.Image = make([]*image.Paletted, 1)
	g.Delay = make([]int, 1)

	f, err := os.Open("source.png")
	if err != nil {
		panic(err)
	}
	defer f.Close()
	img, _, err := image.Decode(f)
	pal, err := palgen.Generate(img, 256)

	Paletted := image.NewPaletted(img.Bounds(), pal)
	draw.FloydSteinberg.Draw(Paletted, img.Bounds(), img, image.Point{})
	g.Image[0] = Paletted
	g.Delay[0] = 100

	out, err := os.Create("gif.gif")
	if err != nil {
		panic(err)
	}
	defer out.Close()
	err = gif.EncodeAll(out, g)
	if err != nil {
		panic(err)
	}
}

源图像source.png

Golang的image/gif EncodeAll函数有很多黑点。

最终的GIF gif.gif

Golang的image/gif EncodeAll函数有很多黑点。

英文:

GIF uses a 256 color palette, whereas PNG typically is RGBA with at least 8 bits per color channel (and alpha). In your incomplete example code you use the predefined palette.Plan9 color palette. Picking at least the most dominant color in the origin PNG shows it's the RGB color #f08740. But there is no matching color in the Plan9 palette, so FloydSteinberg will have to dither using "nearest" colors from the Plan9 palette. This obviously doesn't work well.

You need to use an adapted palette to avoid dithering either at all or at least minimize it. As you are giving a non-minimal and incomplete example, I had to roll a minimal example myself that creates a custom palette for the GIF based on the only PNG source given (and please, do upload separate images next time, don't put everything into a single image, it makes things really inconvenient).

A quick google search reveals the Go module github.com/xyproto/palgen that does create a custom color.Palette based on an input image and with the specified numbers of colors; this module seems to be actively maintained and I had immediate success in using it:

img, _, err := image.Decode(f)
pal, err := palgen.Generate(img, 256)

The full example that produces for me a suitable GIF (gif.gif) without dithering, given a source PNG in source.png:

package main

import (
	"image"
	"image/draw"
	"image/gif"
	_ "image/png"
	"os"

	"github.com/xyproto/palgen"
)

func main() {
	g := new(gif.GIF)
	g.Image = make([]*image.Paletted, 1)
	g.Delay = make([]int, 1)

	f, err := os.Open("source.png")
	if err != nil {
		panic(err)
	}
	defer f.Close()
	img, _, err := image.Decode(f)
	pal, err := palgen.Generate(img, 256)

	Paletted := image.NewPaletted(img.Bounds(), pal)
	draw.FloydSteinberg.Draw(Paletted, img.Bounds(), img, image.Point{})
	g.Image[0] = Paletted
	g.Delay[0] = 100

	out, err := os.Create("gif.gif")
	if err != nil {
		panic(err)
	}
	defer out.Close()
	err = gif.EncodeAll(out, g)
	if err != nil {
		panic(err)
	}
}

Source image source.png:

Golang的image/gif EncodeAll函数有很多黑点。

Final GIF gif.gif:

Golang的image/gif EncodeAll函数有很多黑点。

答案2

得分: 0

使用:
draw.Draw(Paletted,img.Bounds(),img,image.ZP, draw.Src)

替换为:
draw.FloydSteinberg.Draw(Paletted, img.Bounds(), img, image.Point{})

英文:

Use:
draw.Draw(Paletted,img.Bounds(),img,image.ZP, draw.Src)

Replace:
draw.FloydSteinberg.Draw(Paletted, img.Bounds(), img, image.Point{})

huangapple
  • 本文由 发表于 2022年10月7日 20:55:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/73987493.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定