func drawText(font *truetype.Font, c *freetype.Context, color color.Color, rgba *image.RGBA, text string) (int, int) { fg := image.NewUniform(color) bg := image.Transparent draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c.SetFont(font) c.SetDst(rgba) c.SetSrc(fg) c.SetClip(rgba.Bounds()) // height is the fraction of the font that is above the line, 1.0 would mean // that the font never falls below the line // TODO: wtf - this is all wrong! // fix fonts - we can't change the font size easily height := 1.3 pt := freetype.Pt(0, int(float64(c.PointToFixed(*size)>>8)*height)) adv, _ := c.DrawString(text, pt) pt.X += adv.X py := int(float64(pt.Y>>8)/height + 0.01) return int(pt.X >> 8), py }
// CenterX returns the Point at which string s will be centered within rect r // along the X coordinate when passed to c.DrawString. The Y coordinate will be 0. // Clip is set to r before returning. func CenterX(c *freetype.Context, s string, r image.Rectangle) (fixed.Point26_6, error) { w, err := DrawWidth(c, s) c.SetClip(r) if err != nil { return fixed.Point26_6{}, err } half := Int26_6(0.5) xmin := freetype.Pt(r.Min.X, 0) return freetype.Pt(r.Dx(), 0).Mul(half).Sub(w.Mul(half)).Add(xmin), nil }
func (f *Font) Render(text string) *Texture { width, height, yBearing := f.TextDimensions(text) font := f.ttf size := f.Size // Colors fg := image.NewUniform(color.NRGBA{f.FG.R, f.FG.G, f.FG.B, f.FG.A}) bg := image.NewUniform(color.NRGBA{f.BG.R, f.BG.G, f.BG.B, f.BG.A}) // Create the font context c := freetype.NewContext() nrgba := image.NewNRGBA(image.Rect(0, 0, width, height)) draw.Draw(nrgba, nrgba.Bounds(), bg, image.ZP, draw.Src) c.SetDPI(dpi) c.SetFont(font) c.SetFontSize(size) c.SetClip(nrgba.Bounds()) c.SetDst(nrgba) c.SetSrc(fg) // Draw the text. pt := freetype.Pt(0, int(yBearing)) _, err := c.DrawString(text, pt) if err != nil { log.Println(err) return nil } // Create texture imObj := &ImageObject{nrgba} return NewTexture(imObj) }
func (this *Signer) drawStringImage(text string) (image.Image, error) { fontBytes, err := ioutil.ReadFile(this.fontPath) if err != nil { fmt.Println(err) } font, err := freetype.ParseFont(fontBytes) if err != nil { fmt.Println(err) } rgba := image.NewRGBA(image.Rect(0, 0, 900, 900)) draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(this.dpi) c.SetFontSize(this.fontSize) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(image.White) c.SetFont(font) pt := freetype.Pt(100, 100+int(c.PointToFixed(this.fontSize)>>8)) for _, s := range strings.Split(text, "\r\n") { _, err = c.DrawString(s, pt) pt.Y += c.PointToFixed(12 * 1.5) } return rgba, nil }
func drawBarcode(img *image.Gray, unitSize, xPos, yPos float64, num int) { drawSO(img, unitSize, xPos, yPos) x := xPos + unitSize*4.0 // Draw reference bar x += drawBar(img, unitSize, x, yPos, 0) + unitSize // Print the form number below the barcode ftContext.SetFontSize(7) ftContext.SetSrc(image.NewUniform(color.Black)) ftContext.DrawString(fmt.Sprintf("%d", num), freetype.Pt(int(x), int(yPos+unitSize*7))) // Draw bars ds := toBase4(num, 9) for i := len(ds) - 1; i >= 0; i-- { x += drawBar(img, unitSize, x, yPos, ds[i]) + unitSize } // Draw checksum bars ckBase10 := csumGen(num) fmt.Println("ckBase10 = ", ckBase10) ck := toBase4(ckBase10, 2) fmt.Println("ck = ", ck) for i := len(ck) - 1; i >= 0; i-- { x += drawBar(img, unitSize, x, yPos, ck[i]) + unitSize } }
func Example() { // As usual in examples, this ignores all errors. Don't do this in your program. // setup and find start point for centering s := "Hello, World!" size := image.Rect(0, 0, 120, 20) dst := image.NewRGBA(size) c := freetype.NewContext() c.SetFont(font) c.SetFontSize(14.0) c.SetSrc(image.NewUniform(color.Black)) c.SetDst(dst) start, _ := fontutil.CenterX(c, s, size) // CenterX calls c.SetClip(size) // perform draw at start.X + y 16 c.DrawString(s, start.Add(freetype.Pt(0, 16))) // write the image out to a file // out, _ := os.Create("helloworld.png") // defer out.Close() // write image to hash for testing purposes out := fnv.New64() _ = png.Encode(out, dst) fmt.Printf("Hash of compressed image: %x", out.Sum64()) // Output: Hash of compressed image: fa83a1b8d8abf5f2 }
func (ff *FontFace) GetImage(text string) (img draw.Image, err error) { var ( src image.Image bg image.Image dst draw.Image pt fixed.Point26_6 w int h int ) src = image.NewUniform(ff.fg) bg = image.NewUniform(ff.bg) w = int(float32(len(text)) * ff.charw) h = int(ff.charh) dst = image.NewRGBA(image.Rect(0, 0, w, h)) draw.Draw(dst, dst.Bounds(), bg, image.ZP, draw.Src) ff.context.SetSrc(src) ff.context.SetDst(dst) ff.context.SetClip(dst.Bounds()) pt = freetype.Pt(0, int(ff.charh+ff.offy)) if pt, err = ff.context.DrawString(text, pt); err != nil { return } img = image.NewRGBA(image.Rect(0, 0, int(pt.X/64), int(pt.Y/64))) draw.Draw(img, img.Bounds(), dst, image.Pt(0, -int(ff.offy)), draw.Src) return }
func (a *Annotator) DrawInfoBox() error { tStart, tEnd := a.table.TimeStart, a.table.TimeEnd // tDuration := humanize.RelTime(*tStart, *tEnd, "", "") tPixel := (tEnd.Unix() - tStart.Unix()) / int64(a.table.Integrations) fStart, fEnd := a.table.HzLow, a.table.HzHigh fBandwidth := fEnd - fStart fPixel := fBandwidth / float64(a.table.Bins) perPixel := fmt.Sprintf("%s x %d seconds", a.humanHz(fPixel), tPixel) // positioning imgSize := a.table.Image().Bounds().Size() top, left := imgSize.Y-75, 3 strings := []string{ "Scan start: " + tStart.String(), "Scan end: " + tEnd.String(), // "Scan duration: " + tDuration, fmt.Sprintf("Band: %s to %s", a.humanHz(fStart), a.humanHz(fEnd)), fmt.Sprintf("Bandwidth: %s", a.humanHz(fBandwidth)), "1 pixel = " + perPixel, } // drawing pt := freetype.Pt(left, top) for _, s := range strings { _, _ = a.context.DrawString(s, pt) pt.Y += a.context.PointToFixed(size * spacing) } return nil }
func (ff *FontFace) GetText(text string) (t *Texture, err error) { var ( src image.Image bg image.Image dst draw.Image shortened draw.Image pt fixed.Point26_6 w int h int ) src = image.NewUniform(ff.fg) bg = image.NewUniform(ff.bg) w = int(float32(len(text)) * ff.charw) h = int(ff.charh) dst = image.NewRGBA(image.Rect(0, 0, w, h)) draw.Draw(dst, dst.Bounds(), bg, image.ZP, draw.Src) ff.context.SetSrc(src) ff.context.SetDst(dst) ff.context.SetClip(dst.Bounds()) pt = freetype.Pt(0, int(ff.charh)) if pt, err = ff.context.DrawString(text, pt); err != nil { return } // if err = WritePNG("hello.png", dst); err != nil { // return // } shortened = image.NewRGBA(image.Rect(0, 0, int(pt.X/64), h)) draw.Draw(shortened, shortened.Bounds(), dst, image.ZP, draw.Src) t, err = GetTexture(shortened, gl.NEAREST) return }
func main() { fontBytes, err := ioutil.ReadFile("luxisr.ttf") if err != nil { log.Fatal(err) } font, err := freetype.ParseFont(fontBytes) if err != nil { log.Fatal(err) } fg, bg := image.White, image.Black rgba := image.NewRGBA(image.Rect(0, 0, width, height)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(font) c.SetFontSize(size) c.SetClip(rgba.Bounds()) c.SetDst(rgba) c.SetSrc(fg) c.SetHinting(freetype.FullHinting) count := 0 l := NewLife(width, height) for { if count%10 == 0 { count = 0 pt := freetype.Pt(rand.Intn(width-width/4), height/4+rand.Intn(height-height/4)) c.DrawString("NOPE", pt) for x := 0; x < width; x++ { for y := 0; y < height; y++ { c := rgba.RGBAAt(x, y) l.a.Set(x, y, c.R > 0 || c.B > 0 || c.G > 0) } } } count++ for x := 0; x < width; x++ { for y := 0; y < height; y++ { var c color.Color = color.Black if l.a.Alive(x, y) { c = rainbow(y) } rgba.Set(x, y, c) } } //fmt.Println(l) sendImage(rgba) l.Step() time.Sleep(time.Second / 8) } }
func (w *TextEditLine) findOffsetAtIndex(index int) float64 { pt := freetype.Pt(0, 0) if index > len(w.text) { index = len(w.text) } if index < 0 { index = 0 } adv, _ := w.context.DrawString(w.text[:index], pt) return float64(adv.X>>8) * w.scale }
func (a *Annotator) DrawYScale() error { log.WithFields(log.Fields{ "timestart": a.table.TimeStart.String(), "timeend": a.table.TimeEnd.String(), }).Debug("annotate Y scale") start, end := a.table.TimeStart, a.table.TimeEnd // how many samples? count := int(math.Floor(float64(a.table.Integrations) / float64(100))) uStart := start.Unix() uEnd := end.Unix() secsPerLabel := int(math.Floor(float64(uEnd-uStart) / float64(count))) pxPerLabel := int(math.Floor(float64(a.table.Integrations) / float64(count))) log.WithFields(log.Fields{ "labels": count, "secsPerLabel": secsPerLabel, "pxPerLabel": pxPerLabel, }).Debug("annotate Y scale") for si := 0; si < count; si++ { secs := time.Duration(secsPerLabel * si * int(time.Second)) px := si * pxPerLabel var str string = "" if si == 0 { str = start.String() } else { point := start.Add(secs) str = point.Format("15:04:05") } // draw a guideline on the exact time for i := 0; i < 75; i++ { a.image.Set(i, px, image.White) } // draw the text, 3 px margin to the line pt := freetype.Pt(3, px-3) _, _ = a.context.DrawString(str, pt) } return nil }
// Write a text inside the image func WriteText(text string, f *truetype.Font, img *image.Paletted) { // Initialize the context. fg := image.Black c := freetype.NewContext() c.SetDPI(72) c.SetFont(f) c.SetFontSize(64) c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(fg) // Draw the text. pt := freetype.Pt(40, 120) c.DrawString(text, pt) }
func (ig *ImageGraphics) TextLen(s string, font chart.Font) int { c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) fontsize := ig.relFontsizeToPixel(font.Size) c.SetFontSize(fontsize) // really draw it width, err := c.DrawString(s, freetype.Pt(0, 0)) if err != nil { return 10 * len(s) // BUG } return int(width.X+32)>>6 + 1 }
func (a Annotator) annotate(upperText string, lowerText string) []byte { fontColor, _ := colorful.Hex("#000000") fontMask := image.NewUniform(fontColor) templateFile, _ := ioutil.ReadFile("./static/template.jpg") srcImage, _ := jpeg.Decode(bytes.NewBuffer(templateFile)) srcBounds := srcImage.Bounds() srcHeight := srcBounds.Max.Y imageMask := image.NewRGBA(srcBounds) imageMaskClip := imageMask.Bounds() draw.Draw(imageMask, imageMaskClip, srcImage, image.ZP, draw.Src) c := freetype.NewContext() c.SetFont(font) c.SetFontSize(60) c.SetDPI(60) c.SetSrc(fontMask) c.SetDst(imageMask) c.SetClip(imageMaskClip) drawLines := func(line string, point fixed.Point26_6) { c.DrawString(line, point) } upperPoint := freetype.Pt(10, 40) lowerPoint := freetype.Pt(10, srcHeight-10) drawLines(upperText, upperPoint) drawLines(lowerText, lowerPoint) dataBuffer := bytes.NewBuffer([]byte("")) jpeg.Encode(dataBuffer, imageMask, nil) return dataBuffer.Bytes() }
func main() { imgcounter := 123 imgfile, _ := os.Create(fmt.Sprintf("%03d.png", imgcounter)) defer imgfile.Close() img := image.NewNRGBA(image.Rect(0, 0, dx, dy)) for y := 0; y < dy; y++ { for x := 0; x < dx; x++ { img.Set(x, y, color.RGBA{uint8(x), uint8(y), 0, 255}) } } fontBytes, err := ioutil.ReadFile(fontFile) //读取字体数据 if err != nil { fmt.Println(err) return } font, err := freetype.ParseFont(fontBytes) if err != nil { fmt.Print(err) return } c := freetype.NewContext() c.SetDPI(fontDPI) c.SetFont(font) c.SetFontSize(fontSize) c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(image.White) pt := freetype.Pt(10, 10+int(c.PointToFixed(fontSize)>>8)) // 字出现的位置 _, err = c.DrawString("ABCDE", pt) if err != nil { fmt.Println(err) return } err = png.Encode(imgfile, img) if err != nil { fmt.Println(err) } }
func (t *Text) getMaxHeight() int { w, h := t.GetStringSize("|") bounds := image.Rect(0, 0, int(w>>6), int(h>>6)) img := image.NewRGBA(bounds) ctx := freetype.NewContext() ctx.SetFont(t.font) ctx.SetFontSize(t.fontSize) ctx.SetSrc(&image.Uniform{t.fillColor}) ctx.SetDst(img) ctx.SetClip(bounds) ctx.DrawString("|", freetype.Pt(0, int(t.fontSize))) var i = len(img.Pix) - 1 for ; img.Pix[i] == 0; i-- { } return (i / img.Stride) + 1 }
func (this *Signer) mark(text string) (image.Image, error) { fontBytes, err := ioutil.ReadFile(this.fontPath) if err != nil { fmt.Println(err) } font, err := freetype.ParseFont(fontBytes) if err != nil { fmt.Println(err) } //读取图片 file, err := os.Open(this.srcImage) if err != nil { fmt.Println(err) } defer file.Close() img, err := jpeg.Decode(file) if err != nil { fmt.Println(err) } bounds := img.Bounds() nrgba := image.NewNRGBA(bounds) draw.Draw(nrgba, img.Bounds(), img, image.ZP, draw.Over) c := freetype.NewContext() c.SetDPI(this.dpi) c.SetFont(font) c.SetDst(nrgba) c.SetFontSize(this.fontSize) c.SetClip(nrgba.Bounds()) c.SetSrc(image.White) pt := freetype.Pt(100, 100+int(c.PointToFixed(this.fontSize)>>8)) for _, s := range strings.Split(text, "\r\n") { _, err = c.DrawString(s, pt) pt.Y += c.PointToFixed(12 * 1.5) } return nrgba, nil }
func createTextImage(text string, fontSize int, color color.Color, f *truetype.Font) (*image.RGBA, float32, float32, error) { // 1 pt = 1/72 in, 72 dpi = 1 in const dpi = 72 fg, bg := image.NewUniform(color), image.Transparent c := freetype.NewContext() c.SetFont(f) c.SetDPI(dpi) c.SetFontSize(float64(fontSize)) // points c.SetSrc(fg) c.SetHinting(font.HintingFull) // 1. Figure out maximum height so all text lines are the same height. // 2. Draw within small bounds to figure out bounds. // 3. Draw within final bounds. scale := c.PointToFixed(float64(fontSize)) // point to pixels rect := f.Bounds(scale) // scale is pixels of 1 em maxHeight := int(rect.Max.Y>>6) - int(rect.Min.Y>>6) var rgba *image.RGBA w, h := 10, maxHeight for i := 0; i < 2; i++ { rgba = image.NewRGBA(image.Rect(0, 0, w, h)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c.SetClip(rgba.Bounds()) c.SetDst(rgba) pt := freetype.Pt(0, int(scale>>6)) end, err := c.DrawString(text, pt) if err != nil { return nil, 0, 0, err } w = int(end.X >> 6) } return rgba, float32(w), float32(h), nil }
func drawText(img *image.RGBA, font *truetype.Font, color color.Color, x, y int, s string) error { var ptSize float64 = 12 ctx := freetype.NewContext() ctx.SetDPI(72) ctx.SetFont(font) ctx.SetFontSize(ptSize) ctx.SetClip(img.Bounds()) ctx.SetDst(img) ctx.SetSrc(image.NewUniform(color)) ctx.SetHinting(img_font.HintingFull) width := int(widthOfString(font, ptSize, s)) pt := freetype.Pt(x-width/2, y+int(int32(ctx.PointToFixed(ptSize))>>8)/2) _, err := ctx.DrawString(s, pt) if err != nil { return err } return nil }
func TextToImage(text string, fontSize float64, fontFile string, fontColor color.Color) (image.Image, error) { lines := len(strings.Split(text, "\n")) maxLen := getMaxLen(text) margin := 10 width := maxLen*int(fontSize) + margin*2 height := int(fontSize)*lines + margin*2 var fontDPI float64 = 72 fontBytes, err := ioutil.ReadFile(fontFile) if err != nil { return nil, err } font, err := freetype.ParseFont(fontBytes) if err != nil { return nil, err } bg := image.Transparent newImg := image.NewRGBA(image.Rect(0, 0, width, height)) draw.Draw(newImg, newImg.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(fontDPI) c.SetFont(font) c.SetFontSize(fontSize) c.SetClip(newImg.Bounds()) c.SetDst(newImg) c.SetSrc(image.NewUniform(fontColor)) // Draw the text. for i, s := range strings.Split(text, "\n") { Y := int(fontSize) + i*int(fontSize) pt := freetype.Pt(margin, Y) _, err := c.DrawString(s, pt) if err != nil { return nil, err } } return newImg, nil }
func (a *Annotator) DrawXScale() error { log.WithFields(log.Fields{ "hzHigh": humanize.SI(a.table.HzHigh, "Hz"), "hzLow": humanize.SI(a.table.HzLow, "Hz"), }).Debug("annotate X scale") // how many samples? count := int(math.Floor(float64(a.table.Bins) / float64(350))) hzPerLabel := float64(a.table.HzHigh-a.table.HzLow) / float64(count) pxPerLabel := int(math.Floor(float64(a.table.Bins) / float64(count))) log.WithFields(log.Fields{ "labels": count, "hzPerLabel": humanize.SI(hzPerLabel, "Hz"), "pxPerLabel": pxPerLabel, }).Debug("annotate X scale") for si := 0; si < count; si++ { hz := a.table.HzLow + (float64(si) * hzPerLabel) px := si * pxPerLabel fract, suffix := humanize.ComputeSI(hz) str := fmt.Sprintf("%0.2f %sHz", fract, suffix) // draw a guideline on the exact frequency for i := 0; i < 30; i++ { a.image.Set(px, i, image.White) } // draw the text pt := freetype.Pt(px+5, 17) _, _ = a.context.DrawString(str, pt) } return nil }
func (font *Font) createTexture(text string, width int, height int, size float64, dpi float64, rgba color.Color) (uint32, int, int) { context := freetype.NewContext() context.SetFont(font.ttf) img := image.NewRGBA(image.Rect(0, 0, width, height)) r, g, b, _ := rgba.RGBA() draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{uint8(r), uint8(g), uint8(b), 0}), image.ZP, draw.Src) context.SetDst(img) context.SetClip(img.Bounds()) context.SetSrc(image.NewUniform(rgba)) context.SetFontSize(size) context.SetDPI(dpi) pixelBounds, _ := context.DrawString(text, freetype.Pt(0, height/2)) var tex uint32 gl.GenTextures(1, &tex) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, tex) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, tex) gl.TexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, int32(img.Rect.Size().X), int32(img.Rect.Size().Y), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(img.Pix)) return tex, int26_6Ceiling(pixelBounds.X + 0x3f), int26_6Ceiling(pixelBounds.Y + 0x3f) }
func drawBubble(img *image.Gray, xPos, yPos, width, height float64, content string, filled bool) { gapBeg := xPos + width/4.0 gapEnd := xPos + width - width/4.0 if filled { drawRect(img, black, xPos, yPos, width, height) return } ftContext.DrawString(content, freetype.Pt(int(gapBeg+width/6), int(yPos+height))) for w := xPos; w < xPos+width; w += 1.0 { if w >= gapBeg && w <= gapEnd { continue } img.SetGray(int(w), int(yPos), color.Gray{0x22}) img.SetGray(int(w), int(yPos+height), color.Gray{0x22}) } for h := yPos; h < yPos+height; h += 1.0 { img.SetGray(int(xPos), int(h), color.Gray{0x22}) img.SetGray(int(xPos+width), int(h), color.Gray{0x22}) } }
func createProfileImage(username string, userId string) ([]byte, *model.AppError) { colors := []color.NRGBA{ {197, 8, 126, 255}, {227, 207, 18, 255}, {28, 181, 105, 255}, {35, 188, 224, 255}, {116, 49, 196, 255}, {197, 8, 126, 255}, {197, 19, 19, 255}, {250, 134, 6, 255}, {227, 207, 18, 255}, {123, 201, 71, 255}, {28, 181, 105, 255}, {35, 188, 224, 255}, {116, 49, 196, 255}, {197, 8, 126, 255}, {197, 19, 19, 255}, {250, 134, 6, 255}, {227, 207, 18, 255}, {123, 201, 71, 255}, {28, 181, 105, 255}, {35, 188, 224, 255}, {116, 49, 196, 255}, {197, 8, 126, 255}, {197, 19, 19, 255}, {250, 134, 6, 255}, {227, 207, 18, 255}, {123, 201, 71, 255}, } h := fnv.New32a() h.Write([]byte(userId)) seed := h.Sum32() initial := string(strings.ToUpper(username)[0]) fontBytes, err := ioutil.ReadFile(utils.FindDir("web/static/fonts") + utils.Cfg.FileSettings.InitialFont) if err != nil { return nil, model.NewAppError("createProfileImage", "Could not create default profile image font", err.Error()) } font, err := freetype.ParseFont(fontBytes) if err != nil { return nil, model.NewAppError("createProfileImage", "Could not create default profile image font", err.Error()) } width := int(utils.Cfg.FileSettings.ProfileWidth) height := int(utils.Cfg.FileSettings.ProfileHeight) color := colors[int64(seed)%int64(len(colors))] dstImg := image.NewRGBA(image.Rect(0, 0, width, height)) srcImg := image.White draw.Draw(dstImg, dstImg.Bounds(), &image.Uniform{color}, image.ZP, draw.Src) size := float64((width + height) / 4) c := freetype.NewContext() c.SetFont(font) c.SetFontSize(size) c.SetClip(dstImg.Bounds()) c.SetDst(dstImg) c.SetSrc(srcImg) pt := freetype.Pt(width/6, height*2/3) _, err = c.DrawString(initial, pt) if err != nil { return nil, model.NewAppError("createProfileImage", "Could not add user initial to default profile picture", err.Error()) } buf := new(bytes.Buffer) if imgErr := png.Encode(buf, dstImg); imgErr != nil { return nil, model.NewAppError("createProfileImage", "Could not encode default profile image", imgErr.Error()) } else { return buf.Bytes(), nil } }
func transformCropAndResize(img image.Image, transformation *Transformation) (imgNew image.Image) { parameters := transformation.params width := parameters.width height := parameters.height gravity := parameters.gravity scale := parameters.scale imgWidth := img.Bounds().Dx() imgHeight := img.Bounds().Dy() // Scaling factor if parameters.cropping != CroppingModeKeepScale { width *= scale height *= scale } // Resize and crop switch parameters.cropping { case CroppingModeExact: imgNew = resize.Resize(uint(width), uint(height), img, resize.Bilinear) case CroppingModeAll: if float32(width)*(float32(imgHeight)/float32(imgWidth)) > float32(height) { // Keep height imgNew = resize.Resize(0, uint(height), img, resize.Bilinear) } else { // Keep width imgNew = resize.Resize(uint(width), 0, img, resize.Bilinear) } case CroppingModePart: var croppedRect image.Rectangle if float32(width)*(float32(imgHeight)/float32(imgWidth)) > float32(height) { // Whole width displayed newHeight := int((float32(imgWidth) / float32(width)) * float32(height)) croppedRect = image.Rect(0, 0, imgWidth, newHeight) } else { // Whole height displayed newWidth := int((float32(imgHeight) / float32(height)) * float32(width)) croppedRect = image.Rect(0, 0, newWidth, imgHeight) } topLeftPoint := calculateTopLeftPointFromGravity(gravity, croppedRect.Dx(), croppedRect.Dy(), imgWidth, imgHeight) imgDraw := image.NewRGBA(croppedRect) draw.Draw(imgDraw, croppedRect, img, topLeftPoint, draw.Src) imgNew = resize.Resize(uint(width), uint(height), imgDraw, resize.Bilinear) case CroppingModeKeepScale: // If passed in dimensions are bigger use those of the image if width > imgWidth { width = imgWidth } if height > imgHeight { height = imgHeight } croppedRect := image.Rect(0, 0, width, height) topLeftPoint := calculateTopLeftPointFromGravity(gravity, width, height, imgWidth, imgHeight) imgDraw := image.NewRGBA(croppedRect) draw.Draw(imgDraw, croppedRect, img, topLeftPoint, draw.Src) imgNew = imgDraw.SubImage(croppedRect) } // Filters if parameters.filter == FilterGrayScale { bounds := imgNew.Bounds() w, h := bounds.Max.X, bounds.Max.Y gray := image.NewGray(bounds) for x := 0; x < w; x++ { for y := 0; y < h; y++ { oldColor := imgNew.At(x, y) grayColor := color.GrayModel.Convert(oldColor) gray.Set(x, y, grayColor) } } imgNew = gray } if transformation.watermark != nil { w := transformation.watermark var watermarkSrcScaled image.Image var watermarkBounds image.Rectangle // Try to load a scaled watermark first if scale > 1 { scaledPath, err := constructScaledPath(w.imagePath, scale) if err != nil { log.Println("Error:", err) return } watermarkSrc, _, err := loadImage(scaledPath) if err != nil { log.Println("Error: could not load a watermark", err) } else { watermarkBounds = watermarkSrc.Bounds() watermarkSrcScaled = watermarkSrc } } if watermarkSrcScaled == nil { watermarkSrc, _, err := loadImage(w.imagePath) if err != nil { log.Println("Error: could not load a watermark", err) return } watermarkBounds = image.Rect(0, 0, watermarkSrc.Bounds().Max.X*scale, watermarkSrc.Bounds().Max.Y*scale) watermarkSrcScaled = resize.Resize(uint(watermarkBounds.Max.X), uint(watermarkBounds.Max.Y), watermarkSrc, resize.Bilinear) } bounds := imgNew.Bounds() // Make sure we have a transparent watermark if possible watermark := image.NewRGBA(watermarkBounds) draw.Draw(watermark, watermarkBounds, watermarkSrcScaled, watermarkBounds.Min, draw.Src) pt := calculateTopLeftPointFromGravity(w.gravity, watermarkBounds.Dx(), watermarkBounds.Dy(), bounds.Dx(), bounds.Dy()) pt = pt.Add(getTranslation(w.gravity, w.x*scale, w.y*scale)) wX := pt.X wY := pt.Y watermarkRect := image.Rect(wX, wY, watermarkBounds.Dx()+wX, watermarkBounds.Dy()+wY) finalImage := image.NewRGBA(bounds) draw.Draw(finalImage, bounds, imgNew, bounds.Min, draw.Src) draw.Draw(finalImage, watermarkRect, watermark, watermarkBounds.Min, draw.Over) imgNew = finalImage.SubImage(bounds) } if transformation.texts != nil { bounds := imgNew.Bounds() rgba := image.NewRGBA(bounds) draw.Draw(rgba, bounds, imgNew, image.ZP, draw.Src) dpi := float64(72) // Multiply this by scale for a baaad time c := freetype.NewContext() c.SetDPI(dpi) c.SetClip(rgba.Bounds()) c.SetDst(rgba) for _, text := range transformation.texts { size := float64(text.size * scale) c.SetSrc(image.NewUniform(text.color)) c.SetFont(text.font) c.SetFontSize(size) fontMetrics := text.getFontMetrics(scale) width := int(c.PointToFix32(fontMetrics.width) >> 8) height := int(c.PointToFix32(fontMetrics.height) >> 8) pt := calculateTopLeftPointFromGravity(text.gravity, width, height, bounds.Dx(), bounds.Dy()) pt = pt.Add(getTranslation(text.gravity, text.x*scale, text.y*scale)) x := pt.X y := pt.Y + int(c.PointToFix32(fontMetrics.ascent)>>8) _, err := c.DrawString(text.content, freetype.Pt(x, y)) if err != nil { log.Println("Error adding text:", err) return } } imgNew = rgba } return }
func main() { rightFile, err := os.Open("p1.jpg") if err != nil { panic(err) } rightPortrait, err := jpeg.Decode(rightFile) if err != nil { panic(err) } leftFile, err := os.Open("p2.jpg") if err != nil { panic(err) } leftPortrait, err := jpeg.Decode(leftFile) if err != nil { panic(err) } rightImage := resize.Resize(400, 600, rightPortrait, resize.Bilinear) leftImage := resize.Resize(400, 600, leftPortrait, resize.Bilinear) t, err := os.Open("template.png") if err != nil { panic(err) } mask, err := png.Decode(t) if err != nil { panic(err) } newImage := image.NewRGBA(rightImage.Bounds()) draw.Draw(newImage, rightImage.Bounds(), rightImage, image.ZP, draw.Src) draw.DrawMask(newImage, leftImage.Bounds(), leftImage, image.ZP, mask, image.ZP, draw.Over) ctx := freetype.NewContext() ctx.SetFont(strokeFont) ctx.SetFontSize(84) ctx.SetSrc(image.Black) ctx.SetDst(newImage) ctx.SetClip(newImage.Bounds()) _, err = ctx.DrawString("TOGETHER", freetype.Pt(40, 200)) if err != nil { panic(err) } ctx.SetFont(posterFont) ctx.SetFontSize(12) ctx.SetSrc(image.White) ctx.SetDst(newImage) ctx.SetClip(newImage.Bounds()) _, err = ctx.DrawString("#VOTETOGETHER", freetype.Pt(150, 580)) if err != nil { panic(err) } f, err := os.Create("newimage.png") if err != nil { panic(err) } defer f.Close() err = png.Encode(f, newImage) if err != nil { panic(err) } }
func tryLoadFont(fontFilePath string) (Font, error) { defer tlog.FuncLog(tlog.Func("LoadFont")) var data []byte { fd, err := os.Open(fontFilePath) if err != nil { return Font{}, err } defer fd.Close() data, err = ioutil.ReadAll(fd) if err != nil { return Font{}, err } } texsdfpath := filepath.Join(os.TempDir(), filepath.Base(fontFilePath)+".sdf") texsdf, err := LoadPng(texsdfpath) sdfLoaded := err == nil if err != nil { texsdf = image.NewGray(image.Rect(0, 0, texSize, texSize)) } name := filepath.Base(fontFilePath) name = name[:len(name)-len(filepath.Ext(name))] var f = Font{ SdfTex: texsdf, Glyphs: make([]Glyph, int(highRune-lowRune+1)), FirstRune: lowRune, Name: name, Height: 0, Leading: 0, } { // Read the truetype font. ttf, err := truetype.Parse(data) if err != nil { return Font{}, err } var baseline = 3 * sdfSize / 4 var targetGlyphExtentPxs = float64(sdfSize) * 3.0 / 4.0 var fontHeight float64 // maximum height, in renormalized EMs var renormalizeEM float64 // (real max glyph size / em) { // the real max glyph extent in EMs var maxGlyphExtentEMs float64 { var max fixed.Int26_6 // = 0; max extent(height or width) of a glyph in FontUnits var height fixed.Int26_6 // = 0; max height of a glyph in FontUnits { scale := fixed.I(int(ttf.FUnitsPerEm())) b := ttf.Bounds(scale) max = b.Max.X - b.Min.X height = b.Max.Y - b.Min.Y if max < height { max = height } for ch := lowRune; ch <= highRune; ch++ { hmetric := ttf.HMetric(scale, ttf.Index(ch)) vmetric := ttf.VMetric(scale, ttf.Index(ch)) if max < hmetric.AdvanceWidth { max = hmetric.AdvanceWidth } if height < vmetric.AdvanceHeight { height = vmetric.AdvanceHeight } if max < height { max = height } } } maxGlyphExtentEMs = float64(max) / float64(ttf.FUnitsPerEm()) fontHeight = float64(height) / float64(ttf.FUnitsPerEm()) } renormalizeEM = 1 / maxGlyphExtentEMs fontHeight *= renormalizeEM } f.Height = em(fontHeight) f.Leading = em(leadingFactor * fontHeight) scale := fixed.I(int(ttf.FUnitsPerEm())) graphicIdx := 0 for ch := lowRune; ch <= highRune; ch++ { // fmt.Printf("%c", ch) idx := int(ch - lowRune) var aw float64 { hmetric := ttf.HMetric(scale, ttf.Index(ch)) aw = float64(hmetric.AdvanceWidth) / float64(ttf.FUnitsPerEm()) * renormalizeEM f.Glyphs[idx].AdvanceWidth = em(aw) } if !unicode.IsGraphic(ch) || unicode.IsSpace(ch) { f.Glyphs[idx].Cell = image.ZR continue } x0 := cellSize * (graphicIdx % texNCells) y0 := cellSize * (graphicIdx / texNCells) graphicIdx++ f.Glyphs[idx].Cell = image.Rect(x0, y0, x0+cellSize, y0+cellSize) sdfTargetWidth := targetGlyphExtentPxs * aw sdfTargetHeight := targetGlyphExtentPxs * fontHeight if !sdfLoaded { img := image.NewGray(image.Rect(0, 0, sdfSize, sdfSize)) c := freetype.NewContext() c.SetFont(ttf) c.SetDPI(72) // so that one Pt == one Pixel c.SetFontSize(targetGlyphExtentPxs * renormalizeEM) // how many Pt the max glyph has c.SetClip(img.Bounds()) c.SetDst(img) c.SetSrc(image.White) sdfX := (sdfSize - int(sdfTargetWidth)) / 2 c.DrawString(string(ch), freetype.Pt(sdfX, baseline)) sdfize(img) scaleDownTo(f.SdfTex, f.Glyphs[idx].Cell, img) } dx := (sdfSize - int(sdfTargetWidth)) / 2 * cellSize / sdfSize cellHeight := sdfTargetHeight * float64(cellSize) / float64(sdfSize) dy := (cellSize - int(cellHeight)) / 4 f.Glyphs[idx].Cell = image.Rect(x0+dx, y0+3*dy, x0+cellSize-dx, y0+cellSize-dy) // drawRect(f.SdfTex, f.Glyphs[idx].Cell, color.Gray{255}) } } if !sdfLoaded { SavePng(texsdfpath, f.SdfTex) tlog.Println("sdf ", texsdfpath, " saved") } // ShowImage(f.SdfTex) tlog.Println(fontFilePath, " loaded") return f, nil }
func makeImage(req *http.Request, caption, font string, pt, size, border, scale int, f func(x, y int) uint32) *image.RGBA { d := (size + 2*border) * scale csize := 0 if caption != "" { if pt == 0 { pt = 11 } csize = pt * 2 } c := image.NewRGBA(image.Rect(0, 0, d, d+csize)) // white u := &image.Uniform{C: color.White} draw.Draw(c, c.Bounds(), u, image.ZP, draw.Src) for y := 0; y < size; y++ { for x := 0; x < size; x++ { r := image.Rect((x+border)*scale, (y+border)*scale, (x+border+1)*scale, (y+border+1)*scale) rgba := f(x, y) u.C = color.RGBA{byte(rgba >> 24), byte(rgba >> 16), byte(rgba >> 8), byte(rgba)} draw.Draw(c, r, u, image.ZP, draw.Src) } } if csize != 0 { if font == "" { font = "data/luxisr.ttf" } ctxt := fs.NewContext(req) dat, _, err := ctxt.Read(font) if err != nil { panic(err) } tfont, err := freetype.ParseFont(dat) if err != nil { panic(err) } ft := freetype.NewContext() ft.SetDst(c) ft.SetDPI(100) ft.SetFont(tfont) ft.SetFontSize(float64(pt)) ft.SetSrc(image.NewUniform(color.Black)) ft.SetClip(image.Rect(0, 0, 0, 0)) wid, err := ft.DrawString(caption, freetype.Pt(0, 0)) if err != nil { panic(err) } p := freetype.Pt(d, d+3*pt/2) p.X -= wid.X p.X /= 2 ft.SetClip(c.Bounds()) ft.DrawString(caption, p) } return c }
func (font *Font) updateTexture(texture uint32, text string, width int, height int, size float64, dpi float64, rgba color.Color) (int, int) { context := freetype.NewContext() context.SetFont(font.ttf) img := image.NewRGBA(image.Rect(0, 0, width, height)) r, g, b, _ := rgba.RGBA() draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{uint8(r), uint8(g), uint8(b), 0}), image.ZP, draw.Src) context.SetDst(img) context.SetClip(img.Bounds()) context.SetSrc(image.NewUniform(rgba)) context.SetFontSize(size) context.SetDPI(dpi) pixelBounds, _ := context.DrawString(text, freetype.Pt(0, height/2)) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, texture) gl.TexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, int32(img.Rect.Size().X), int32(img.Rect.Size().Y), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(img.Pix)) return int26_6Ceiling(pixelBounds.X + 0x3f), int26_6Ceiling(pixelBounds.Y + 0x3f) }