将额外的数据写入io.Writer

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

writing extra data into io.Writer

问题

我正在尝试弄清楚如何更改jpeg.Encode API(http://golang.org/pkg/image/jpeg/#Encode)的行为,该API接受一个io.Writer作为参数,并将文件写入其中。

我需要在写入文件的前两个字节之后插入一组字节,并且我认为可以在不将所有内容保存在内存中的情况下完成。我对Golang还不熟悉,我找到了io.Pipe,它连接了一个读取器和一个写入器,但我不知道如何将其用于我所需的情况。

有人可以帮忙吗?

编辑:我应该只是实现自己的io.Writer接口吗?

英文:

I am trying to figure out how to change the behaviour of jpeg.Encode API (http://golang.org/pkg/image/jpeg/#Encode) that takes an io.Writer as a parameter and writes the file to it.

I need to insert a set of bytes after the first two bytes written in to the file, and I think it is possible to do without keeping everything in memory. I am new to Golang, I found io.Pipe that connects a reader and a writer, but I do not understand how to use it for what I need.

Could someone help?

EDIT: should I just implement my own io.Writer interface?

答案1

得分: 6

如果您事先知道需要在流中添加的字节(无论是哪种流,包括图像),为此特定目的构建一个Writer对象并不是很困难。

这是一个示例:

package main

import (
	"fmt"
	"image"
	"image/draw"
	"image/jpeg"
	"image/color"
	"os"
	"io"
)

type ByteInserter struct {
	n   int
	b   []byte
	pos int
	w   io.Writer
}

func NewByteInserter(w io.Writer) *ByteInserter {
	return &ByteInserter{w:w}
}

func (bi *ByteInserter) Set(b []byte, pos int) {
	bi.b = b
	bi.pos = pos
}

func (bi *ByteInserter) Write(p []byte) (n int, err error) {
	if bi.n > bi.pos || bi.n+len(p) <= bi.pos {
		n, err = bi.w.Write(p)
		bi.n += n
	} else {
		cut := bi.pos - bi.n
		if cut > 0 {
			n, err = bi.w.Write(p[:cut])
			bi.n += n
			if err != nil {
				return
			}
		}
		_, err = bi.w.Write(bi.b)
		if err != nil {
			return
		}
		n2 := 0
		n2, err = bi.w.Write(p[cut:])
		bi.n += n2
		n += n2
	}
	return
}

func main() {

    // 蓝色矩形,从Nigel Tao的帖子中借来
    // http://blog.golang.org/go-imagedraw-package
	img := image.NewRGBA(image.Rect(0, 0, 640, 480))
	blue := color.RGBA{0, 0, 255, 255}
	draw.Draw(img, img.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)

	file, err := os.Create("file.jpg")
	if err != nil {
		panic(err)
	}

	bi := NewByteInserter(file)
	bi.Set([]byte("XXX"), 2)   // 在位置2添加三个字节
	jpeg.Encode(bi, img, nil)
	file.Close()

	fmt.Println("已写入!")
}

话虽如此,编辑流以自定义图像对我来说似乎有点破坏性。

英文:

If you know upfront the bytes you need to add in the stream (whatever the stream, image or not), building a Writer object for this specific purpose is not really hard.

Here is an example:

package main
import (
&quot;fmt&quot;
&quot;image&quot;
&quot;image/draw&quot;
&quot;image/jpeg&quot;
&quot;image/color&quot;
&quot;os&quot;
&quot;io&quot;
)
type ByteInserter struct {
n   int
b   []byte
pos int
w   io.Writer
}
func NewByteInserter(w io.Writer) *ByteInserter {
return &amp;ByteInserter{w:w}
}
func (bi* ByteInserter) Set( b[]byte, pos int ) {
bi.b = b
bi.pos = pos
}
func (bi *ByteInserter) Write( p []byte ) (n int, err error) {
if bi.n&gt;bi.pos || bi.n+len(p)&lt;=bi.pos {
n, err = bi.w.Write(p)
bi.n += n
} else {
cut := bi.pos-bi.n
if cut &gt; 0 {
n,err = bi.w.Write(p[:cut])
bi.n += n
if err != nil {
return
}
}
_,err = bi.w.Write(bi.b)
if err != nil {
return
}
n2 := 0
n2, err = bi.w.Write(p[cut:])
bi.n += n2
n += n2
}
return
}
func main() {
// Blue rectangle, stolen from Nigel Tao&#39;s post
// http://blog.golang.org/go-imagedraw-package
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
blue := color.RGBA{0, 0, 255, 255}
draw.Draw(img, img.Bounds(), &amp;image.Uniform{blue}, image.ZP, draw.Src)
file, err := os.Create(&quot;file.jpg&quot;)
if err != nil {
panic(err)
}
bi := NewByteInserter(file)
bi.Set( []byte(&quot;XXX&quot;), 2 )   // Three bytes added at position 2
jpeg.Encode(bi,img,nil)
file.Close()
fmt.Println(&quot;Written!&quot;)
}

That said, editing a stream to customize an image seems really hackish to me.

答案2

得分: 2

除非您能直接获取具有正确内容的图像(即您需要的额外字节),否则您确实需要提供自己的Writer。

第一种策略例如在signer/signer.go中进行了说明:您可以修改图像以添加所需的信息(在jianfengye/image-sign项目中的情况是添加签名)。

但是,如果您无法将这些信息添加到图像中,则需要提供一个Writer来管理所需的写入操作。jpeg/writer.go 已经实现了这一点,它使用自己的内部writer类型

一旦jpeg writer 开始写入图像,它将调用您自己的Writer,然后您可以决定是否添加这些额外的字节。

_, e.err = e.w.Write(p)
英文:

Unless you manage to get an Image directly with the right content (meaning the extra bytes you need), you would have indeed to provide your own Writer.

The first strategy is illustrated for instance in signer/signer.go: you modify an image in order to add the information you want (in the case of the jianfengye/image-sign project: a signature)

But if you cannot add those to the Image, then you need to provide a Writer which will manage the expected writing.
jpeg/writer.go does already that, with its own internal writer type.

Once the jpeg writer starts to write the Image, it will call your own Writer, which can then decide to add those extra bytes or not.

_, e.err = e.w.Write(p)

huangapple
  • 本文由 发表于 2014年12月31日 14:30:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/27717141.html
匿名

发表评论

匿名网友

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

确定