func blur(img image.Image, howmuch float32) image.Image { g := gift.New(gift.Grayscale()) g.Add(gift.GaussianBlur(howmuch)) dst := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(dst, img) return (dst) }
func varianceF(img image.Image, disk int) (imageF, imageF) { m := meanF(img, disk) // gets a grayscale copy of local mean // create a grayscale version of the original //g := gift.New( gift.Grayscale() ) //v := image.NewRGBA(g.Bounds(img.Bounds())) //g.Draw(v, img) g := gift.New(gift.Grayscale()) dst := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(dst, img) bounds := img.Bounds() floatData := make([][]float32, bounds.Max.Y-bounds.Min.Y) for i := range floatData { floatData[i] = make([]float32, bounds.Max.X-bounds.Min.X) } for y := bounds.Min.X; y < bounds.Max.X; y++ { for x := bounds.Min.Y; x < bounds.Max.Y; x++ { p1r, p1g, p1b, _ := dst.At(x, y).RGBA() g1 := 0.2125*float64(p1r) + 0.7154*float64(p1g) + 0.0721*float64(p1b) g2 := float64(m[x][y]) floatData[x][y] = float32((g1 - g2) * (g1 - g2)) } } return m, floatData }
func mean(img image.Image, disk int) image.Image { g := gift.New(gift.Grayscale()) g.Add(gift.Mean(disk, false)) // use square neighborhood dst := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(dst, img) return (dst) }
func main() { if len(os.Args) != 2 { fmt.Println("Usage:\tgoimger <file>") os.Exit(1) } srcFileName := os.Args[1] srcFile, _ := os.Open(srcFileName) src, _, _ := image.Decode(srcFile) // let's make a new gift g := gift.New( gift.Grayscale(), gift.UnsharpMask(1.0, 0.5, 0.0), ) // dest - output image dest := image.NewRGBA(g.Bounds(src.Bounds())) // draw result g.Draw(dest, src) outFileName := srcFileName + "_goimger.jpg" toimg, _ := os.Create(outFileName) defer toimg.Close() jpeg.Encode(toimg, dest, &jpeg.Options{jpeg.DefaultQuality}) }
func main() { if len(os.Args) != 2 { fmt.Println("Usage:\tspiffy <file>") os.Exit(1) } srcFileName := os.Args[1] srcFile, _ := os.Open(srcFileName) src, _, _ := image.Decode(srcFile) // 1. Create a new GIFT and add some filters: g := gift.New( gift.Grayscale(), gift.UnsharpMask(1.0, 1.0, 0.0), ) // 2. Create a new image of the corresponding size. // dst is a new target image, src is the original image dst := image.NewRGBA(g.Bounds(src.Bounds())) // 3. Use Draw func to apply the filters to src and store the result in dst: g.Draw(dst, src) outFileName := srcFileName + ".spiffy.jpg" toimg, _ := os.Create(outFileName) defer toimg.Close() jpeg.Encode(toimg, dst, &jpeg.Options{jpeg.DefaultQuality}) }
// take an image and revert its rgb channels (255-channel) func invert(img image.Image) image.Image { g := gift.New(gift.Grayscale(), gift.Invert()) dst := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(dst, img) return dst }
// try to focus on a specific scale by using a mexican hat filter func focus(img image.Image, s float32) image.Image { onethird := s / 3.0 small := blur(img, s-onethird) large := blur(img, s+onethird) bounds := img.Bounds() floatData := make([][]float32, bounds.Max.X-bounds.Min.X) for i := range floatData { floatData[i] = make([]float32, bounds.Max.Y-bounds.Min.Y) } for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { p1r, p1g, p1b, _ := small.At(x, y).RGBA() p2r, p2g, p2b, _ := large.At(x, y).RGBA() g1 := 0.2125*float64(p1r) + 0.7154*float64(p1g) + 0.0721*float64(p1b) g2 := 0.2125*float64(p2r) + 0.7154*float64(p2g) + 0.0721*float64(p2b) floatData[x][y] = float32(g1 - g2) } } min := floatData[0][0] max := floatData[0][0] for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { if min > floatData[x][y] { min = floatData[x][y] } if max < floatData[x][y] { max = floatData[x][y] } } } g := gift.New(gift.Grayscale()) dst := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(dst, img) for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { dst.Set(x, y, color.Gray16{uint16((floatData[x][y] - min) / (max - min) * 65535)}) } } return dst }
func meanF(img image.Image, disk int) imageF { g := gift.New(gift.Grayscale()) g.Add(gift.Mean(disk, false)) // use square neighborhood dst := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(dst, img) // now convert this to float array of arrays floatData := make([][]float32, dst.Bounds().Max.Y-dst.Bounds().Min.Y) for i := range floatData { floatData[i] = make([]float32, dst.Bounds().Max.X-dst.Bounds().Min.X) } bounds := dst.Bounds() for y := bounds.Min.X; y < bounds.Max.X; y++ { for x := bounds.Min.Y; x < bounds.Max.Y; x++ { pr, _, _, _ := dst.At(x, y).RGBA() floatData[x][y] = float32(pr) // 0.2125*float32(pr) + 0.7154*float32(pg) + 0.0721*float32(pb) } } return floatData }
func variance(img image.Image, disk int) (image.Image, image.Image) { m := mean(img, disk) // gets a grayscale copy // create a grayscale version of the original g := gift.New(gift.Grayscale()) v := image.NewRGBA(g.Bounds(img.Bounds())) g.Draw(v, img) bounds := img.Bounds() dst := image.NewGray(bounds) for y := bounds.Min.X; y < bounds.Max.X; y++ { for x := bounds.Min.Y; x < bounds.Max.Y; x++ { p1r, p1g, p1b, _ := v.At(x, y).RGBA() p2r, p2g, p2b, _ := m.At(x, y).RGBA() g1 := 0.2125*float64(p1r) + 0.7154*float64(p1g) + 0.0721*float64(p1b) g2 := 0.2125*float64(p2r) + 0.7154*float64(p2g) + 0.0721*float64(p2b) dst.Set(x, y, color.Gray16{uint16(math.Sqrt((g1 - g2) * (g1 - g2)))}) //fmt.Println("value: ", math.Sqrt((g1-g2) * (g1-g2))) } } return m, dst }
// GreyscaleDctMatrix Computes the Dct of a greyscale image using matrixes func GreyscaleDctMatrix(im image.Image) uint64 { greyFilter := gift.Grayscale() convFilter := gift.Convolution([]float32{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, true, false, false, 0) resizeFilter := gift.Resize(32, 32, gift.LinearResampling) g := gift.New(greyFilter, convFilter, resizeFilter) dst := image.NewRGBA(g.Bounds(im.Bounds())) g.Draw(dst, im) /* out, _ := os.Create("/Users/danielriley/desktop/output.jpg") var opt jpeg.Options opt.Quality = 80 _ = jpeg.Encode(out, dst, &opt) // put quality to 80% out1, _ := os.Create("/Users/danielriley/desktop/output1.jpg") opt.Quality = 80 _ = jpeg.Encode(out1, im, &opt) // put quality to 80% return 0 */ //width := im.Bounds().Max.X //height := im.Bounds().Max.Y m := make([][]float64, 32) for i := 0; i < 32; i++ { m[i] = make([]float64, 32) for j := 0; j < 32; j++ { _, _, b, _ := dst.At(i, j).RGBA() m[i][j] = float64(b) } } /* out, _ := os.Create("/Users/danielriley/desktop/output.jpg") var opt jpeg.Options opt.Quality = 80 _ = jpeg.Encode(out, dst, &opt) // put quality to 80% out1, _ := os.Create("/Users/danielriley/desktop/output1.jpg") opt.Quality = 80 _ = jpeg.Encode(out1, im, &opt) // put quality to 80% */ imMatrix := FloatMatrix(m) dctMatrix := NewDCTMatrix(32) // We can safely ignore errors here, since the sizes // always match. dct, _ := dctMatrix.Multiply(imMatrix) dct, _ = dct.Multiply(dctMatrix.Transposed()) sub, _ := dct.SubMatrix(1, 1, 8, 8) values := sub.UnrollX() // We need the original values, so we must sort a copy cpy := make([]float64, len(values)) copy(cpy, values) sort.Float64s(cpy) median := (cpy[64/2-1] + cpy[64/2]) / 2 fmt.Println("got median ", median) bit := uint64(1) hash := uint64(0) for _, v := range values { if v > median { hash |= bit } bit <<= 1 } fmt.Println("calculated hash ", hash) return hash /* imgMtx, err := manipulator.GrayImageToMatrix(img) if err != nil { panic(err) } dctMtx, err := createDctMatrix(img.Bounds().Max.X, img.Bounds().Max.Y) if err != nil { panic(err) } dctMtxTransp := dctMtx.T() // Transpose dctMtx.Mul(dctMtx, imgMtx) dctMtx.Mul(dctMtx, dctMtxTransp) dctImage, err := manipulator.CropMatrix(dctMtx, 0, 0, 7, 7) if err != nil { panic(err) } subsec := dctImage.RawMatrix().Data median := median(subsec) var one, hash uint64 = 1, 0 for i := 0; i < len(subsec); i++ { current := subsec[i] if current > median { hash |= one } one = one << 1 } return hash */ }
func (processor *Processor) Execute(src *Image, dst io.Writer, query *Query) { processor.gift.Empty() quality := 100 if query.Count() > 0 { // resize if query.Has("w") || query.Has("h") { width := query.GetInt("w") height := query.GetInt("h") if width > 0 || height > 0 { processor.gift.Add(gift.Resize(width, height, gift.LanczosResampling)) } } // crop if query.Has("c") { c := query.GetIntArray("c") if len(c) == 4 { processor.gift.Add(gift.Crop(image.Rect(c[0], c[1], c[2], c[3]))) } } // grayscale if query.Has("grayscale") { processor.gift.Add(gift.Grayscale()) } // sepia if query.Has("sepia") { sepia := query.GetInt("sepia") if sepia <= 100 { processor.gift.Add(gift.Sepia(float32(sepia))) } } // contrast if query.Has("contrast") { contrast := query.GetInt("contrast") processor.gift.Add(gift.Contrast(float32(contrast))) } // brightness if query.Has("brightness") { brightness := query.GetInt("brightness") processor.gift.Add(gift.Brightness(float32(brightness))) } // saturation if query.Has("saturation") { saturation := query.GetInt("saturation") processor.gift.Add(gift.Saturation(float32(saturation))) } // colorize if query.Has("colorize") { colorize := query.GetIntArray("colorize") if len(colorize) == 3 { processor.gift.Add(gift.Colorize(float32(colorize[0]), float32(colorize[1]), float32(colorize[2]))) } } // colorbalance if query.Has("colorbalance") { colorbalance := query.GetIntArray("colorbalance") if len(colorbalance) == 3 { processor.gift.Add(gift.ColorBalance(float32(colorbalance[0]), float32(colorbalance[1]), float32(colorbalance[2]))) } } // quality if query.Has("q") { q := query.GetInt("q") if q > 0 && q < 100 { quality = q } } // Draw if len(processor.gift.Filters) > 0 { rgba := image.NewRGBA(processor.gift.Bounds(src.Object.Bounds())) processor.gift.Draw(rgba, src.Object) jpeg.Encode(dst, rgba, &jpeg.Options{Quality: quality}) return } } // default jpeg.Encode(dst, src.Object, &jpeg.Options{Quality: quality}) }
func (r *FilesResource) getImageReader(registry kit.Registry, tmpDir string, file kit.File, width, height int64, filters []string, ip string) (reader kit.ReadSeekerCloser, size int64, err apperror.Error) { if width == 0 && height == 0 && len(filters) == 0 { reader, err = file.Reader() return } // Dimensions specified. // Check if the thumbnail was already created. // If so, serve it. Otherwise, create it first. if (width == 0 || height == 0) && (file.GetWidth() == 0 || file.GetHeight() == 0) { err = &apperror.Err{ Code: "image_dimensions_not_determined", Message: fmt.Sprintf("The file with id %v does not have width/height", file.GetId()), } return } if width < 0 || height < 0 { err = apperror.New("invalid_dimensions") return } // If either height or width is 0, determine proper values to presserve aspect ratio. if width == 0 { ratio := float64(file.GetWidth()) / float64(file.GetHeight()) width = int64(float64(height) * ratio) } else if height == 0 { ratio := float64(file.GetHeight()) / float64(file.GetWidth()) height = int64(float64(width) * ratio) } maxWidth := registry.Config().UInt("files.thumbGenerator.maxWidth", 2000) maxHeight := registry.Config().UInt("files.thumbGenerator.maxHeight", 2000) if width > int64(maxWidth) || height > int64(maxHeight) { err = &apperror.Err{ Code: "dimensions_exceed_maximum_limits", Message: "The specified dimensions exceed the maximum limits", } return } thumbId := fmt.Sprintf("%v_%v_%v_%v_%v_%v.%v", file.GetId(), file.GetBucket(), file.GetName(), strconv.FormatInt(width, 10), strconv.FormatInt(height, 10), strings.Replace(strings.Join(filters, "_"), ":", "_", -1), "jpeg") if ok, _ := file.GetBackend().HasFileById("thumbs", thumbId); !ok { var channel chan bool channel, err = r.thumbnailRateLimiter.Start(ip) if err != nil { return } if channel != nil { <-channel } // Thumb does not exist yet, so create it. reader, err = file.Reader() if err != nil { return } defer reader.Close() img, _, err2 := image.Decode(reader) if err2 != nil { err = apperror.Wrap(err2, "image_decode_error") return } var giftFilters []gift.Filter if !(height == 0 && width == 0) { giftFilters = append(giftFilters, gift.ResizeToFill(int(width), int(height), gift.LanczosResampling, gift.CenterAnchor)) } for _, filter := range filters { if filter == "" { continue } parts := strings.Split(filter, ":") if len(parts) > 1 { filter = parts[0] } switch filter { case "sepia": n := float32(100) if len(parts) == 2 { x, err2 := strconv.ParseFloat(parts[1], 64) if err2 == nil { n = float32(x) } else { err = apperror.New("invalid_sepia_filter_value", true) return } } giftFilters = append(giftFilters, gift.Sepia(n)) case "grayscale": giftFilters = append(giftFilters, gift.Grayscale()) case "brightness": n := float32(0) if len(parts) == 2 { x, err2 := strconv.ParseFloat(parts[1], 64) if err2 == nil { n = float32(x) } else { err = apperror.New("invalid_brightness_filter_value", true) return } } giftFilters = append(giftFilters, gift.Brightness(n)) default: err = apperror.New("unknown_filter", fmt.Sprintf("Unknown filter: %v", filter), true) return } } gift := gift.New(giftFilters...) thumb := image.NewRGBA(gift.Bounds(img.Bounds())) gift.Draw(thumb, img) var writer io.WriteCloser _, writer, err = file.GetBackend().WriterById("thumbs", thumbId, true) if err != nil { return } defer writer.Close() jpeg.Encode(writer, thumb, &jpeg.Options{Quality: 90}) r.thumbnailRateLimiter.Finish() } backend := file.GetBackend() size, err = backend.FileSizeById("thumbs", thumbId) if err != nil { return } reader, err = file.GetBackend().ReaderById("thumbs", thumbId) return }