func main() { // Some GraphicsMagick boilerplate C.InitializeMagick(nil) defer C.DestroyMagick() C.GetExceptionInfo(&exceptionInfo) imageInfo = C.CloneImageInfo(nil) defer C.DestroyExceptionInfo(&exceptionInfo) defer C.DestroyImageInfo(imageInfo) // main OMIT Show("./cgo/armed_gopher.jpg") img, err := Read("./cgo/armed_gopher.jpg") if err != nil { fmt.Println(err) return } if img, err = Resize(img, 200, 800); err != nil { fmt.Println("resize error:", err) return } if err = Save(img, "./cgo/resized_gopher.jpg"); err != nil { fmt.Println("save error:", err) return } Show("./cgo/resized_gopher.jpg") }
// Composite modifies the image, drawing the draw Image argument at offset // (x, y) using the c Composite operation. func (im *Image) Composite(c Composite, draw *Image, x int, y int) error { op, err := im.compositeOperator(c) if err != nil { return err } var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var data C.CompositeData data.composite = C.int(op) data.draw = draw.image data.x = C.int(x) data.y = C.int(y) res, err := im.applyDataFunc("compositing", C.ImageDataFunc(C.compositeImage), &data) // res.image will be != than im.image when im is a non // coalesced animation if res.image != im.image { unrefImages(im.image) initializeRefCounts(res.image) refImages(res.image) im.image = res.image dontFree(res) } return err }
func (im *Image) fn(what string, f C.ImageFunc) (*Image, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) res := C.bridge_image_func(f, im.image, &ex) return checkImage(res, nil, &ex, what) }
func (im *Image) Roll(xoffset, yoffset int) (*Image, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) rolled := C.RollImage(im.image, magickLong(xoffset), magickLong(yoffset), &ex) return checkImage(rolled, nil, &ex, "rolling") }
// FloatMatrix returns an Image in the GRAY colorspace as FloatMatrix, // where each pixel represents an element of the matrix. Each element // is normalized to the [0,1] range. func (im *Image) FloatMatrix() (FloatMatrix, error) { if im.Colorspace() != GRAY { return nil, fmt.Errorf("FloatMatrix() is available only for GRAY images, this one is in %s", im.Colorspace()) } width := im.Width() height := im.Height() ptrs := make([]*C.double, width) for ii := range ptrs { ptrs[ii] = allocDoublePtr(height) } defer func() { for _, p := range ptrs { freeDoublePtr(p) } }() var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) C.image_matrix(im.image, (**C.double)(unsafe.Pointer(&ptrs[0])), &ex) if ex.severity != C.UndefinedException { return nil, exError(&ex, "generating float matrix") } m := make([][]float64, width) for ii := range m { m[ii] = doublePtrToFloat64Slice(ptrs[ii], height) } return FloatMatrix(m), nil }
func (im *Image) NColors() (int, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) val := C.GetNumberColors(im.image, nil, &ex) if ex.severity != C.UndefinedException { return 0, exError(&ex, "getting colors") } return int(val), nil }
// ChannelDepth returns the depth of the given channel. func (im *Image) ChannelDepth(ch Channel) (uint, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) ret := C.GetImageChannelDepth(im.image, C.ChannelType(ch), &ex) if ex.severity != C.UndefinedException { return 0, exError(&ex, "getting channel info") } return uint(ret), nil }
func (im *Image) IsPalette() (bool, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) b := C.IsPaletteImage(im.image, &ex) if ex.severity != C.UndefinedException { return false, exError(&ex, "getting isPalette") } return int(b) != 0, nil }
func (im *Image) statistics() (*Statistics, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var stats C.ImageStatistics C.GetImageStatistics(im.image, &stats, &ex) if ex.severity != C.UndefinedException { return nil, exError(&ex, "getting statistics") } return newStatistics(&stats), nil }
// Clone returns a copy of the image. If the image // has multiple frames, it copies all of them. To // Clone just one frame use im.Frame(i).Clone(). func (im *Image) Clone() (*Image, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var image *C.Image if im.parent == nil { image = C.CloneImageList(im.image, &ex) } else { image = C.CloneImage(im.image, magickSize(0), magickSize(0), 1, &ex) } return checkImage(image, nil, &ex, "cloning") }
func (im *Image) applyFunc(what string, f C.ImageFunc) (*Image, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) res := C.apply_image_func(f, im.root(), unsafe.Pointer(im.parent), btoi(im.coalesced), &ex) if res == nil { return nil, exError(&ex, what) } ret := newImage(res, nil) ret.coalesced = true return ret, nil }
func (im *Image) applyDataFunc(what string, f C.ImageDataFunc, data interface{}) (*Image, error) { p := unsafe.Pointer(reflect.ValueOf(data).Pointer()) var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) res := C.apply_image_data_func(f, im.root(), p, unsafe.Pointer(im.parent), btoi(im.coalesced), &ex) if res == nil { return nil, exError(&ex, what) } ret := newImage(res, nil) ret.coalesced = true return ret, nil }
func (im *Image) statistics() (*Statistics, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) stats := C.GetImageChannelStatistics(im.image, &ex) if stats != nil { defer freeMagickMemory(unsafe.Pointer(stats)) } if stats == nil || ex.severity != C.UndefinedException { return nil, exError(&ex, "getting statistics") } return newStatistics(stats), nil }
func decodeData(data []byte, try int) (*Image, error) { if len(data) == 0 { return nil, ErrNoData } info := C.CloneImageInfo(nil) defer C.DestroyImageInfo(info) var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) im := C.BlobToImage(info, unsafe.Pointer(&data[0]), C.size_t(len(data)), &ex) if im == nil && try < maxGifTries && ex.severity == C.CorruptImageError && looksLikeGif(data) { return fixAndDecodeGif(data, try) } return checkImage(im, nil, &ex, "decoding") }
// Composite modifies the image, drawing the draw Image argument at offset // (x, y) using the c Composite operation. func (im *Image) Composite(c Composite, draw *Image, x int, y int) error { op, err := im.compositeOperator(c) if err != nil { return err } var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var data C.CompositeData data.composite = C.int(op) data.draw = draw.image data.x = C.int(x) data.y = C.int(y) _, err = im.applyDataFunc("compositing", C.ImageDataFunc(C.compositeImage), &data) return err }
// Supported formats returns a list with the names // of all supported image formats. This varies depending // on the backend and the compile options that have been // used while building IM or GM. func SupportedFormats() ([]string, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) infos, p := supportedFormats(&ex) if infos == nil { return nil, exError(&ex, "getting supported formats") } var formats []string for _, v := range infos { if v == nil { break } formats = append(formats, C.GoString(v.name)) } freeMagickMemory(p) return formats, nil }
func (im *Image) Apply(f func(*Image) (*Image, error)) (*Image, error) { if im.IsOrphan() || im.parent != nil { return f(im) } var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) cur, free := im.coalescedCImage(&ex) if cur == nil { return nil, exError(&ex, "coalescing") } buf := &Image{ parent: im, image: cur, } first, err := f(buf) if err != nil { return nil, err } prev := first.image var res *Image for cur := (*C.Image)(im.image.next); cur != nil; cur = (*C.Image)(cur.next) { buf.image = cur res, err = f(buf) if err != nil { break } dontFree(res) img := res.image if img != cur { prev.next = (*C.struct__Image)(img) img.previous = (*C.struct__Image)(prev) } prev = img } if free && (first.image != cur || err != nil) { C.DestroyImageList(cur) } if err != nil { return nil, err } return first, nil }
// SetPixels changes the pixels in the given rect, in row major order. // Note that the number of elements in p must match r.Width * r.Height, // otherwise an error is returned. func (im *Image) SetPixels(r Rect, p []*Pixel) error { if int(r.Width*r.Height) != len(p) { return fmt.Errorf("rect contains %d pixels, but %d were provided", int(r.Width*r.Height), len(p)) } if len(p) == 0 { return nil } var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) packets := make([]C.PixelPacket, len(p)) for ii, v := range p { copyPixel(v, &packets[ii]) } if !im.setPixels(&r, (*C.PixelPacket)(unsafe.Pointer(&packets[0])), &ex) { return exError(&ex, "setting pixels") } return nil }
func (im *Image) AddFrame(f Frame, c *Pixel) (*Image, error) { return im.Apply(func(i *Image) (*Image, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var m *Pixel if c != nil { m = i.MatteColor() i.SetMatteColor(c) } framed := C.FrameImage(i.image, f.frameInfo(), &ex) if m != nil { i.SetMatteColor(m) } if framed == nil { return nil, exError(&ex, "adding border") } return newImage(framed, nil), nil }) }
func (im *Image) AddBorder(r Rect, c *Pixel) (*Image, error) { return im.Apply(func(i *Image) (*Image, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var b *Pixel if c != nil { b = i.BorderColor() im.SetBorderColor(c) } bordered := C.BorderImage(i.image, r.rectangleInfo(), &ex) if b != nil { i.SetBorderColor(b) } if bordered == nil { return nil, exError(&ex, "adding border") } return newImage(bordered, nil), nil }) }
// Pixels returns the image pixels contained in the given rect, // in row major order. Note that modifications to the returned pixels // won't alter the image. Use SetPixels to change pixels in the // image. func (im *Image) Pixels(r Rect) ([]*Pixel, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) ptr := im.pixels(&r, &ex) if ptr == nil { return nil, exError(&ex, "getting pixels") } count := int(r.Width * r.Height) var pkts []C.PixelPacket header := (*reflect.SliceHeader)((unsafe.Pointer(&pkts))) header.Cap = count header.Len = count header.Data = uintptr(unsafe.Pointer(ptr)) px := make([]*Pixel, count) for ii, v := range pkts { px[ii] = newPixel(&v) } return px, nil }
// Encode writes the image to the given io.Writer, encoding // it according to the info parameter. Please, see the // Info type for the available encoding options. func (im *Image) Encode(w io.Writer, info *Info) error { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) if info == nil { info = NewInfo() } /* ImageToBlob copies the format from the image into the image info. Overwrite if required and then restore */ im.mu.Lock() var format *C.char copied := false if info.info.magick[0] != 0 { copied = true if im.image.magick[0] != 0 { format = C.strdup(&im.image.magick[0]) } C.strncpy(&im.image.magick[0], &info.info.magick[0], C.MaxTextExtent) } var s C.size_t mem := imageToBlob(info, im, &s, &ex) if copied { /* Restore image format */ if format != nil { C.strncpy(&im.image.magick[0], format, C.MaxTextExtent) C.free(unsafe.Pointer(format)) } else { C.memset(unsafe.Pointer(&im.image.magick[0]), 0, C.MaxTextExtent) } } im.mu.Unlock() if mem == nil { return exError(&ex, "encoding") } b := goBytes(mem, int(s)) w.Write(b) C.free(mem) return nil }
// FloatMatrix returns an Image in the GRAY colorspace as FloatMatrix, // where each pixel represents an element of the matrix. Each element // is normalized to the [0,1] range. func (im *Image) FloatMatrix() (FloatMatrix, error) { if im.Colorspace() != GRAY { return nil, fmt.Errorf("FloatMatrix() is available only for GRAY images, this one is in %s", im.Colorspace()) } width := im.Width() height := im.Height() m := make([][]float64, width) ptrs := make([]unsafe.Pointer, width) for ii := range m { col := make([]float64, height) m[ii] = col ptrs[ii] = unsafe.Pointer(&col[0]) } var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) C.image_matrix(im.image, (**C.double)(unsafe.Pointer(&ptrs[0])), &ex) if ex.severity != C.UndefinedException { return nil, exError(&ex, "generating float matrix") } return FloatMatrix(m), nil }
func (im *Image) histogram() (*Histogram, error) { var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) var colors C.ulong hist := C.GetColorHistogram(im.image, &colors, &ex) if hist == nil { return nil, exError(&ex, "getting histogram") } defer C.free(unsafe.Pointer(hist)) count := int(colors) items := make([]*HistogramItem, count) var hitems []C.HistogramColorPacket sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&hitems))) sliceHeader.Cap = count sliceHeader.Len = count sliceHeader.Data = uintptr(unsafe.Pointer(hist)) for ii, v := range hitems { px := newPixel(&v.pixel) items[ii] = &HistogramItem{px, int(v.count)} } return &Histogram{items}, nil }
func (im *Image) operateChannel(op Operator, ch Channel, value float64) error { var cop C.QuantumOperator switch op { case OpAdd: cop = C.AddQuantumOp case OpAnd: cop = C.AndQuantumOp case OpAssign: cop = C.AssignQuantumOp case OpDepth: cop = C.DepthQuantumOp case OpDivide: cop = C.DivideQuantumOp case OpGamma: cop = C.GammaQuantumOp case OpLog: cop = C.LogQuantumOp case OpLShift: cop = C.LShiftQuantumOp case OpMax: cop = C.MaxQuantumOp case OpMin: cop = C.MinQuantumOp case OpMultiply: cop = C.MultiplyQuantumOp case OpGaussianNoise: cop = C.GammaQuantumOp case OpImpulseNoise: cop = C.NoiseImpulseQuantumOp case OpLaplacianNoise: cop = C.NoiseLaplacianQuantumOp case OpMultiplicativeNoise: cop = C.NoiseMultiplicativeQuantumOp case OpPoissonNoise: cop = C.NoisePoissonQuantumOp case OpRandomNoise: cop = C.NoiseRandomQuantumOp case OpUniformNoise: cop = C.NoisePoissonQuantumOp case OpOr: cop = C.OrQuantumOp case OpPow: cop = C.PowQuantumOp case OpRShift: cop = C.RShiftQuantumOp case OpSubstract: cop = C.SubtractQuantumOp case OpThresholdBlack: cop = C.ThresholdBlackQuantumOp case OpThreshold: cop = C.ThresholdQuantumOp case OpThresholdWhite: cop = C.ThresholdWhiteQuantumOp case OpXor: cop = C.XorQuantumOp default: return notImplementedError(fmt.Sprintf("operator %s", op)) } var ex C.ExceptionInfo C.GetExceptionInfo(&ex) defer C.DestroyExceptionInfo(&ex) if C.QuantumOperatorImage(im.image, C.ChannelType(ch), cop, C.double(value), &ex) != C.MagickTrue { return exError(&ex, "operating") } return nil }