// Scale will scale the image to the size provided. // Note that this will destroy the current pixmap associated with this image. // After scaling, XSurfaceSet will need to be called for each window that // this image is painted to. (And obviously, XDraw and XPaint will need to // be called again.) func (im *Image) Scale(width, height int) *Image { dimg := New(im.X, image.Rect(0, 0, width, height)) graphics.Scale(dimg, im) im.Destroy() return dimg }
// Smart crop given image file & write it to io.Writer func smartCrop(w io.Writer, r io.Reader, size []int) error { img, mimetype, err := image.Decode(r) if size == nil || err != nil { io.Copy(w, r) return nil } size = setMaxSize(fitToActualSize(&img, size)) crop, err := smartcrop.SmartCrop(&img, size[0], size[1]) if err != nil { io.Copy(w, r) return nil } croppedBuffer := image.NewRGBA(image.Rect(0, 0, crop.Width, crop.Height)) draw.Draw( croppedBuffer, croppedBuffer.Bounds(), img, image.Point{crop.X, crop.Y}, draw.Src, ) dst := image.NewRGBA(image.Rect(0, 0, size[0], size[1])) graphics.Scale(dst, croppedBuffer) return writeByMimetype(w, dst, mimetype) }
//缩放图片,proportion为比例 func reszieImage(imageName string, minWidth float32, minHeight float32) { src, err := LoadImage(imageName) if err != nil { log.Fatal(err) } info := src.Bounds() width := info.Dx() //图片宽度 height := info.Dy() //图片高度 var ( newWidth, newHeight float32 ) if float32(width)/float32(height) > minWidth/minHeight { newHeight = minHeight newWidth = float32(width) * minHeight / float32(height) } else { newWidth = minWidth newHeight = (float32(height) * minWidth) / float32(width) } // 缩略图的大小 dst := image.NewRGBA(image.Rect(0, 0, int(newWidth), int(newHeight))) // 产生缩略图,等比例缩放 err = graphics.Scale(dst, src) if err != nil { log.Fatal(err) } // 需要保存的文件 imgcounter := 734 saveImage(fmt.Sprintf("%03d.jpg", imgcounter), dst) }
func ResizeWidth(img image.Image, width int) (image.Image, error) { s := img.Bounds().Size() h := int((float32(width) / float32(s.X)) * float32(s.Y)) r := image.NewRGBA(image.Rect(0, 0, width, h)) if err := graphics.Scale(r, img); err != nil { return nil, err } return r, nil }
func load_likelost_img(json_str string) (err error) { //load json obj obj, err := JsonToLikeLostChild(json_str) //con sig_con.FontSize = 11.5 sig_bd.FontSize = 11.5 color_con := image.NewUniform(color.NRGBA{88, 88, 88, 255}) //find time img_ft_l, err = sig_bd.GetSimpalImage("发现时间:", color_con, 2, 2) //describe img_desc_l, err = sig_bd.GetSimpalImage("特征描述:", color_con, 2, 2) //find address img_fa_l, err = sig_bd.GetSimpalImage("发现地点:", color_con, 2, 2) //find time right img_ft_r, err = sig_con.GetMoreLineImage(obj.FindTime, color_con, 304, 2, 2) img_desc_r, err = sig_con.GetMoreLineImage(obj.Describe, color_con, 304, 2, 2) img_fa_r, err = sig_con.GetMoreLineImage(obj.FindAddress, color_con, 304, 2, 2) //map gpsx := strconv.FormatFloat(obj.FindGPSX, 'f', -1, 64) //gpsx_off := strconv.FormatFloat(obj.FindGPSX-0.03, 'f', -1, 64) //gpsy_off := strconv.FormatFloat(obj.FindGPSY-0.005, 'f', -1, 64) gpsy := strconv.FormatFloat(obj.FindGPSY, 'f', -1, 64) add := obj.FindAddress if len(obj.FindAddress) > 16 { add_rune := []rune(obj.FindAddress) add = string(add_rune[0:12]) + "..." } map_url := "http://api.map.baidu.com/staticimage?center=" + gpsx + "," + gpsy + "&width=414&height=222&zoom=13©right=1" + "&labels=" + gpsx + "," + gpsy + "&labelStyles=" + url.QueryEscape(add) + ",1,14,0x585858,0xffffff,0" baidu_map, err = GetImg(map_url) m_x, m_y := align(baidu_map.Bounds(), masker_img.Bounds()) img_baidu_map = image.NewNRGBA(baidu_map.Bounds()) draw.Draw(img_baidu_map, baidu_map.Bounds(), baidu_map, image.ZP, draw.Over) //masker_img, err = GetStaticImg("mask") draw.Draw(img_baidu_map, offset(baidu_map.Bounds(), m_x, m_y-20), masker_img, image.ZP, draw.Over) //child pic list length := len(obj.PicList) imglist = make([]image.Image, length, length) for i, chilpic := range obj.PicList { img_src, err_childlist := GetImg(chilpic.PicUrl) err = err_childlist bound := img_src.Bounds() dx := bound.Dx() dy := bound.Dy() dst := image.NewRGBA(image.Rect(0, 0, 414, 414*dy/dx)) err = graphics.Scale(dst, img_src) imglist[i] = dst } return }
func (xdg *XDG) scaleIcon(srcImg image.Image, name string, size int) image.Image { img := image.NewRGBA(image.Rect(0, 0, size, size)) err := graphics.Scale(img, srcImg) if err != nil { fmt.Printf("Failed to scale: %s\n", err.Error()) return nil } xdg.icons[Icon{name, size}] = img return img }
func (en *JKEncoderImage) JK_reducejpeg(save, name string, enType draw.Op, quality int) error { // 1. Open file ifile, err := os.Open(name) if err != nil { return err } defer ifile.Close() // Create file to save ofile, err := os.Create(save) if err != nil { return err } defer ofile.Close() /* config, err := jpeg.DecodeConfig(ifile) if err != nil { jklog.L().Errorln("error : ", err) } jklog.L().Infof("[%d, %d]\n", config.Width, config.Height) */ img, err := jpeg.Decode(ifile) if err != nil { jklog.L().Errorln("error : ", err) return err } bounds := img.Bounds() x := bounds.Dx() y := bounds.Dy() nx := x * en.Scale / 100 ny := y * en.Scale / 100 m := image.NewRGBA(image.Rect(0, 0, x, y)) jklog.L().Infof("[%d, %d] \n", x, y) // white := color.RGBA{255, 255, 255, 255} // draw.Draw(m, bounds, &image.Uniform{white}, image.ZP, draw.Src) // draw.Draw(m, bounds, img, image.ZP, draw.Src) draw.Draw(m, m.Bounds(), img, bounds.Min, enType) mm := image.NewRGBA(image.Rect(0, 0, nx, ny)) graphics.Scale(mm, m) err = jpeg.Encode(ofile, mm, &jpeg.Options{quality}) if err != nil { jklog.L().Errorln("error: ", err) return err } return nil }
func main() { defer Recovery() X, Xerr = xgbutil.Dial("") if Xerr != nil { panic(Xerr) } simg, err := xgraphics.LoadPngFromFile("openbox.png") if err != nil { fmt.Println(err) } img := image.NewRGBA(image.Rect(0, 0, 50, 101)) graphics.Scale(img, simg) dest := xgraphics.BlendBg(img, nil, 100, color.RGBA{255, 255, 255, 255}) win := xgraphics.CreateImageWindow(X, dest, 3940, 400) X.Conn().MapWindow(win) time.Sleep(20 * time.Second) }
func main() { flag.Parse() args := flag.Args() if flag.NArg() != 4 { errMsg("Usage: scale-png src-png new_width new_height dest-png") } pngsrc := args[0] pngdest := args[3] neww, errw := strconv.Atoi(args[1]) newh, errh := strconv.Atoi(args[2]) if errw != nil || errh != nil { errMsg("Could not convert (%s, %s) to integers.", args[1], args[2]) } fmt.Printf("Resizing %s to (%d, %d) and saving as %s\n", pngsrc, neww, newh, pngdest) srcReader, err := os.Open(pngsrc) if err != nil { errMsg("%s is not readable.", pngsrc) } srcImg, err := png.Decode(srcReader) if err != nil { errMsg("Could not decode %s.", pngsrc) } destWriter, err := os.Create(pngdest) if err != nil { errMsg("Could not write %s", pngdest) } destImg := image.NewRGBA(image.Rect(0, 0, neww, newh)) graphics.Scale(destImg, srcImg) // for x := 0; x < destImg.Bounds().Max.X; x++ { // for y := 0; y < destImg.Bounds().Max.Y; y++ { // c := destImg.At(x, y).(color.RGBA) // blah := 0.3 * 0xff // c.A = uint8(blah) // destImg.SetRGBA(x, y, c) // } // } // finalDest := image.NewRGBA(image.Rect(0, 0, neww, newh)) // blue := color.RGBA{255, 255, 255, 255} // draw.Draw(finalDest, finalDest.Bounds(), image.NewUniform(blue), // image.ZP, draw.Src) // Create a transparency mask mask := image.NewUniform(color.Alpha16{32767}) // Now blend our scaled image draw.DrawMask(destImg, destImg.Bounds(), destImg, image.ZP, mask, image.ZP, draw.Src) png.Encode(destWriter, destImg) fmt.Printf("Type of src: %T\n", srcImg) fmt.Printf("Source opaque? %v\n", srcImg.(*image.RGBA).Opaque()) fmt.Printf("Destination opaque? %v\n", destImg.Opaque()) }
func load_losted_img(jsonstr string) (err error) { lostedobj, err := JsonToLostedChild(jsonstr) //map gpsx := strconv.FormatFloat(lostedobj.LostGPSX, 'f', -1, 64) gpsy := strconv.FormatFloat(lostedobj.LostGPSY, 'f', -1, 64) add := lostedobj.LostAddress if len(lostedobj.LostAddress) > 16 { add_rune := []rune(lostedobj.LostAddress) add = string(add_rune[0:12]) + "..." } map_url := "http://api.map.baidu.com/staticimage?center=" + gpsx + "," + gpsy + "&width=414&height=165&zoom=13©right=1" + "&labels=" + gpsx + "," + gpsy + "&labelStyles=" + url.QueryEscape(add) + ",1,14,0x585858,0xffffff,0" baidu_map, err := GetImg(map_url) m_x, m_y := align(baidu_map.Bounds(), masker_img.Bounds()) img_baidu_map = image.NewNRGBA(baidu_map.Bounds()) draw.Draw(img_baidu_map, baidu_map.Bounds(), baidu_map, image.ZP, draw.Over) draw.Draw(img_baidu_map, offset(baidu_map.Bounds(), m_x, m_y-20), masker_img, image.ZP, draw.Over) head_pic, err := GetImg(lostedobj.FirstFacePic.PicUrl) head_smal = image.NewNRGBA(image.Rect(0, 0, 83, 83)) err = graphics.Scale(head_smal, head_pic) head_circle = image.NewNRGBA(image.Rect(0, 0, 83, 83)) draw.DrawMask(head_circle, head_circle.Bounds(), head_smal, image.ZP, &circle{image.Point{41, 41}, 41}, image.ZP, draw.Over) //find time sig_bd.FontSize = 13 //lost height name, err = sig_bd.GetSimpalImage(lostedobj.BabyName, color_tbk, 2, 2) sig_bd.FontSize = 11.5 sig_con.FontSize = 10 sex_age, err = sig_con.GetSimpalImage(lostedobj.Sex+" "+lostedobj.Age, color_con, 2, 2) sig_con.FontSize = 11.5 img_lh_l, err = sig_bd.GetSimpalImage("走失时身高:", color_con, 2, 2) img_lt_l, err = sig_bd.GetSimpalImage("走失时间:", color_con, 2, 2) img_la_l, err = sig_bd.GetSimpalImage("走失地点:", color_con, 2, 2) //describe img_desc_l, err = sig_bd.GetSimpalImage("特征描述:", color_con, 2, 2) // current address img_ca_l, err = sig_bd.GetSimpalImage("现居地:", color_con, 2, 2) //contact img_contact_l, err = sig_bd.GetSimpalImage("联系人:", color_con, 2, 2) //phone img_phone_l, err = sig_bd.GetSimpalImage("联系电话:", color_con, 2, 2) //lost height right img_lh_r, err = sig_con.GetMoreLineImage(lostedobj.Height, color_con, 288, 2, 2) img_lt_r, err = sig_con.GetMoreLineImage(lostedobj.LostTime, color_con, 304, 2, 2) img_la_r, err = sig_con.GetMoreLineImage(lostedobj.LostAddress, color_con, 304, 2, 2) img_desc_r, err = sig_con.GetMoreLineImage(lostedobj.Describe, color_con, 304, 2, 2) img_ca_r, err = sig_con.GetMoreLineImage(lostedobj.Address, color_con, 320, 2, 2) img_contact_r, err = sig_con.GetMoreLineImage(lostedobj.Contacts, color_con, 320, 2, 2) img_phone_r, err = sig_con.GetMoreLineImage(lostedobj.TelNum, color_con, 304, 2, 2) length := len(lostedobj.OriPicUrlList) imglist = make([]image.Image, length, length) for i, chilpic := range lostedobj.OriPicUrlList { img_src, errr := GetImg(chilpic.PicUrl) err = errr bound := img_src.Bounds() dx := bound.Dx() dy := bound.Dy() dst := image.NewRGBA(image.Rect(0, 0, 414, 414*dy/dx)) err = graphics.Scale(dst, img_src) imglist[i] = dst } return }
func main() { fmt.Println(time.Now()) obj, _ := JsonToObj("") //title text sig_bd := signer.NewSigner("./msyhbd.ttf") sig_bd.FontSize = 14 white := image.NewUniform(color.NRGBA{255, 255, 255, 255}) color_tbk := image.NewUniform(color.NRGBA{78, 187, 109, 255}) //color_trans := color.NRGBA{0, 0, 0, 0} img_title_text, _ := sig_bd.GetSimpalImage("睿介寻子", white, color_tbk, 3, 3) //title back top_back_r := image.Rect(0, 0, 414, 57) img_tbk := image.NewNRGBA(top_back_r) // sum and align draw.Draw(img_tbk, img_tbk.Bounds(), color_tbk, image.ZP, draw.Src) x, y := align(top_back_r, img_title_text.Bounds()) draw.Draw(img_tbk, offset(img_title_text.Bounds(), x, y-3), img_title_text, image.Point{0, 3}, draw.Src) //con sig_con := signer.NewSigner("./msyh.ttf") sig_con.FontSize = 11.5 color_con := image.NewUniform(color.NRGBA{88, 88, 88, 255}) //find time sig_bd.FontSize = 11.5 img_ft_l, _ := sig_bd.GetSimpalImage("发现时间:", color_con, white, 2, 2) //describe img_desc_l, _ := sig_bd.GetSimpalImage("特征描述:", color_con, white, 2, 2) //find address img_fa_l, _ := sig_bd.GetSimpalImage("发现地点:", color_con, white, 2, 2) //find time right img_ft_r, _ := sig_con.GetMoreLineImage(obj.FindTime, color_con, white, 304, 2, 2) img_desc_r, _ := sig_con.GetMoreLineImage(obj.Describe, color_con, white, 304, 2, 2) img_fa_r, _ := sig_con.GetMoreLineImage(obj.FindAddress, color_con, white, 304, 2, 2) //map //http://api.map.baidu.com/staticimage?center=113.649644,34.75661&width=414&height=222&zoom=11 gpsx := strconv.FormatFloat(obj.FindGPSX, 'f', -1, 64) //gpsx_off := strconv.FormatFloat(obj.FindGPSX-0.03, 'f', -1, 64) //gpsy_off := strconv.FormatFloat(obj.FindGPSY-0.005, 'f', -1, 64) gpsy := strconv.FormatFloat(obj.FindGPSY, 'f', -1, 64) add := obj.FindAddress if len(obj.FindAddress) > 16 { add_rune := []rune(obj.FindAddress) add = string(add_rune[0:12]) + "..." } map_url := "http://api.map.baidu.com/staticimage?center=" + gpsx + "," + gpsy + "&width=414&height=222&zoom=13©right=1" + "&labels=" + gpsx + "," + gpsy + "&labelStyles=" + url.QueryEscape(add) + ",1,12,0x585858,0xffffff,0" fmt.Println(map_url) baidu_map, _ := GetImg(map_url) //masker_img, _ := GetImg("http://7xl130.com1.z0.glb.clouddn.com/mask.png") masker, _ := os.Open("./mask.png") masker_img, _ := png.Decode(masker) m_x, m_y := align(baidu_map.Bounds(), masker_img.Bounds()) fmt.Println(m_x, m_y) img_baidu_map := image.NewNRGBA(baidu_map.Bounds()) draw.Draw(img_baidu_map, baidu_map.Bounds(), baidu_map, image.ZP, draw.Src) draw.Draw(img_baidu_map, offset(baidu_map.Bounds(), m_x, m_y-20), masker_img, image.ZP, draw.Over) length := len(obj.PicUrlList) imglist := make([]image.Image, length, length) for i, chilpic := range obj.PicUrlList { fmt.Println(time.Now()) img_src, _ := GetImg(chilpic.PicUrl) fmt.Println(time.Now()) bound := img_src.Bounds() dx := bound.Dx() dy := bound.Dy() dst := image.NewRGBA(image.Rect(0, 0, 414, 414*dy/dx)) err := graphics.Scale(dst, img_src) fmt.Println(time.Now()) if err != nil { fmt.Println("Scale Image failed") } imglist[i] = dst } //img_bottom, _ := GetImg("http://7xl130.com1.z0.glb.clouddn.com/bottom.png") bottom, _ := os.Open("./bottom.png") img_bottom, _ := png.Decode(bottom) img_h := 0 img_h += 57 //top img_h += imglist[0].Bounds().Dy() //the head baby image img_h += 22 //text top img_h += 20 //text middle img_h += 18 //text bottom img_h += 222 //map height img_h += 23 ///map bottom for i := 1; i < len(imglist); i++ { //image height img_h += imglist[i].Bounds().Dy() img_h += 12 } img_h -= 12 img_h += 315 //qr code and logo img_h += img_ft_r.Bounds().Dy() //find time height img_h += img_desc_r.Bounds().Dy() //desc height img_h += img_fa_r.Bounds().Dy() //find address height //create result image result_r := image.Rect(0, 0, 414, img_h) result_img := image.NewNRGBA(result_r) draw.Draw(result_img, result_r, white, image.ZP, draw.Src) offset_height := 0 //draw top draw.Draw(result_img, top_back_r, img_tbk, image.ZP, draw.Src) //draw top offset_height += 57 //draw first child image draw.Draw(result_img, offset(imglist[0].Bounds(), 0, offset_height), imglist[0], image.ZP, draw.Src) offset_height += imglist[0].Bounds().Dy() offset_height += 22 //draw find time draw.Draw(result_img, offset(img_ft_l.Bounds(), 4, offset_height), img_ft_l, image.Point{0, 2}, draw.Src) draw.Draw(result_img, offset(img_ft_r.Bounds(), 90, offset_height+3), img_ft_r, image.Point{0, 2}, draw.Src) offset_height += img_ft_r.Bounds().Dy() offset_height += 10 //draw find desc draw.Draw(result_img, offset(img_desc_l.Bounds(), 4, offset_height), img_desc_l, image.Point{0, 2}, draw.Src) draw.Draw(result_img, offset(img_desc_r.Bounds(), 90, offset_height+3), img_desc_r, image.Point{0, 2}, draw.Src) offset_height += img_desc_r.Bounds().Dy() offset_height += 10 //draw find address draw.Draw(result_img, offset(img_fa_l.Bounds(), 4, offset_height), img_fa_l, image.Point{0, 2}, draw.Src) draw.Draw(result_img, offset(img_fa_r.Bounds(), 90, offset_height+3), img_fa_r, image.Point{0, 2}, draw.Src) offset_height += img_fa_r.Bounds().Dy() offset_height += 18 //draw map draw.Draw(result_img, offset(img_baidu_map.Bounds(), 0, offset_height), img_baidu_map, image.ZP, draw.Src) offset_height += img_baidu_map.Bounds().Dy() offset_height += 23 //draw child pic for i := 1; i < len(imglist); i++ { //image height draw.Draw(result_img, offset(imglist[i].Bounds(), 0, offset_height), imglist[i], image.ZP, draw.Src) offset_height += imglist[i].Bounds().Dy() offset_height += 12 } img_h -= 12 //draw qrcode and logo draw.Draw(result_img, offset(img_bottom.Bounds(), 0, offset_height), img_bottom, image.ZP, draw.Src) f, _ := os.Create("./test.png") defer f.Close() png.Encode(f, result_img) fmt.Println(time.Now()) /* resp, err := http.Get("http://7xl130.com1.z0.glb.clouddn.com/back.png") if err != nil { fmt.Println("Error:" + err.Error()) } else { //length, _ := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 0) content_type := resp.Header.Get("Content-Type") switch strings.TrimPrefix(content_type, "image/") { case "png": img, _ := png.Decode(resp.Body) text := fmt.Println(img.ColorModel()) } } */ }
// Scale is a simple wrapper around graphics.Scale. func Scale(img image.Image, width, height int) draw.Image { dimg := image.NewRGBA(image.Rect(0, 0, width, height)) graphics.Scale(dimg, img) return dimg }
// Converts image to text version func convertImage(img image.Image, settings map[string]interface{}) (result []byte, err error) { // Set up parameters var p parameters p = defaults() if v, ok := settings["bgcolor"].(string); ok && len(v) > 0 { p.bgcolor = v } if v, ok := settings["browser"].(string); ok && len(v) > 0 { p.browser = v } if v, ok := settings["characters"].(string); ok && len(v) > 0 { p.characters = v } if v, ok := settings["contrast"].(string); ok && len(v) > 0 { p.contrast, _ = strconv.Atoi(v) } if v, ok := settings["fontsize"].(string); ok && len(v) > 0 { p.fontsize = v } if v, ok := settings["grayscale"].(string); ok && len(v) > 0 { p.grayscale, _ = strconv.Atoi(v) } if v, ok := settings["textType"].(string); ok && len(v) > 0 { p.texttype = v } if v, ok := settings["width"].(string); ok && len(v) > 0 { p.width, _ = strconv.Atoi(v) if p.width < 1 || p.width > 500 { p.width = 100 } } // Rescale proportions to make output prettier in text height := int(float32(p.width) / (float32(img.Bounds().Dx()) / float32(img.Bounds().Dy()))) if p.browser == "ie" { height = height * 65 / 100 } else { height = height * 43 / 100 } // Produce minified image to work with start := time.Now() var m *image.RGBA if p.width < img.Bounds().Dx() && p.width >= 150 && (img.Bounds().Dx()*img.Bounds().Dy()/p.width) < 5000 { temp, err := resize(img, p.width, height) if err != nil { return result, err } m = temp.(*image.RGBA) } else { m = image.NewRGBA(image.Rect(0, 0, p.width, height)) graphics.Scale(m, img) } // Modify image as required if p.grayscale == 1 { grayscale(m) } else if p.grayscale == 2 { monochrome(m) } // Initialize buffer var buffer bytes.Buffer buffer.WriteString("<table align=\"center\" cellpadding=\"10\">\n<tr bgcolor=\"" + p.bgcolor + "\"><td>\n\n") buffer.WriteString("<!-- IMAGE BEGINS HERE -->\n<font size=\"" + p.fontsize + "\">\n<pre>") // Prepare variables htmlStart := "<font color=#" htmlEnd := "</font>" var current, previous uint = 0, 0 next := nextChar(p.texttype, p.characters) b := m.Bounds() // Loop over all pixels and add HTML-font converted data to the output buffer for y := b.Min.Y; y < b.Max.Y; y++ { j := m.PixOffset(0, y) current = uint(m.Pix[j+0])<<16 | uint(m.Pix[j+1])<<8 | uint(m.Pix[j+2]) buffer.WriteString(htmlStart + hex(current) + ">" + next()) previous = current for x := b.Min.X + 1; x < b.Max.X; x++ { i := m.PixOffset(x, y) current = uint(m.Pix[i+0])<<16 | uint(m.Pix[i+1])<<8 | uint(m.Pix[i+2]) if previous != current { buffer.WriteString(htmlEnd + htmlStart + hex(current) + ">" + next()) } else { buffer.WriteString(next()) } previous = current } buffer.WriteString(htmlEnd + "<br>") } // Finish up buffer buffer.WriteString("\n</pre></font>") buffer.WriteString("\n<!-- IMAGE ENDS HERE -->\n") buffer.WriteString("\n<FONT COLOR=LIGHTBLUE SIZE=2>Rendering time: " + time.Since(start).String() + "</FONT><BR>\n") result = buffer.Bytes() return }
// VersionSourceRect searches and returns an existing matching version, // or a new one will be created and saved. func (self *Image) VersionSourceRect(sourceRect image.Rectangle, width, height int, grayscale bool, outsideColor color.Color) (im *ImageVersion, err error) { debug.Nop() // debug.Printf( // "VersionSourceRect: from %dx%d image take rectangle [%d,%d,%d,%d] (%dx%d) and scale it to %dx%d", // self.Width(), // self.Height(), // sourceRect.Min.X, // sourceRect.Min.Y, // sourceRect.Max.X, // sourceRect.Max.Y, // sourceRect.Dx(), // sourceRect.Dy(), // width, // height, // ) if self.Grayscale() { grayscale = true // Ignore color requests when original image is grayscale } // Search for exact match for i := range self.Versions { v := &self.Versions[i] match := v.SourceRect.Rectangle() == sourceRect && v.Width.GetInt() == width && v.Height.GetInt() == height && v.OutsideColor.EqualsColor(outsideColor) && v.Grayscale.Get() == grayscale if match { return v, nil } } // No exact match, create version origImage, err := self.Versions[0].LoadImage() if err != nil { return nil, err } var versionImage image.Image if grayscale { versionImage = image.NewGray(image.Rect(0, 0, width, height)) } else { versionImage = image.NewRGBA(image.Rect(0, 0, width, height)) } if sourceRect.In(self.Rectangle()) { // debug.Print("VersionSourceRect: rectangle is within image") // versionImage = ResampleImage(origImage, sourceRect, width, height) subImage := SubImageWithoutOffset(origImage, sourceRect) err = graphics.Scale(versionImage.(draw.Image), subImage) if err != nil { return nil, err } if grayscale && !self.Grayscale() { var grayVersion image.Image = image.NewGray(versionImage.Bounds()) draw.Draw(grayVersion.(draw.Image), versionImage.Bounds(), versionImage, image.ZP, draw.Src) versionImage = grayVersion } } else { // debug.Print("VersionSourceRect: rectangle is not completely within image, using outsideColor") // Fill version with outsideColor draw.Draw(versionImage.(draw.Image), versionImage.Bounds(), image.NewUniform(outsideColor), image.ZP, draw.Src) // Where to draw the source image into the version image var destRect image.Rectangle if !(sourceRect.Min.X < 0 || sourceRect.Min.Y < 0) { panic("touching from outside means that sourceRect x or y must be negative") } sourceW := float64(sourceRect.Dx()) sourceH := float64(sourceRect.Dy()) destRect.Min.X = int(float64(-sourceRect.Min.X) / sourceW * float64(width)) destRect.Min.Y = int(float64(-sourceRect.Min.Y) / sourceH * float64(height)) destRect.Max.X = destRect.Min.X + int(float64(self.Width())/sourceW*float64(width)) destRect.Max.Y = destRect.Min.Y + int(float64(self.Height())/sourceH*float64(height)) // destImage := ResampleImage(origImage, origImage.Bounds(), destRect.Dx(), destRect.Dy()) // draw.Draw(versionImage.(draw.Image), destRect, destImage, image.ZP, draw.Src) subImage := SubImageWithoutOffset(origImage, sourceRect) destImage := SubImageWithoutOffset(versionImage, destRect) err = graphics.Scale(destImage.(draw.Image), subImage) if err != nil { return nil, err } } // Save new image version version := self.addVersion(self.Filename(), self.ContentType(), sourceRect, width, height, grayscale) err = version.SaveImage(versionImage) if err != nil { return nil, err } err = self.Save() if err != nil { return nil, err } return version, nil }