コード例 #1
0
ファイル: image.go プロジェクト: jimmyfrasche/cairo
func cNewImageSurface(s *C.cairo_surface_t) (Surface, error) {
	format := Format(C.cairo_image_surface_get_format(s))
	width := int(C.cairo_image_surface_get_width(s))
	height := int(C.cairo_image_surface_get_height(s))
	stride := int(C.cairo_image_surface_get_stride(s))

	return newImg(s, format, width, height, stride)
}
コード例 #2
0
ファイル: graphics.go プロジェクト: nathankerr/graphics
// pdf, ps, and svg surfaces use the current surface (page)
func (g *Graphic) Image() (image.Image, error) {
	var surface *C.cairo_surface_t
	switch g.format {
	case "eps", "pdf", "ps", "svg":
		// map vector surfaces to an image surface
		surface = C.cairo_surface_map_to_image(g.surface, nil)
		defer C.cairo_surface_unmap_image(g.surface, surface)

		status := C.cairo_surface_status(surface)
		err := statusToError(status)
		if err != nil {
			return nil, err
		}
	case "png", "jpeg":
		// no conversion needed
		surface = g.surface
	}

	width := int(C.cairo_image_surface_get_width(surface))
	height := int(C.cairo_image_surface_get_height(surface))
	stride := int(C.cairo_image_surface_get_stride(surface))
	format := C.cairo_image_surface_get_format(surface)
	dataPtr := C.cairo_image_surface_get_data(surface)
	data := C.GoBytes(unsafe.Pointer(dataPtr), C.int(stride*height))

	var img image.Image
	switch format {
	case C.CAIRO_FORMAT_ARGB32:
		img = &extimage.ARGB{
			Pix:    data,
			Stride: stride,
			Rect:   image.Rect(0, 0, width, height),
		}
	case C.CAIRO_FORMAT_RGB24:
		img = &extimage.RGB{
			Pix:    data,
			Stride: stride,
			Rect:   image.Rect(0, 0, width, height),
		}
	case C.CAIRO_FORMAT_A8:
		img = &image.Alpha{
			Pix:    data,
			Stride: stride,
			Rect:   image.Rect(0, 0, width, height),
		}
	default:
		// known unsupported formats:
		// CAIRO_FORMAT_INVALID   = -1,
		// CAIRO_FORMAT_A1        = 3,
		// CAIRO_FORMAT_RGB16_565 = 4,
		// CAIRO_FORMAT_RGB30     = 5
		panic(fmt.Sprintf("unsupported cairo image surface format: %d", int(format)))
	}

	return img, nil
}
コード例 #3
0
ファイル: surface.go プロジェクト: ungerik/go-cairo
// GetData returns a copy of the surfaces raw pixel data.
// This method also calls Flush.
func (self *Surface) GetData() []byte {
	self.Flush()
	dataPtr := C.cairo_image_surface_get_data(self.surface)
	if dataPtr == nil {
		panic("cairo.Surface.GetData(): can't access surface pixel data")
	}
	stride := C.cairo_image_surface_get_stride(self.surface)
	height := C.cairo_image_surface_get_height(self.surface)
	return C.GoBytes(unsafe.Pointer(dataPtr), stride*height)
}
コード例 #4
0
ファイル: surface.go プロジェクト: jimmyfrasche/cairo
//CreateSimilarImage creates a new surface that is as compatible as possible
//for uploading to and using in conjunction with existing surface.
//However, this surface can still be used like any normal image surface.
//
//Initially the contents of the returned surface are all 0 (transparent if contents
//have transparency, black otherwise.)
//
//Originally cairo_surface_create_similar_image.
func (e *XtensionSurface) CreateSimilarImage(f Format, w, h int) (ImageSurface, error) {
	s := C.cairo_surface_create_similar_image(e.s, f.c(), C.int(w), C.int(h))
	stride := int(C.cairo_image_surface_get_stride(s))
	o := ImageSurface{
		XtensionSurface: NewXtensionSurface(s),
		format:          f,
		width:           w,
		height:          h,
		stride:          stride,
	}
	return o, o.Err()
}
コード例 #5
0
ファイル: cairo.go プロジェクト: visionect/gotk3
func (v *Surface) GetData() []byte {
	c_data := C.cairo_image_surface_get_data(v.native())
	c_data_len := int(C.cairo_image_surface_get_stride(v.native()) *
		C.cairo_image_surface_get_height(v.native()))
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(c_data)),
		Len:  c_data_len,
		Cap:  c_data_len,
	}
	goSlice := *(*[]byte)(unsafe.Pointer(&hdr))
	return goSlice
}
コード例 #6
0
ファイル: webview.go プロジェクト: visionect/go-webkit2
// 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)
}
コード例 #7
0
ファイル: surface.go プロジェクト: ungerik/go-cairo
// SetData sets the surfaces raw pixel data.
// This method also calls Flush and MarkDirty.
func (self *Surface) SetData(data []byte) {
	self.Flush()
	dataPtr := unsafe.Pointer(C.cairo_image_surface_get_data(self.surface))
	if dataPtr == nil {
		panic("cairo.Surface.SetData(): can't access surface pixel data")
	}
	stride := C.cairo_image_surface_get_stride(self.surface)
	height := C.cairo_image_surface_get_height(self.surface)
	if len(data) != int(stride*height) {
		panic("cairo.Surface.SetData(): invalid data size")
	}
	C.memcpy(dataPtr, unsafe.Pointer(&data[0]), C.size_t(stride*height))
	self.MarkDirty()
}
コード例 #8
0
ファイル: webview.go プロジェクト: jayvansantos/go-webkit2
// GetSnapshot 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) GetSnapshot(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) != cairoImageSurfaceFormatARB32 {
				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))
			data := unsafe.Pointer(C.cairo_image_surface_get_data(snapResult))
			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)(1), // FullDocument is the only working region at this point
		(C.WebKitSnapshotOptions)(0),
		nil,
		cCallback,
		userData)
}
コード例 #9
0
ファイル: area_unix.go プロジェクト: UIKit0/ui
//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)
}
コード例 #10
0
ファイル: imagelist_unix.go プロジェクト: NotBadPad/ui
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)
}
コード例 #11
0
ファイル: surface.go プロジェクト: ungerik/go-cairo
func (self *Surface) GetStride() int {
	return int(C.cairo_image_surface_get_stride(self.surface))
}
コード例 #12
0
ファイル: webview.go プロジェクト: missionMeteora/go-webkit2
// GetSnapshot 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) GetSnapshot(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))
			data := unsafe.Pointer(C.cairo_image_surface_get_data(snapResult))
			surfaceBytes := C.GoBytes(data, C.int(stride*h))
			// convert from b,g,r,a or a,r,g,b(local endianness) to r,g,b,a
			testint, _ := binary.ReadUvarint(bytes.NewBuffer([]byte{0x1, 0}))
			if testint == 0x1 {
				// Little: b,g,r,a -> r,g,b,a
				for i := 0; i < w*h; i++ {
					b := surfaceBytes[4*i+0]
					r := surfaceBytes[4*i+2]
					surfaceBytes[4*i+0] = r
					surfaceBytes[4*i+2] = b
				}
			} else {
				// Big: a,r,g,b -> r,g,b,a
				for i := 0; i < w*h; i++ {
					a := surfaceBytes[4*i+0]
					r := surfaceBytes[4*i+1]
					g := surfaceBytes[4*i+2]
					b := surfaceBytes[4*i+3]
					surfaceBytes[4*i+0] = r
					surfaceBytes[4*i+1] = g
					surfaceBytes[4*i+2] = b
					surfaceBytes[4*i+3] = a
				}
			}
			rgba := &image.RGBA{surfaceBytes, 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)(1), // FullDocument is the only working region at this point
		(C.WebKitSnapshotOptions)(0),
		nil,
		cCallback,
		userData)
}
コード例 #13
0
ファイル: image.go プロジェクト: jimmyfrasche/cairo
//NewImageSurface creates an image surface of the given width, height,
//and format.
//
//Originally cairo_image_surface_create.
func NewImageSurface(format Format, width, height int) (ImageSurface, error) {
	is := C.cairo_image_surface_create(format.c(), C.int(width), C.int(height))
	stride := int(C.cairo_image_surface_get_stride(is))
	return newImg(is, format, width, height, stride)
}
コード例 #14
0
ファイル: imgops.go プロジェクト: akiross/gogp
// Fill the image evaluating the function over each pixel
// You can specify one function per channel, or one function for all the channels
// The values will be normalized
// BUG(akiross) this should return an error
func (img *Image) FillMath(chanFuncs ...PixelFunc) {
	nch := len(chanFuncs)
	// BUG(akiross) this code introduces checks which may be unnecessary
	// in production, would be nice to disable this checking
	switch img.ColorSpace {
	case MODE_A8:
		if nch != 1 {
			fmt.Println("ERROR! For A8 images is mandatory to use a single chanFunc")
			return
		}
	case MODE_G8:
		if nch != 1 {
			fmt.Println("ERROR! For G8 images is mandatory to use a single chanFunc")
			return
		}
	case MODE_RGB:
		if nch < 1 || nch > 3 {
			fmt.Println("ERROR! For mode RGB you need 1, 2 or 3 chanFuncs")
			return
		}
	default:
		fmt.Println("RGBA not implemented yet! Alpha must evaluate to 1, or value is always transparent!")
		return
		/*
			if nch < 1 || nch > 4 {
				fmt.Println("ERROR! For mode RGBA you need from 1 to 4 chanFuncs")
				return
			}
			if nch == 4 {
				// If 4 parameters are specified, the alpha gets moved in front
				chanFuncs[0], chanFuncs[1], chanFuncs[2], chanFuncs[3] = chanFuncs[3], chanFuncs[0], chanFuncs[1], chanFuncs[2]
			} else {
				// Else, first parameter is alpha (nil), other parameters follow
				chanFuncs2 := []PixelFunc{nil}
				chanFuncs = append(chanFuncs2, chanFuncs...)
			}
				Problem: if alpha returns a constant value, or if it is nil, image is always transparent (normalized -> 0)
		*/
	}
	// Evaluate the channel functions in every point
	realData := make([][][]float64, nch)
	//realData := make([]float64, img.H*img.W*nch)
	max := make([]float64, nch) // Hold max value per each channel
	min := make([]float64, nch) // Hold min value per each channel
	for k := 0; k < nch; k++ {
		realData[k] = make([][]float64, img.H)
		// If the channel function is defined, use it on every pixel
		// othersize, the data, min and max are already set to 0
		if chanFuncs[k] != nil {
			for i := 0; i < img.H; i++ {
				realData[k][i] = make([]float64, img.W)
				for j := 0; j < img.W; j++ {
					realData[k][i][j] = chanFuncs[k](j, i)
					max[k] = math.Max(max[k], realData[k][i][j])
					min[k] = math.Min(min[k], realData[k][i][j])
				}
			}
		}
	}

	// Copy the data onto the image
	stride := int(C.cairo_image_surface_get_stride(img.Surf)) // Stride in bytes
	rawData := unsafe.Pointer(C.cairo_image_surface_get_data(img.Surf))

	// Prepare byte data, normalizing if necessary (we cannot write directly to unsafe.Pointer)
	byteData := make([]byte, stride*img.H)

	// Depending on format, we copy the data in different ways
	switch img.ColorSpace {
	case MODE_A8:
		fmt.Println("Copying data for mode A8")
		const k = 0
		if max[k] != min[k] {
			for i := 0; i < img.H; i++ {
				for j := 0; j < img.W; j++ {
					byteData[i*stride+j] = byte(0xff * (realData[k][i][j] - min[k]) / (max[k] - min[k]))
				}
			}
		}
	case MODE_G8:
		fmt.Println("Copying data for mode G8")
		const k = 0
		if max[k] != min[k] {
			for i := 0; i < img.H; i++ {
				for j := 0; j < img.W; j++ {
					p := i*stride + j*4
					v := byte(0xff * (realData[k][i][j] - min[k]) / (max[k] - min[k]))
					byteData[p], byteData[p+1], byteData[p+2] = v, v, v
				}
			}
		}
	case MODE_RGB:
		fmt.Println("Copying data mode RGB")
		for k := 0; k < nch; k++ {
			if max[k] != min[k] {
				for i := 0; i < img.H; i++ {
					for j := 0; j < img.W; j++ {
						p := i*stride + j*4 + 1
						byteData[p+k] = byte(0xff * (realData[k][i][j] - min[k]) / (max[k] - min[k]))
					}
				}
			}
		}
	/*
		case MODE_RGBA:
			fmt.Println("Copying data mode RGBA")
			for k := 0; k < nch; k++ {
				if max[k] != min[k] {
					for i := 0; i < img.H; i++ {
						for j := 0; j < img.W; j++ {
							p := i*stride + j*4 + 1
							byteData[p+k] = byte(0xff * (realData[k][i][j] - min[k]) / (max[k] - min[k]))
						}
					}
				}
			}
	*/
	default:
		fmt.Println("ERROR! Not implemented yet")
	}
	// Copy the data on the C-side
	C.memcpy(rawData, unsafe.Pointer(&byteData[0]), C.size_t(stride*img.H))
}
コード例 #15
0
//export go_genericGAsyncCallback
func go_genericGAsyncCallback(source *C.GObject, result *C.GAsyncResult, callbackId *C.char) {
	key := C.GoString(callbackId)

	if obj, ok := cgoget(key); ok {
		switch obj.(type) {
		case *RunJavaScriptResponse:
			var jserr *C.GError

			response := obj.(*RunJavaScriptResponse)

			if response.Autoremove {
				defer cgounregister(key)
			}

			if jsResult := C.webkit_web_view_run_javascript_finish(response.CWebView, result, &jserr); jsResult == nil {
				defer C.g_error_free(jserr)
				msg := C.GoString((*C.char)(jserr.message))
				response.Reply(nil, errors.New(msg))
			} else {
				ctxRaw := gojs.RawGlobalContext(unsafe.Pointer(C.webkit_javascript_result_get_global_context(jsResult)))
				jsValRaw := gojs.RawValue(unsafe.Pointer(C.webkit_javascript_result_get_value(jsResult)))
				ctx := (*gojs.Context)(gojs.NewGlobalContextFrom(ctxRaw))
				jsVal := ctx.NewValueFrom(jsValRaw)
				response.Reply(jsVal, nil)
			}

		case *GetSnapshotAsImageResponse:
			var snapErr *C.GError

			response := obj.(*GetSnapshotAsImageResponse)

			if response.Autoremove {
				defer cgounregister(key)
			}

			if snapResult := C.webkit_web_view_get_snapshot_finish(response.CWebView, result, &snapErr); snapResult == nil {
				defer C.g_error_free(snapErr)
				msg := C.GoString((*C.char)(snapErr.message))
				response.Reply(nil, errors.New(msg))
			} else {
				defer C.cairo_surface_destroy(snapResult)

				if C.cairo_surface_get_type(snapResult) != cairoSurfaceTypeImage ||
					C.cairo_image_surface_get_format(snapResult) != cairoImageSurfaceFormatARGB32 {
					response.Reply(nil, errors.New("Snapshot in unexpected format"))
					return
				}

				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))
				data := unsafe.Pointer(C.cairo_image_surface_get_data(snapResult))
				surfaceBytes := C.GoBytes(data, C.int(stride*h))

				// convert from b,g,r,a or a,r,g,b(local endianness) to r,g,b,a
				testint, _ := binary.ReadUvarint(bytes.NewBuffer([]byte{0x1, 0}))

				if testint == 0x1 {
					// Little: b,g,r,a -> r,g,b,a
					for i := 0; i < w*h; i++ {
						b := surfaceBytes[4*i+0]
						r := surfaceBytes[4*i+2]
						surfaceBytes[4*i+0] = r
						surfaceBytes[4*i+2] = b
					}
				} else {
					// Big: a,r,g,b -> r,g,b,a
					for i := 0; i < w*h; i++ {
						a := surfaceBytes[4*i+0]
						r := surfaceBytes[4*i+1]
						g := surfaceBytes[4*i+2]
						b := surfaceBytes[4*i+3]
						surfaceBytes[4*i+0] = r
						surfaceBytes[4*i+1] = g
						surfaceBytes[4*i+2] = b
						surfaceBytes[4*i+3] = a
					}
				}

				rgba := &image.RGBA{
					Pix:    surfaceBytes,
					Stride: stride,
					Rect:   image.Rect(0, 0, w, h),
				}

				response.Reply(rgba, nil)
			}

		case *GetSnapshotAsCairoSurfaceResponse:
			var snapErr *C.GError

			response := obj.(*GetSnapshotAsCairoSurfaceResponse)

			snapResult := C.webkit_web_view_get_snapshot_finish(response.CWebView, result, &snapErr)

			if snapResult == nil {
				defer C.g_error_free(snapErr)
				msg := C.GoString((*C.char)(snapErr.message))
				response.Reply(nil, errors.New(msg))
			} else {
				surface := cairo.NewSurface(uintptr(unsafe.Pointer(snapResult)), false)

				if status := surface.Status(); status == cairo.STATUS_SUCCESS {
					response.Reply(surface, nil)
				} else {
					response.Reply(nil, fmt.Errorf("Cairo surface error %d", status))
				}
			}
		}
	}
}