// Same copyright and license as the rest of the files in this project package gdk // #cgo pkg-config: gdk-3.0 glib-2.0 gobject-2.0 // #include // #include "gdk.go.h" // #include "pixbuf.go.h" import "C" import ( "errors" "reflect" "runtime" "strconv" "unsafe" "github.com/gotk3/gotk3/glib" ) func init() { tm := []glib.TypeMarshaler{ // Enums {glib.Type(C.gdk_pixbuf_alpha_mode_get_type()), marshalPixbufAlphaMode}, // Objects/Interfaces {glib.Type(C.gdk_pixbuf_get_type()), marshalPixbuf}, {glib.Type(C.gdk_pixbuf_animation_get_type()), marshalPixbufAnimation}, {glib.Type(C.gdk_pixbuf_loader_get_type()), marshalPixbufLoader}, } glib.RegisterGValueMarshalers(tm) } /* * Constants */ // TODO: // GdkPixbufError // PixbufRotation is a representation of GDK's GdkPixbufRotation. type PixbufRotation int const ( PIXBUF_ROTATE_NONE PixbufRotation = C.GDK_PIXBUF_ROTATE_NONE PIXBUF_ROTATE_COUNTERCLOCKWISE PixbufRotation = C.GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE PIXBUF_ROTATE_UPSIDEDOWN PixbufRotation = C.GDK_PIXBUF_ROTATE_UPSIDEDOWN PIXBUF_ROTATE_CLOCKWISE PixbufRotation = C.GDK_PIXBUF_ROTATE_CLOCKWISE ) // PixbufAlphaMode is a representation of GDK's GdkPixbufAlphaMode. type PixbufAlphaMode int const ( GDK_PIXBUF_ALPHA_BILEVEL PixbufAlphaMode = C.GDK_PIXBUF_ALPHA_BILEVEL GDK_PIXBUF_ALPHA_FULL PixbufAlphaMode = C.GDK_PIXBUF_ALPHA_FULL ) func marshalPixbufAlphaMode(p uintptr) (interface{}, error) { c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p))) return PixbufAlphaMode(c), nil } /* * GdkPixbuf */ // PixbufGetType is a wrapper around gdk_pixbuf_get_type(). func PixbufGetType() glib.Type { return glib.Type(C.gdk_pixbuf_get_type()) } // Pixbuf is a representation of GDK's GdkPixbuf. type Pixbuf struct { *glib.Object } // native returns a pointer to the underlying GdkPixbuf. func (v *Pixbuf) native() *C.GdkPixbuf { if v == nil || v.GObject == nil { return nil } p := unsafe.Pointer(v.GObject) return C.toGdkPixbuf(p) } // Native returns a pointer to the underlying GdkPixbuf. func (v *Pixbuf) Native() uintptr { return uintptr(unsafe.Pointer(v.native())) } func (v *Pixbuf) NativePrivate() *C.GdkPixbuf { if v == nil || v.GObject == nil { return nil } p := unsafe.Pointer(v.GObject) return C.toGdkPixbuf(p) } func marshalPixbuf(p uintptr) (interface{}, error) { c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p))) obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} return &Pixbuf{obj}, nil } // PixbufNew is a wrapper around gdk_pixbuf_new(). func PixbufNew(colorspace Colorspace, hasAlpha bool, bitsPerSample, width, height int) (*Pixbuf, error) { c := C.gdk_pixbuf_new(C.GdkColorspace(colorspace), gbool(hasAlpha), C.int(bitsPerSample), C.int(width), C.int(height)) if c == nil { return nil, nilPtrErr } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} //obj.Ref() runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p, nil } // File Loading // PixbufNewFromFile is a wrapper around gdk_pixbuf_new_from_file(). func PixbufNewFromFile(filename string) (*Pixbuf, error) { cstr := C.CString(filename) defer C.free(unsafe.Pointer(cstr)) var err *C.GError c := C.gdk_pixbuf_new_from_file((*C.char)(cstr), &err) if c == nil { defer C.g_error_free(err) return nil, errors.New(C.GoString((*C.char)(err.message))) } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} //obj.Ref() runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p, nil } // Image Data in Memory // PixbufNewFromData is a wrapper around gdk_pixbuf_new_from_data(). func PixbufNewFromData(pixbufData []byte, cs Colorspace, hasAlpha bool, bitsPerSample, width, height, rowStride int) (*Pixbuf, error) { arrayPtr := (*C.guchar)(unsafe.Pointer(&pixbufData[0])) c := C.gdk_pixbuf_new_from_data( arrayPtr, C.GdkColorspace(cs), gbool(hasAlpha), C.int(bitsPerSample), C.int(width), C.int(height), C.int(rowStride), nil, // TODO: missing support for GdkPixbufDestroyNotify nil, ) if c == nil { return nil, nilPtrErr } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} //obj.Ref() runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p, nil } // PixbufNewFromDataOnly is a convenient alternative to PixbufNewFromData() and also a wrapper around gdk_pixbuf_new_from_data(). func PixbufNewFromDataOnly(pixbufData []byte) (*Pixbuf, error) { pixbufLoader, err := PixbufLoaderNew() if err != nil { return nil, err } return pixbufLoader.WriteAndReturnPixbuf(pixbufData) } // PixbufNewFromResource is a wrapper around gdk_pixbuf_new_from_resource() func PixbufNewFromResource(resourcePath string) (*Pixbuf, error) { var gerr *C.GError cstr := C.CString(resourcePath) defer C.free(unsafe.Pointer(cstr)) c := C.gdk_pixbuf_new_from_resource((*C.gchar)(cstr), &gerr) if gerr != nil { defer C.g_error_free(gerr) return nil, errors.New(C.GoString(gerr.message)) } obj := glib.Take(unsafe.Pointer(c)) return &Pixbuf{obj}, nil } // PixbufNewFromResourceAtScale is a wrapper around gdk_pixbuf_new_from_resource_at_scale() func PixbufNewFromResourceAtScale(resourcePath string, width, height int, preserveAspectRatio bool) (*Pixbuf, error) { var gerr *C.GError cstr := C.CString(resourcePath) defer C.free(unsafe.Pointer(cstr)) cPreserveAspectRatio := gbool(preserveAspectRatio) c := C.gdk_pixbuf_new_from_resource_at_scale( (*C.gchar)(cstr), C.gint(width), C.gint(height), C.gboolean(cPreserveAspectRatio), &gerr, ) if gerr != nil { defer C.g_error_free(gerr) return nil, errors.New(C.GoString(gerr.message)) } obj := glib.Take(unsafe.Pointer(c)) return &Pixbuf{obj}, nil } // TODO: // gdk_pixbuf_new_from_xpm_data(). // gdk_pixbuf_new_subpixbuf() // PixbufCopy is a wrapper around gdk_pixbuf_copy(). func PixbufCopy(v *Pixbuf) (*Pixbuf, error) { c := C.gdk_pixbuf_copy(v.native()) if c == nil { return nil, nilPtrErr } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} //obj.Ref() runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p, nil } // The GdkPixbuf Structure // GetColorspace is a wrapper around gdk_pixbuf_get_colorspace(). func (v *Pixbuf) GetColorspace() Colorspace { c := C.gdk_pixbuf_get_colorspace(v.native()) return Colorspace(c) } // GetNChannels is a wrapper around gdk_pixbuf_get_n_channels(). func (v *Pixbuf) GetNChannels() int { c := C.gdk_pixbuf_get_n_channels(v.native()) return int(c) } // GetHasAlpha is a wrapper around gdk_pixbuf_get_has_alpha(). func (v *Pixbuf) GetHasAlpha() bool { c := C.gdk_pixbuf_get_has_alpha(v.native()) return gobool(c) } // GetBitsPerSample is a wrapper around gdk_pixbuf_get_bits_per_sample(). func (v *Pixbuf) GetBitsPerSample() int { c := C.gdk_pixbuf_get_bits_per_sample(v.native()) return int(c) } // GetPixels is a wrapper around gdk_pixbuf_get_pixels_with_length(). // A Go slice is used to represent the underlying Pixbuf data array, one // byte per channel. func (v *Pixbuf) GetPixels() (channels []byte) { var length C.guint c := C.gdk_pixbuf_get_pixels_with_length(v.native(), &length) sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&channels)) sliceHeader.Data = uintptr(unsafe.Pointer(c)) sliceHeader.Len = int(length) sliceHeader.Cap = int(length) // To make sure the slice doesn't outlive the Pixbuf, add a reference v.Ref() runtime.SetFinalizer(&channels, func(_ *[]byte) { glib.FinalizerStrategy(v.Unref) }) return } // GetWidth is a wrapper around gdk_pixbuf_get_width(). func (v *Pixbuf) GetWidth() int { c := C.gdk_pixbuf_get_width(v.native()) return int(c) } // GetHeight is a wrapper around gdk_pixbuf_get_height(). func (v *Pixbuf) GetHeight() int { c := C.gdk_pixbuf_get_height(v.native()) return int(c) } // GetRowstride is a wrapper around gdk_pixbuf_get_rowstride(). func (v *Pixbuf) GetRowstride() int { c := C.gdk_pixbuf_get_rowstride(v.native()) return int(c) } // GetOption is a wrapper around gdk_pixbuf_get_option(). ok is true if // the key has an associated value. func (v *Pixbuf) GetOption(key string) (value string, ok bool) { cstr := C.CString(key) defer C.free(unsafe.Pointer(cstr)) c := C.gdk_pixbuf_get_option(v.native(), (*C.gchar)(cstr)) if c == nil { return "", false } return C.GoString((*C.char)(c)), true } // Scaling // ScaleSimple is a wrapper around gdk_pixbuf_scale_simple(). func (v *Pixbuf) ScaleSimple(destWidth, destHeight int, interpType InterpType) (*Pixbuf, error) { c := C.gdk_pixbuf_scale_simple(v.native(), C.int(destWidth), C.int(destHeight), C.GdkInterpType(interpType)) if c == nil { return nil, nilPtrErr } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} //obj.Ref() runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p, nil } // Scale is a wrapper around gdk_pixbuf_scale(). func (v *Pixbuf) Scale(dest *Pixbuf, destX, destY, destWidth, destHeight int, offsetX, offsetY, scaleX, scaleY float64, interpType InterpType) { C.gdk_pixbuf_scale( v.native(), dest.native(), C.int(destX), C.int(destY), C.int(destWidth), C.int(destHeight), C.double(offsetX), C.double(offsetY), C.double(scaleX), C.double(scaleY), C.GdkInterpType(interpType), ) } // Composite is a wrapper around gdk_pixbuf_composite(). func (v *Pixbuf) Composite(dest *Pixbuf, destX, destY, destWidth, destHeight int, offsetX, offsetY, scaleX, scaleY float64, interpType InterpType, overallAlpha int) { C.gdk_pixbuf_composite( v.native(), dest.native(), C.int(destX), C.int(destY), C.int(destWidth), C.int(destHeight), C.double(offsetX), C.double(offsetY), C.double(scaleX), C.double(scaleY), C.GdkInterpType(interpType), C.int(overallAlpha), ) } // TODO: // gdk_pixbuf_composite_color_simple(). // gdk_pixbuf_composite_color(). // Utilities // TODO: // gdk_pixbuf_copy_area(). // gdk_pixbuf_saturate_and_pixelate(). // Fill is a wrapper around gdk_pixbuf_fill(). The given pixel is an RGBA value. func (v *Pixbuf) Fill(pixel uint32) { C.gdk_pixbuf_fill(v.native(), C.guint32(pixel)) } // AddAlpha is a wrapper around gdk_pixbuf_add_alpha(). If substituteColor is // true, then the color specified by r, g and b will be assigned zero opacity. func (v *Pixbuf) AddAlpha(substituteColor bool, r, g, b uint8) *Pixbuf { c := C.gdk_pixbuf_add_alpha(v.native(), gbool(substituteColor), C.guchar(r), C.guchar(g), C.guchar(b)) obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p } // File saving // TODO: // gdk_pixbuf_savev(). // gdk_pixbuf_save(). // SaveJPEG is a convenience wrapper around gdk_pixbuf_save() for saving image as jpeg file. // Quality is a number between 0...100 func (v *Pixbuf) SaveJPEG(path string, quality int) error { cpath := C.CString(path) cquality := C.CString(strconv.Itoa(quality)) defer C.free(unsafe.Pointer(cpath)) defer C.free(unsafe.Pointer(cquality)) var err *C.GError c := C._gdk_pixbuf_save_jpeg(v.native(), cpath, &err, cquality) if !gobool(c) { defer C.g_error_free(err) return errors.New(C.GoString((*C.char)(err.message))) } return nil } // SavePNG is a convenience wrapper around gdk_pixbuf_save() for saving image as png file. // Compression is a number between 0...9 func (v *Pixbuf) SavePNG(path string, compression int) error { cpath := C.CString(path) ccompression := C.CString(strconv.Itoa(compression)) defer C.free(unsafe.Pointer(cpath)) defer C.free(unsafe.Pointer(ccompression)) var err *C.GError c := C._gdk_pixbuf_save_png(v.native(), cpath, &err, ccompression) if !gobool(c) { defer C.g_error_free(err) return errors.New(C.GoString((*C.char)(err.message))) } return nil } /* * PixbufFormat */ type PixbufFormat struct { format *C.GdkPixbufFormat } // native returns a pointer to the underlying GdkPixbuf. func (v *PixbufFormat) native() *C.GdkPixbufFormat { if v == nil { return nil } return v.format } func wrapPixbufFormat(obj *C.GdkPixbufFormat) *PixbufFormat { return &PixbufFormat{obj} } // Native returns a pointer to the underlying GdkPixbuf. func (v *PixbufFormat) Native() uintptr { return uintptr(unsafe.Pointer(v.native())) } /* * GdkPixbufAnimation */ // PixbufAnimation is a representation of GDK's GdkPixbufAnimation. type PixbufAnimation struct { *glib.Object } // native returns a pointer to the underlying GdkPixbufAnimation. func (v *PixbufAnimation) native() *C.GdkPixbufAnimation { if v == nil || v.GObject == nil { return nil } p := unsafe.Pointer(v.GObject) return C.toGdkPixbufAnimation(p) } func (v *PixbufAnimation) NativePrivate() *C.GdkPixbufAnimation { if v == nil || v.GObject == nil { return nil } p := unsafe.Pointer(v.GObject) return C.toGdkPixbufAnimation(p) } func (v *PixbufAnimation) GetStaticImage() *Pixbuf { c := C.gdk_pixbuf_animation_get_static_image(v.native()) obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &Pixbuf{obj} // Add a reference so the pixbuf doesn't outlive the parent pixbuf // animation. v.Ref() runtime.SetFinalizer(p, func(*Pixbuf) { glib.FinalizerStrategy(v.Unref) }) return p } func marshalPixbufAnimation(p uintptr) (interface{}, error) { c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p))) obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} return &PixbufAnimation{obj}, nil } // PixbufAnimationNewFromFile is a wrapper around gdk_pixbuf_animation_new_from_file(). func PixbufAnimationNewFromFile(filename string) (*PixbufAnimation, error) { cstr := C.CString(filename) defer C.free(unsafe.Pointer(cstr)) var err *C.GError c := C.gdk_pixbuf_animation_new_from_file((*C.char)(cstr), &err) if c == nil { defer C.g_error_free(err) return nil, errors.New(C.GoString((*C.char)(err.message))) } obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} p := &PixbufAnimation{obj} runtime.SetFinalizer(p, func(_ interface{}) { glib.FinalizerStrategy(obj.Unref) }) return p, nil } // TODO: // gdk_pixbuf_animation_new_from_resource(). /* * GdkPixbufLoader */ // PixbufLoader is a representation of GDK's GdkPixbufLoader. // Users of PixbufLoader are expected to call Close() when they are finished. type PixbufLoader struct { *glib.Object } // native() returns a pointer to the underlying GdkPixbufLoader. func (v *PixbufLoader) native() *C.GdkPixbufLoader { if v == nil || v.GObject == nil { return nil } p := unsafe.Pointer(v.GObject) return C.toGdkPixbufLoader(p) } func marshalPixbufLoader(p uintptr) (interface{}, error) { c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p))) obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))} return &PixbufLoader{obj}, nil } // PixbufLoaderNew() is a wrapper around gdk_pixbuf_loader_new(). func PixbufLoaderNew() (*PixbufLoader, error) { c := C.gdk_pixbuf_loader_new() if c == nil { return nil, nilPtrErr } return &PixbufLoader{glib.AssumeOwnership(unsafe.Pointer(c))}, nil } // PixbufLoaderNewWithType() is a wrapper around gdk_pixbuf_loader_new_with_type(). func PixbufLoaderNewWithType(t string) (*PixbufLoader, error) { var err *C.GError cstr := C.CString(t) defer C.free(unsafe.Pointer(cstr)) c := C.gdk_pixbuf_loader_new_with_type((*C.char)(cstr), &err) if err != nil { defer C.g_error_free(err) return nil, errors.New(C.GoString((*C.char)(err.message))) } if c == nil { return nil, nilPtrErr } return &PixbufLoader{glib.AssumeOwnership(unsafe.Pointer(c))}, nil } // Write() is a wrapper around gdk_pixbuf_loader_write(). The // function signature differs from the C equivalent to satisify the // io.Writer interface. func (v *PixbufLoader) Write(data []byte) (int, error) { // n is set to 0 on error, and set to len(data) otherwise. // This is a tiny hacky to satisfy io.Writer and io.WriteCloser, // which would allow access to all io and ioutil goodies, // and play along nice with go environment. if len(data) == 0 { return 0, nil } var err *C.GError c := C.gdk_pixbuf_loader_write(v.native(), (*C.guchar)(unsafe.Pointer(&data[0])), C.gsize(len(data)), &err) if !gobool(c) { defer C.g_error_free(err) return 0, errors.New(C.GoString((*C.char)(err.message))) } return len(data), nil } // Convenient function like above for Pixbuf. Write data, close loader and return Pixbuf. func (v *PixbufLoader) WriteAndReturnPixbuf(data []byte) (*Pixbuf, error) { _, err := v.Write(data) if err != nil { return nil, err } if err := v.Close(); err != nil { return nil, err } return v.GetPixbuf() } // Close is a wrapper around gdk_pixbuf_loader_close(). An error is // returned instead of a bool like the native C function to support the // io.Closer interface. func (v *PixbufLoader) Close() error { var err *C.GError if ok := gobool(C.gdk_pixbuf_loader_close(v.native(), &err)); !ok { defer C.g_error_free(err) return errors.New(C.GoString((*C.char)(err.message))) } return nil } // GetPixbuf is a wrapper around gdk_pixbuf_loader_get_pixbuf(). func (v *PixbufLoader) GetPixbuf() (*Pixbuf, error) { c := C.gdk_pixbuf_loader_get_pixbuf(v.native()) if c == nil { return nil, nilPtrErr } return &Pixbuf{glib.Take(unsafe.Pointer(c))}, nil } // GetAnimation is a wrapper around gdk_pixbuf_loader_get_animation(). func (v *PixbufLoader) GetAnimation() (*PixbufAnimation, error) { c := C.gdk_pixbuf_loader_get_animation(v.native()) if c == nil { return nil, nilPtrErr } return &PixbufAnimation{glib.Take(unsafe.Pointer(c))}, nil } // Convenient function like above for Pixbuf. Write data, close loader and return PixbufAnimation. func (v *PixbufLoader) WriteAndReturnPixbufAnimation(data []byte) (*PixbufAnimation, error) { _, err := v.Write(data) if err != nil { return nil, err } if err := v.Close(); err != nil { return nil, err } return v.GetAnimation() }