关于imagic拼接透明背景图片的问题

目标:

为了做图片水印,需要水平拼接多个logo和文字。。。

之前用过imagick,所以继续使用。

第一个版本:实现了图片和文字的拼接,代码如下:

package main

import (
    "fmt"

    "gopkg.in/gographics/imagick.v2/imagick"
)

func draw_setfont(mw *imagick.MagickWand,
    dw *imagick.DrawingWand,
    font string, size float64,
    colour string, sx *float64) {
    sflag := false

    if len(font) > 0 {
        dw.SetFont(font)
        sflag = true
    }

    if len(colour) > 0 {
        pw := imagick.NewPixelWand()
        pw.SetColor(colour)
        dw.SetFillColor(pw)
        pw.Destroy()
        sflag = true
    }

    if size > 0 {
        dw.SetFontSize(size)
    }

    if sflag {
        fm := mw.QueryFontMetrics(dw, " ")
        *sx = fm.TextWidth
    }
}

// sx is the width of a space in the current font and fontsize.
// If the font or fontsize is changed a new value for the space
// width must be obtained before calling this again (by calling draw_setfont)
func draw_metrics(mw *imagick.MagickWand, dw *imagick.DrawingWand, dx *float64, dy, sx float64, text string) {
    mw.AnnotateImage(dw, *dx, dy, 0, text)
    mw.DrawImage(dw)

    // get the font metrics
    fm := mw.QueryFontMetrics(dw, text)
    if fm != nil {
        // Adjust the new x coordinate
        *dx += fm.TextWidth + sx
    }
}

func main() {
    imagick.Initialize()
    defer imagick.Terminate()

    mw := imagick.NewMagickWand()
    ll := imagick.NewMagickWand()
    nn := imagick.NewMagickWand()
    bb := imagick.NewMagickWand()

    fmt.Println("read logo...")
    ll.ReadImage("../logo3.png")
    nn.ReadImage("../logo2.png")
//加上文字
    bb.SetSize(400, 128)
    bb.ReadImage("xc:none")
    dw := imagick.NewDrawingWand()
    var dx, dy, sx float64
    dx = 10//set y
    dw.SetFontSize(32)
    dw.SetFont("Times-New-Roman")
    fm := bb.QueryFontMetrics(dw, "M")
    dy = fm.CharacterHeight + fm.Descender + 50

    dw.SetTextEncoding("UTF-8")
    dw.SetFont("../yahei.ttf")
    fmt.Println("start draw.......")
    draw_setfont(bb, dw, "", 32, "#40FF80", &sx)
    fmt.Println("curr:", sx, "dy:", dy)
    draw_metrics(bb, dw, &dx, dy, sx, "like......你好。。。")
    bb.DrawImage(dw)
    bb.WriteImage("font.png")

    mw.AddImage(ll)
    mw.AddImage(nn)
    mw.AddImage(bb)

    total := mw.MontageImage(ndw, "3x1", "", 0, "0")
    total.WriteImage("append.png")
}

实现效果:图片和文字,都已经拼接到一行,拼接方式由 MontageImage 第二个参数决定(Nx1,表示都在一行。。。)

但是有个问题,原先透明的logo图片,拼接到一起,居然没有透明效果了。。。。。

各种查资料,然后第二版来了

package main

import (
    "fmt"

    "gopkg.in/gographics/imagick.v2/imagick"
)

func draw_setfont(mw *imagick.MagickWand,
    dw *imagick.DrawingWand,
    font string, size float64,
    colour string, sx *float64) {
    sflag := false

    if len(font) > 0 {
        dw.SetFont(font)
        sflag = true
    }

    if len(colour) > 0 {
        pw := imagick.NewPixelWand()
        pw.SetColor(colour)
        dw.SetFillColor(pw)
        pw.Destroy()
        sflag = true
    }

    if size > 0 {
        dw.SetFontSize(size)
    }

    if sflag {
        fm := mw.QueryFontMetrics(dw, " ")
        *sx = fm.TextWidth
    }
}

// sx is the width of a space in the current font and fontsize.
// If the font or fontsize is changed a new value for the space
// width must be obtained before calling this again (by calling draw_setfont)

func draw_metrics(mw *imagick.MagickWand, dw *imagick.DrawingWand, dx *float64, dy, sx float64, text string) {
    mw.AnnotateImage(dw, *dx, dy, 0, text)
    mw.DrawImage(dw)

    // get the font metrics
    fm := mw.QueryFontMetrics(dw, text)
    if fm != nil {
        // Adjust the new x coordinate
        *dx += fm.TextWidth + sx
    }
}

func main() {
    imagick.Initialize()
    defer imagick.Terminate()

    mw := imagick.NewMagickWand()
    ll := imagick.NewMagickWand()
    nn := imagick.NewMagickWand()
    bb := imagick.NewMagickWand()

    fmt.Println("read logo...")
    ll.ReadImage("../logo3.png")
    nn.ReadImage("../logo2.png")

    //加上文字
    bb.SetSize(400, 128)
    bb.ReadImage("xc:none")
    dw := imagick.NewDrawingWand()
    var dx, dy, sx float64
    dx = 10

    //set y
    dw.SetFontSize(32)
    dw.SetFont("Times-New-Roman")
    fm := bb.QueryFontMetrics(dw, "M")
    dy = fm.CharacterHeight + fm.Descender + 50

    dw.SetTextEncoding("UTF-8")
    dw.SetFont("../yahei.ttf")
    fmt.Println("start draw.......")
    draw_setfont(bb, dw, "", 32, "#40FF80", &sx)
    fmt.Println("curr:", sx, "dy:", dy)
    draw_metrics(bb, dw, &dx, dy, sx, "like......你好。。。")
    bb.DrawImage(dw)

    mw.AddImage(ll)
    mw.AddImage(nn)
    mw.AddImage(bb)

    mw.ResetIterator()
    append_img := mw.AppendImages(false)
    append_img.WriteImage("append.png")
}

标红的两行代码是关键,如果不调用 ResetIterator,则拼接的终效果是最后一张图片,这里是让迭代器指向第一张图片,重新开始。

AppendImages的参数,true或者false表示上下排列(true),还是水平排列(false)。

OK,到这里,就可以完成目标了。

不得不说,imagick很强大,但是API研究起来还是很头疼呀。

另外,如果你想把一张有背景的图片的 背景去掉,变成透明,那么可以用下面的方法。

// Port of http://members.shaw.ca/el.supremo/MagickWand/trans_paint.htm to Go
package main

import "gopkg.in/gographics/imagick.v2/imagick"

func main() {
    imagick.Initialize()
    defer imagick.Terminate()

    mw := imagick.NewMagickWand()
    mw.ReadImage("logo:")

    // A larger fuzz value allows more colours "near" white to be
    // modified. A fuzz of zero only allows an exact match with the
    // given colour
    // Set up the pixelwand containing the colour to be "targeted"
    // by transparency
    target := imagick.NewPixelWand()
    target.SetColor("white")
    // Change the transparency of all colours which match target (with
    // fuzz applied). In this case they are made completely transparent (0)
    // but you can set this to any value from 0 to 1.
    mw.TransparentPaintImage(target, 0, 10, false)
    mw.WriteImage("logo_white.png")
}

但是这个方法也不是万能的,SetColor用来指定需要去处的背景色,程序会查找相似的颜色,并去掉,然后编程透明。

原文地址:https://www.cnblogs.com/zhangqingping/p/5741801.html