new cairo image example

This commit is contained in:
Stefan Salewski 2019-08-22 20:09:44 +02:00
commit e0a619eff5
2 changed files with 336 additions and 0 deletions

View file

@ -0,0 +1,160 @@
# https://discourse.gnome.org/t/proper-zoom-pan-image-approach-for-large-images/1497/6
# Nim version of the C example of C. Eric Cashon
import gintro/[gtk, gobject, glib, cairo]
from math import TAU
import strutils
const
Width = 5000
Height = 5000
CFormat = cairo.Format.argb32
var
Key: cairo.UserDataKey
translateX: float
translateY: float
scale = 1.0
## Store data from file.
bigSurfaceData*: ptr cuchar = nil
proc translateXSpinChanged(spinButton: SpinButton; data: DrawingArea) =
translateX = spinButton.value
data.queueDraw
proc translateYSpinChanged(spinButton: SpinButton; data: DrawingArea) =
translateY = spinButton.getValue
data.queueDraw
proc scaleSpinChanged(spinButton: SpinButton; data: DrawingArea) =
scale = spinButton.value
data.queueDraw
proc saveBigSurface =
## Use gdk_cairo_surface_create_from_pixbuf() to read in a pixbuf. Try a test surface here.
let bigSurface = imageSurfaceCreate(CFormat, Width, Height)
let cr = newContext(bigSurface)
## Paint the background.
cr.setSource(1, 1, 1)
cr.paint
## Draw a circle.
cr.setSource(0, 0, 1)
cr.arc(250, 250, 50, 0, math.TAU)
cr.fill
## Draw some test grid lines.
cr.setSource(0, 1, 0)
for i in countup(0, 4900, 100):
cr.moveTo(0, i.float)
cr.lineTo(5000, i.float)
cr.stroke
for i in countup(0, 4900, 100):
cr.moveTo(i.float, 0)
cr.lineTo(i.float, 5000)
cr.stroke
cr.setSource(0, 0, 1)
cr.setLineWidth(10)
for i in 0 ..< 10:
cr.moveTo(0, i.float * 500.0)
cr.lineTo(5000, i.float * 500.0)
cr.stroke
for i in 0 ..< 10:
cr.moveTo(i.float * 500.0, 0)
cr.lineTo(i.float * 500.0, 5000)
cr.stroke
## Outside box.
cr.setLineWidth(20)
cr.setSource(1, 0, 1)
cr.rectangle(0, 0, 5000, 5000)
cr.stroke
## Save surface data to file.
let f: File = open("big_surface.s", fmWrite)
let p: ptr cuchar = cairo_image_surface_get_data(bigSurface.impl)
let len = writeBuffer(f, p, cairo_format_stride_for_width(CFormat, Width) * Height)
echo("write $1\n" % $len)
close(f)
proc myDealloc(data: pointer) {.cdecl.} =
system.dealloc(data)
proc getBigSurface(): Surface =
let f: File = open("big_surface.s", fmRead)
# setFilePos(f, 0)
# https://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-stride-for-width
let stride = cairo_format_stride_for_width(CFormat, Width)
bigSurfaceData = cast[ptr cuchar](malloc((stride * Height).uint64))
var len = readBuffer(f, bigSurfaceData, stride * Height)
echo("read $1" % $len)
close(f)
let bigSurface: Surface = new Surface # this is a temporary fix, we will support this later in cairo modul
bigSurface.impl = cairo_image_surface_create_for_data(bigSurfaceData, CFormat, Width, Height, stride)
discard setUserData(bigSurface, addr(Key), bigSurfaceData, myDealloc) # automatic deallocation
# flush(bigSurface)
echo("open $1" % bigSurface.status.statusToString)
return bigSurface
proc daDrawing*(da: DrawingArea; cr: Context; bigSurface: Surface): bool =
var
width = da.getAllocatedWidth.float
height = da.getAllocatedHeight.float
originX = translateX
originY = translateY
## Some constraints.
if translateX > 5000.0 - width:
originX = 5000.0 - width / scale
if translateY > 5000.0 - height:
originY = 5000.0 - height / scale
cr.setSource(0, 0, 0)
cr.paint
## Partition the big surface.
var littleSurface: Surface = cairo.surfaceCreateForRectangle(bigSurface,
originX, originY, width / scale, height / scale)
cr.scale(scale, scale)
cr.setSourceSurface(littleSurface, 0, 0)
setFilter(getSource(cr), cairo.Filter.bilinear)
cr.paint
return true
proc bye(w: Window) =
mainQuit()
echo "Bye..."
proc main =
gtk.init()
let window = newWindow()
window.setTitle("Big Surface2")
window.setDefaultSize(500, 500)
window.setPosition(gtk.WindowPosition.center)
window.connect("destroy", bye)
## Get a test surface.
saveBigSurface()
let bigSurface = getBigSurface()
let da: DrawingArea = newDrawingArea()
da.setHexpand
da.setVexpand
da.connect("draw", daDrawing, bigSurface)
let
translateXAdj = newAdjustment(0, 0, 5000, 20, 0, 0)
translateYAdj = newAdjustment(0, 0, 5000, 20, 0, 0)
scaleAdj = newAdjustment(1, 1, 5, 0.1, 0, 0)
translateXLabel = newLabel("translate x")
translateXSpin= newSpinButton(translateXAdj, 50, 1)
connect(translateXSpin, "value-changed", translateXSpinChanged, da)
let translateYLabel = newLabel("translate y")
let translateYSpin = newSpinButton(translateYAdj, 50, 1)
connect(translateYSpin, "value-changed", translateYSpinChanged, da)
let scaleLabel = newLabel("Scale")
let scaleSpin = newSpinButton(scaleAdj, 0.2, 1)
connect(scaleSpin, "value-changed", scaleSpinChanged, da)
let grid = newGrid()
grid.attach(da, 0, 0, 3, 1)
grid.attach(translateXLabel, 0, 1, 1, 1)
grid.attach(translateYLabel, 1, 1, 1, 1)
grid.attach(scaleLabel, 2, 1, 1, 1)
grid.attach(translateXSpin, 0, 2, 1, 1)
grid.attach(translateYSpin, 1, 2, 1, 1)
grid.attach(scaleSpin, 2, 2, 1, 1)
add(window, grid)
showAll(window)
gtk.main()
main()