3 回答

TA貢獻(xiàn)1802條經(jīng)驗(yàn) 獲得超6個(gè)贊
圖像解碼返回一個(gè)圖像接口,該接口具有Bounds獲取圖像像素寬度和高度的方法。
img, _, err := image.Decode(imgfile)
if err != nil {
fmt.Println(err.Error())
}
size := img.Bounds().Size()
獲得寬度和高度后,您可以使用兩個(gè)嵌套的 for 循環(huán)(一個(gè)用于 the x,一個(gè)用于y坐標(biāo))遍歷像素。
for x := 0; x < size.X; x++ {
for y := 0; y < size.Y; y++ {
color := color.RGBA{
uint8(255 * x / size.X),
uint8(255 * y / size.Y),
55,
255}
m.Set(x, y, color)
}
}
完成圖像處理后,您可以對(duì)文件進(jìn)行編碼。但是因?yàn)閕mage.Image沒(méi)有Set方法,您可以創(chuàng)建一個(gè)新的RGBA圖像,該圖像返回一個(gè)RGBA結(jié)構(gòu)體,您可以在該結(jié)構(gòu)體上使用該Set方法。
m := image.NewRGBA(image.Rect(0, 0, width, height))
outFile, err := os.Create("changed.jpg")
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
png.Encode(outFile, m)

TA貢獻(xiàn)1808條經(jīng)驗(yàn) 獲得超4個(gè)贊
image.Image 默認(rèn)是不可變的,但 draw.Image 是可變的。
如果你對(duì) draw.Image 進(jìn)行類(lèi)型轉(zhuǎn)換,那應(yīng)該會(huì)給你一個(gè) Set 方法
img.(draw.Image).Set(0,0, color.RGBA{85, 165, 34, 1})

TA貢獻(xiàn)1848條經(jīng)驗(yàn) 獲得超2個(gè)贊
在成功解碼image.Decode()(以及特定的解碼函數(shù),如jpeg.Decode())時(shí),返回值image.Image。image.Image是一個(gè)定義圖像只讀視圖的接口:它不提供更改/繪制圖像的方法。
該image包提供了幾種image.Image實(shí)現(xiàn),允許您更改/繪制圖像,通常使用一種Set(x, y int, c color.Color)方法。
image.Decode()但是不保證返回的圖像將是image包中定義的任何圖像類(lèi)型,甚至Set()不保證圖像的動(dòng)態(tài)類(lèi)型具有方法(可能,但不能保證)。注冊(cè)的自定義圖像解碼器可能會(huì)返回一個(gè)image.Image作為自定義實(shí)現(xiàn)的值(意味著不是image包中定義的圖像類(lèi)型)。
如果(動(dòng)態(tài)類(lèi)型的)圖像確實(shí)有Set()方法,則可以使用類(lèi)型斷言并使用其Set()方法對(duì)其進(jìn)行繪制。這是如何做到的:
type Changeable interface {
Set(x, y int, c color.Color)
}
imgfile, err := os.Open("unchanged.jpg")
if err != nil {
panic(err.Error())
}
defer imgfile.Close()
img, err := jpeg.Decode(imgfile)
if err != nil {
panic(err.Error())
}
if cimg, ok := img.(Changeable); ok {
// cimg is of type Changeable, you can call its Set() method (draw on it)
cimg.Set(0, 0, color.RGBA{85, 165, 34, 255})
cimg.Set(0, 1, color.RGBA{255, 0, 0, 255})
// when done, save img as usual
} else {
// No luck... see your options below
}
如果圖像沒(méi)有Set()方法,您可以選擇通過(guò)實(shí)現(xiàn)實(shí)現(xiàn) 的自定義類(lèi)型來(lái)“覆蓋其視圖” image.Image,但在其At(x, y int) color.Color方法(返回/提供像素的顏色)中,您將返回您將設(shè)置的新顏色,如果圖像將是可變的,并返回原始圖像的像素,您不會(huì)更改圖像。
image.Image使用embedding最容易實(shí)現(xiàn)接口,因此您只需要實(shí)現(xiàn)您想要的更改。這是如何做到的:
type MyImg struct {
// Embed image.Image so MyImg will implement image.Image
// because fields and methods of Image will be promoted:
image.Image
}
func (m *MyImg) At(x, y int) color.Color {
// "Changed" part: custom colors for specific coordinates:
switch {
case x == 0 && y == 0:
return color.RGBA{85, 165, 34, 255}
case x == 0 && y == 1:
return color.RGBA{255, 0, 0, 255}
}
// "Unchanged" part: the colors of the original image:
return m.Image.At(x, y)
}
使用它:非常簡(jiǎn)單。像您一樣加載圖像,但在保存時(shí),請(qǐng)?zhí)峁┪覀僊yImg類(lèi)型的值,該值將在編碼器詢(xún)問(wèn)時(shí)提供更改的圖像內(nèi)容(顏色):
jpeg.Encode(outFile, &MyImg{img}, nil)
如果您必須更改許多像素,則在At()方法中包含所有像素是不切實(shí)際的。為此,我們可以擴(kuò)展我們MyImg的Set()實(shí)現(xiàn)來(lái)存儲(chǔ)我們想要更改的像素。示例實(shí)現(xiàn):
type MyImg struct {
image.Image
custom map[image.Point]color.Color
}
func NewMyImg(img image.Image) *MyImg {
return &MyImg{img, map[image.Point]color.Color{}}
}
func (m *MyImg) Set(x, y int, c color.Color) {
m.custom[image.Point{x, y}] = c
}
func (m *MyImg) At(x, y int) color.Color {
// Explicitly changed part: custom colors of the changed pixels:
if c := m.custom[image.Point{x, y}]; c != nil {
return c
}
// Unchanged part: colors of the original image:
return m.Image.At(x, y)
}
使用它:
// Load image as usual, then
my := NewMyImg(img)
my.Set(0, 0, color.RGBA{85, 165, 34, 1})
my.Set(0, 1, color.RGBA{255, 0, 0, 255})
// And when saving, save 'my' instead of the original:
jpeg.Encode(outFile, my, nil)
如果您必須更改許多像素,那么創(chuàng)建一個(gè)支持更改其像素的新圖像可能會(huì)更有利可圖,例如image.RGBA,在其上繪制原始圖像,然后繼續(xù)更改您想要的像素。
要將圖像繪制到另一個(gè)圖像上,您可以使用該image/draw包。
cimg := image.NewRGBA(img.Bounds())
draw.Draw(cimg, img.Bounds(), img, image.Point{}, draw.Over)
// Now you have cimg which contains the original image and is changeable
// (it has a Set() method)
cimg.Set(0, 0, color.RGBA{85, 165, 34, 255})
cimg.Set(0, 1, color.RGBA{255, 0, 0, 255})
// And when saving, save 'cimg' of course:
jpeg.Encode(outFile, cimg, nil)
以上代碼僅用于演示。在“現(xiàn)實(shí)生活”中,圖像Image.Bounds()可能會(huì)返回一個(gè)不是從(0;0)點(diǎn)開(kāi)始的矩形,在這種情況下,需要進(jìn)行一些調(diào)整才能使其工作。
- 3 回答
- 0 關(guān)注
- 301 瀏覽
添加回答
舉報(bào)