1// Same copyright and license as the rest of the files in this project
2
3// +build !gdk_pixbuf_2_2
4
5package gdk
6
7// #cgo pkg-config: gdk-3.0 glib-2.0 gobject-2.0 gmodule-2.0
8// #include <glib.h>
9// #include <gmodule.h>
10// #include <gdk/gdk.h>
11// #include "gdk.go.h"
12// #include "pixbuf.go.h"
13// #include "pixbuf_since_2_4.go.h"
14import "C"
15import (
16	"errors"
17	"io"
18	"reflect"
19	"runtime"
20	"strconv"
21	"unsafe"
22
23	"github.com/gotk3/gotk3/glib"
24	"github.com/gotk3/gotk3/internal/callback"
25)
26
27// File saving
28
29//export goPixbufSaveCallback
30func goPixbufSaveCallback(buf *C.gchar, count C.gsize, gerr **C.GError, id C.gpointer) C.gboolean {
31	v := callback.Get(uintptr(id))
32
33	if v == nil {
34		C._pixbuf_error_set_callback_not_found(gerr)
35		return C.FALSE
36	}
37
38	var bytes []byte
39	header := (*reflect.SliceHeader)((unsafe.Pointer(&bytes)))
40	header.Cap = int(count)
41	header.Len = int(count)
42	header.Data = uintptr(unsafe.Pointer(buf))
43
44	_, err := v.(io.Writer).Write(bytes)
45	if err != nil {
46		cerr := C.CString(err.Error())
47		defer C.free(unsafe.Pointer(cerr))
48
49		C._pixbuf_error_set(gerr, cerr)
50		return C.FALSE
51	}
52
53	return C.TRUE
54}
55
56// WritePNG is a convenience wrapper around gdk_pixbuf_save_to_callback() for
57// saving images using a streaming callback API. Compression is a number from 0
58// to 9.
59func (v *Pixbuf) WritePNG(w io.Writer, compression int) error {
60	ccompression := C.CString(strconv.Itoa(compression))
61	defer C.free(unsafe.Pointer(ccompression))
62
63	id := callback.Assign(w)
64
65	var err *C.GError
66	c := C._gdk_pixbuf_save_png_writer(v.native(), C.gpointer(id), &err, ccompression)
67
68	callback.Delete(id)
69
70	if !gobool(c) {
71		defer C.g_error_free(err)
72		return errors.New(C.GoString((*C.char)(err.message)))
73	}
74
75	return nil
76}
77
78// WriteJPEG is a convenience wrapper around gdk_pixbuf_save_to_callback() for
79// saving images using a streaming callback API. Quality is a number from 0 to
80// 100.
81func (v *Pixbuf) WriteJPEG(w io.Writer, quality int) error {
82	cquality := C.CString(strconv.Itoa(quality))
83	defer C.free(unsafe.Pointer(cquality))
84
85	id := callback.Assign(w)
86
87	var err *C.GError
88	c := C._gdk_pixbuf_save_jpeg_writer(v.native(), C.gpointer(id), &err, cquality)
89
90	callback.Delete(id)
91
92	if !gobool(c) {
93		defer C.g_error_free(err)
94		return errors.New(C.GoString((*C.char)(err.message)))
95	}
96
97	return nil
98}
99
100// TODO:
101// GdkPixbufSaveFunc
102// gdk_pixbuf_save_to_callback().
103// gdk_pixbuf_save_to_callbackv().
104// gdk_pixbuf_save_to_buffer().
105// gdk_pixbuf_save_to_bufferv().
106
107// File Loading
108
109// PixbufNewFromFileAtSize is a wrapper around gdk_pixbuf_new_from_file_at_size().
110func PixbufNewFromFileAtSize(filename string, width, height int) (*Pixbuf, error) {
111	cstr := C.CString(filename)
112	defer C.free(unsafe.Pointer(cstr))
113
114	var err *C.GError = nil
115	c := C.gdk_pixbuf_new_from_file_at_size(cstr, C.int(width), C.int(height), &err)
116	if err != nil {
117		defer C.g_error_free(err)
118		return nil, errors.New(C.GoString((*C.char)(err.message)))
119	}
120
121	if c == nil {
122		return nil, nilPtrErr
123	}
124
125	obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))}
126	p := &Pixbuf{obj}
127	//obj.Ref()
128	runtime.SetFinalizer(p, func(_ interface{}) { obj.Unref() })
129	return p, nil
130}
131
132// PixbufGetFileInfo is a wrapper around gdk_pixbuf_get_file_info().
133func PixbufGetFileInfo(filename string) (*PixbufFormat, int, int, error) {
134	cstr := C.CString(filename)
135	defer C.free(unsafe.Pointer(cstr))
136	var cw, ch C.gint
137	format := C.gdk_pixbuf_get_file_info((*C.gchar)(cstr), &cw, &ch)
138	if format == nil {
139		return nil, -1, -1, nilPtrErr
140	}
141	// The returned PixbufFormat value is owned by Pixbuf and should not be freed.
142	return wrapPixbufFormat(format), int(cw), int(ch), nil
143}
144