// 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 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") }
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") }
// 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) 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) 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 }
// Negate inverts the colors in the image func (im *MagickImage) Negate() (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) new_image := C.Negate(im.Image, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } im.ReplaceImage(new_image) return 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) 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 }
// ParseGeometryToRectangleInfo converts from a geometry string (WxH+X+Y) into a Magick // RectangleInfo that contains the individual properties func (im *MagickImage) ParseGeometryToRectangleInfo(geometry string) (info C.RectangleInfo, err error) { c_geometry := C.CString(geometry) defer C.free(unsafe.Pointer(c_geometry)) exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) C.ParseRegionGeometry(im.Image, c_geometry, &info, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { err = ErrorFromExceptionInfo(exception) } return }
// IntegralRotateImage rotates the image an integral of 90 degrees func (im *MagickImage) IntegralRotateImage(rotations int) (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) new_image := C.IntegralRotateImage(im.Image, C.size_t(rotations), exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } im.ReplaceImage(new_image) return nil }
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 }
// FillBackgroundColor fills transparent areas of an image with a solid color and stores the filled image in place. // color can be any color format that image magick understands, see: http://www.imagemagick.org/ImageMagick-7.0.0/script/color.php#models func (im *MagickImage) FillBackgroundColor(color string) (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) c_color := C.CString(color) defer C.free(unsafe.Pointer(c_color)) new_image := C.FillBackgroundColor(im.Image, c_color, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } im.ReplaceImage(new_image) return 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) 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 (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 }
// Crop crops the image based on the geometry string passed and stores the cropped image in place // For more info about Geometry see http://www.imagemagick.org/script/command-line-processing.php#geometry func (im *MagickImage) Crop(geometry string) (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) rect, err := im.ParseGeometryToRectangleInfo(geometry) if err != nil { return err } new_image := C.CropImage(im.Image, &rect, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } im.ReplaceImage(new_image) return nil }
// NewFromFile loads a file at filename into a MagickImage. // Exceptions are returned as MagickErrors. func NewFromFile(filename string) (im *MagickImage, err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) info := C.AcquireImageInfo() c_filename := C.CString(filename) defer C.free(unsafe.Pointer(c_filename)) C.SetImageInfoFilename(info, c_filename) image := C.ReadImage(info, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { C.DestroyImageInfo(info) return nil, ErrorFromExceptionInfo(exception) } return &MagickImage{Image: image, ImageInfo: info}, 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") }
// ToFile writes the (transformed) MagickImage to the regular file at filename. Magick determines // the encoding of the output file by the extension given to the filename (e.g. "image.jpg", "image.png") func (im *MagickImage) ToFile(filename string) (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) c_outpath := C.CString(filename) defer C.free(unsafe.Pointer(c_outpath)) C.SetImageInfoFilename(im.ImageInfo, c_outpath) success := C.WriteImages(im.ImageInfo, im.Image, c_outpath, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } if success != C.MagickTrue { return &MagickError{"fatal", "", "could not write to " + filename + " for unknown reason"} } return nil }
// ToBlob takes a (transformed) MagickImage and returns a byte slice in the format you specify with extension. // Magick uses the extension to transform the image in to the proper encoding (e.g. "jpg", "png") func (im *MagickImage) ToBlob(extension string) (blob []byte, err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) c_outpath := C.CString("image." + extension) defer C.free(unsafe.Pointer(c_outpath)) C.SetImageInfoFilename(im.ImageInfo, c_outpath) var outlength (C.size_t) outblob := C.ImageToBlob(im.ImageInfo, im.Image, &outlength, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return nil, ErrorFromExceptionInfo(exception) } char_pointer := unsafe.Pointer(outblob) defer C.free(char_pointer) return C.GoBytes(char_pointer, (C.int)(outlength)), nil }
// 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 }
// Shadow adds a dropshadow to the current (transparent) image and stores the shadowed image in place // For more information about shadow options see: http://www.imagemagick.org/Usage/blur/#shadow func (im *MagickImage) Shadow(color string, opacity, sigma float32, xoffset, yoffset int) (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) c_opacity := (C.double)(opacity) c_sigma := (C.double)(sigma) c_x := (C.ssize_t)(xoffset) c_y := (C.ssize_t)(yoffset) c_color := C.CString(color) defer C.free(unsafe.Pointer(c_color)) new_image := C.AddShadowToImage(im.Image, c_color, c_opacity, c_sigma, c_x, c_y, exception) if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } im.ReplaceImage(new_image) return nil }
// NewFromBlob takes a byte slice of image data and an extension that defines the // image type (e.g. "png", "jpg", etc). It loads the image data and returns a MagickImage. // The extension is required so that Magick knows what processor to use. func NewFromBlob(blob []byte, extension string) (im *MagickImage, err error) { if len(blob) < 1 { return nil, &MagickError{"fatal", "", "zero length blob passed to NewFromBlob"} } if len(extension) < 1 { return nil, &MagickError{"fatal", "", "zero length extension passed to NewFromBlob"} } exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) info := C.AcquireImageInfo() defer C.DestroyImageInfo(info) c_filename := C.CString("image." + extension) defer C.free(unsafe.Pointer(c_filename)) C.SetImageInfoFilename(info, c_filename) var success (C.MagickBooleanType) success = C.SetImageInfo(info, 1, exception) if success != C.MagickTrue { return nil, ErrorFromExceptionInfo(exception) } cloned_info := C.CloneImageInfo(info) success = C.GetBlobSupport(info) if success != C.MagickTrue { // No blob support, lets try reading from a file file, err := ioutil.TempFile("", "image."+extension) if _, err = file.Write(blob); err != nil { return nil, &MagickError{"fatal", "", "image format " + extension + " does not support blobs and could not write temp file"} } file.Close() return NewFromFile(file.Name()) } length := (C.size_t)(len(blob)) if length == 0 { return nil, &MagickError{"fatal", "", "empty blob"} } blob_start := unsafe.Pointer(&blob[0]) image := C.ReadImageFromBlob(info, blob_start, length) if image == nil { return nil, &MagickError{"fatal", "", "corrupt image, not a " + extension} } if failed := C.CheckException(exception); failed == C.MagickTrue { return nil, ErrorFromExceptionInfo(exception) } return &MagickImage{Image: image, ImageInfo: cloned_info}, nil }
// 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 }
// 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) 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 }
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 }) }
// Resize resizes the image based on the geometry string passed and stores the resized image in place // For more info about Geometry see http://www.imagemagick.org/script/command-line-processing.php#geometry func (im *MagickImage) Resize(geometry string) (err error) { exception := C.AcquireExceptionInfo() defer C.DestroyExceptionInfo(exception) rect, err := im.ParseGeometryToRectangleInfo(geometry) if err != nil { return err } ratio := im.ResizeRatio(int(rect.width), int(rect.height)) var new_image *C.Image if ratio > 0.4 { new_image = C.AdaptiveResizeImage(im.Image, rect.width, rect.height, exception) } else { new_image = C.ThumbnailImage(im.Image, rect.width, rect.height, exception) } if failed := C.CheckException(exception); failed == C.MagickTrue { return ErrorFromExceptionInfo(exception) } im.ReplaceImage(new_image) return nil }