Example #1
0
//ToImage returns a copy of the surface as an image.
//
//Originally cairo_image_surface_get_data.
func (is ImageSurface) ToImage() (*image.RGBA, error) {
	if err := is.Err(); err != nil {
		return nil, err
	}
	C.cairo_surface_flush(is.s)

	data := C.cairo_image_surface_get_data(is.s)

	n := is.height * is.stride
	img := &image.RGBA{
		Pix:    make([]uint8, n),
		Stride: is.stride,
		Rect:   image.Rect(0, 0, is.width, is.height),
	}
	pseudoslice := (*[1 << 30]C.uchar)(unsafe.Pointer(data))[:n:n]

	for i := 0; i < n; i += 4 {
		img.Pix[i+0] = uint8(pseudoslice[i+oR])
		img.Pix[i+1] = uint8(pseudoslice[i+oG])
		img.Pix[i+2] = uint8(pseudoslice[i+oB])
		img.Pix[i+3] = uint8(pseudoslice[i+oA])
	}

	return img, nil
}
Example #2
0
// GetSnapshotCustom runs asynchronously, taking a snapshot of the WebView.
// Upon completion, resultCallback will be called with a copy of the underlying
// bitmap backing store for the frame, or with an error encountered during
// execution.
//
// See also: webkit_web_view_get_snapshot at
// http://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html#webkit-web-view-get-snapshot
func (v *WebView) GetSnapshotCustom(region SnapshotRegion, options SnapshotOptions, resultCallback func(result *image.RGBA, err error)) {
	var cCallback C.GAsyncReadyCallback
	var userData C.gpointer
	var err error
	if resultCallback != nil {
		callback := func(result *C.GAsyncResult) {
			var snapErr *C.GError
			snapResult := C.webkit_web_view_get_snapshot_finish(v.webView, result, &snapErr)
			if snapResult == nil {
				defer C.g_error_free(snapErr)
				msg := C.GoString((*C.char)(snapErr.message))
				resultCallback(nil, errors.New(msg))
				return
			}
			defer C.cairo_surface_destroy(snapResult)

			if C.cairo_surface_get_type(snapResult) != cairoSurfaceTypeImage ||
				C.cairo_image_surface_get_format(snapResult) != cairoImageSurfaceFormatARGB32 {
				panic("Snapshot in unexpected format")
			}

			w := int(C.cairo_image_surface_get_width(snapResult))
			h := int(C.cairo_image_surface_get_height(snapResult))
			stride := int(C.cairo_image_surface_get_stride(snapResult))
			C.cairo_surface_flush(snapResult)
			data := unsafe.Pointer(C.cairo_image_surface_get_data(snapResult))

			//(miha) fix endianes depended byte order, and copy to go slice at the same time.
			data_fixed := make([]byte, stride*h)
			C.gowk2_cairo_endian_depended_ARGB32_to_RGBA((*C.uchar)(data), (*C.uchar)(&data_fixed[0]), C.uint(stride*h))
			rgba := &image.RGBA{data_fixed, stride, image.Rect(0, 0, w, h)}

			// slower but doesn't use Go pointers inside C. See https://github.com/golang/go/issues/8310 !!!!!!!
			//C.gowk2_cairo_endian_depended_ARGB32_to_RGBA((*C.uchar)(data), C.uint(stride*h))
			//rgba := &image.RGBA{C.GoBytes(data, C.int(stride*h)), stride, image.Rect(0, 0, w, h)}

			resultCallback(rgba, nil)
		}
		cCallback, userData, err = newGAsyncReadyCallback(callback)
		if err != nil {
			panic(err)
		}
	}

	C.webkit_web_view_get_snapshot(v.webView,
		(C.WebKitSnapshotRegion)(region),
		(C.WebKitSnapshotOptions)(options),
		nil,
		cCallback,
		userData)
}
Example #3
0
//export our_area_draw_callback
func our_area_draw_callback(widget *C.GtkWidget, cr *C.cairo_t, data C.gpointer) C.gboolean {
	var x0, y0, x1, y1 C.double
	var maxwid, maxht C.gint

	s := (*sysData)(unsafe.Pointer(data))
	// thanks to desrt in irc.gimp.net/#gtk+
	// these are in user coordinates, which match what coordinates we want by default, even out of a draw event handler (thanks johncc3, mclasen, and Company in irc.gimp.net/#gtk+)
	C.cairo_clip_extents(cr, &x0, &y0, &x1, &y1)
	// we do not need to clear the cliprect; GtkDrawingArea did it for us beforehand
	cliprect := image.Rect(int(x0), int(y0), int(x1), int(y1))
	// the cliprect can actually fall outside the size of the Area; clip it by intersecting the two rectangles
	C.gtk_widget_get_size_request(widget, &maxwid, &maxht)
	cliprect = image.Rect(0, 0, int(maxwid), int(maxht)).Intersect(cliprect)
	if cliprect.Empty() { // no intersection; nothing to paint
		return C.FALSE // signals handled without stopping the event chain (thanks to desrt again)
	}
	i := s.handler.Paint(cliprect)
	surface := C.cairo_image_surface_create(
		C.CAIRO_FORMAT_ARGB32, // alpha-premultiplied; native byte order
		C.int(i.Rect.Dx()),
		C.int(i.Rect.Dy()))
	if status := C.cairo_surface_status(surface); status != C.CAIRO_STATUS_SUCCESS {
		panic(fmt.Errorf("cairo_create_image_surface() failed: %s\n",
			C.GoString(C.cairo_status_to_string(status))))
	}
	// the flush and mark_dirty calls are required; see the cairo docs and https://git.gnome.org/browse/gtk+/tree/gdk/gdkcairo.c#n232 (thanks desrt in irc.gimp.net/#gtk+)
	C.cairo_surface_flush(surface)
	toARGB(i, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))),
		int(C.cairo_image_surface_get_stride(surface)))
	C.cairo_surface_mark_dirty(surface)
	C.cairo_set_source_surface(cr,
		surface,
		0, 0) // origin of the surface
	// that just set the brush that cairo uses: we have to actually draw now
	// (via https://developer.gnome.org/gtkmm-tutorial/stable/sec-draw-images.html.en)
	C.cairo_rectangle(cr, x0, y0, x1, y1) // breaking the nrom here since we have the coordinates as a C double already
	C.cairo_fill(cr)
	C.cairo_surface_destroy(surface) // free surface
	return C.FALSE                   // signals handled without stopping the event chain (thanks to desrt again)
}
Example #4
0
func (i *imagelist) Append(img *image.RGBA) {
	var width, height C.gint

	surface := C.cairo_image_surface_create(C.CAIRO_FORMAT_ARGB32,
		C.int(img.Rect.Dx()),
		C.int(img.Rect.Dy()))
	if status := C.cairo_surface_status(surface); status != C.CAIRO_STATUS_SUCCESS {
		panic(fmt.Errorf("cairo_create_image_surface() failed in ImageList.Append(): %s\n",
			C.GoString(C.cairo_status_to_string(status))))
	}
	C.cairo_surface_flush(surface)
	toARGB(img, uintptr(unsafe.Pointer(C.cairo_image_surface_get_data(surface))),
		int(C.cairo_image_surface_get_stride(surface)), false) // not NRGBA
	C.cairo_surface_mark_dirty(surface)
	basepixbuf := C.gdk_pixbuf_get_from_surface(surface, 0, 0, C.gint(img.Rect.Dx()), C.gint(img.Rect.Dy()))
	if basepixbuf == nil {
		panic(fmt.Errorf("gdk_pixbuf_get_from_surface() failed in ImageList.Append() (no reason available)"))
	}

	if C.gtk_icon_size_lookup(scaleTo, &width, &height) == C.FALSE {
		panic(fmt.Errorf("gtk_icon_size_lookup() failed in ImageList.Append() (no reason available)"))
	}
	if int(width) == img.Rect.Dx() && int(height) == img.Rect.Dy() {
		// just add the base pixbuf; we're good
		i.list = append(i.list, basepixbuf)
		C.cairo_surface_destroy(surface)
		return
	}
	// else scale
	pixbuf := C.gdk_pixbuf_scale_simple(basepixbuf, C.int(width), C.int(height), C.GDK_INTERP_NEAREST)
	if pixbuf == nil {
		panic(fmt.Errorf("gdk_pixbuf_scale_simple() failed in ImageList.Append() (no reason available)"))
	}

	i.list = append(i.list, pixbuf)
	C.gdk_pixbuf_unref(basepixbuf)
	C.cairo_surface_destroy(surface)
}
Example #5
0
func (self *Surface) Flush() {
	C.cairo_surface_flush(self.surface)
}
Example #6
0
// Flush is a wrapper around cairo_surface_flush().
func (v *Surface) Flush() {
	C.cairo_surface_flush(v.native())
}
Example #7
0
//Flush performs any pending drawing and restores any temporary modifcations
//that libcairo has made to the surface's state.
//
//Originally cairo_surface_flush.
func (e *XtensionSurface) Flush() error {
	C.cairo_surface_flush(e.s)
	return e.Err()
}