1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
THIS DOCUMENT IS OBSOLETED BY THE AUTOLAYERS MERGE
* Paint devices and painters
Chalk's core consists of paint devices and painters:
KisPaintDevice
KisPainter
These classes are (very) loosely modelled on QPaintDevice and
QPainter. KisPaintDevice also takes up some of the roles of QImage,
but isn't all that efficient at it.
This is a write-up of my (Boudewijn's) understanding at this point;
* Getting pixel data in and out of a KisPaintDevice.
Chalk stores all image data in tiles; the tiles are managed by the
aptly named KisTileMgr. Inside the tiles, we have a KisPixelData
structure, which is basically a wrapper that packs together a pointer
to a memory area that contains the pixel data (QUANTUM's) and some
more information.
Ordinarily, you will change the data inside a KisPaintDevice through
the KisPainter. Using KisPainter has the advantage that your changes
will be undoable and that the tile manager is hidden. That's
especially nice, since you generally don't want to work directly with
tiles, not before having bought shares in an aspirin producer.
The other way of messing with the pixels inside a KisPaintDevice is
through the pixel() and and setPixel() methods in KisPaintDevice.
These methods retrieve and set the specified pixel data using the
tiles, but are not undoable. They are also rather ineffcient and slow.
KisPainter and KisPaintDevice do the job of hiding the actual image
data from the chalk hacker, but sometimes it's not enough, sometimes
you need to loop over all the pixels in an image, do
something, and write the pixels back to this or another image (or
sections of images).
In the near future, we will offer an iterator over the pixels, for now
you will have to ask the tile manager to copy all the bytes of the
image data in a buffer for you to read. Likewise, in the future we
will hopefully have something clever to feed pixel data to the tile
manager. For now, you will have to fill a memory buffer with the
desired data and feed that to the tile manager.
** Getting pixel data into your buffer
Define a pointer to a memory buffer with QUANTUMS
QUANTUM *buf;
Create the buffer. Note that you cannot assume that there is one byte
per channel; QUANTUM can be bigger.
buf = new QUANTUM[width * height * depth * sizeof(QUANTUM)];
Fill the buf with the data. x1, y1, x2, y2 are the top left and bottom
right corner of the section you want. stride is the width of the
section in bytes, i.e. (x2 - x1 + 1) * depth. Note that stride does
not need to be pre-multiplied with sizeof(QUANTUM), apparently.
tilemgr -> readPixelData(x1, y1, x2, y2, buf, stride);
Now all the pixels in the tile manager are copied into 'buf' -- the
operative word is 'copy', which means slow, and takes a lot of memory
is the section is big.
If you can stand computing with tiles, you can copy each tile into the
buffer, which takes a lot less memory, but you have to take care when
the image isn't exactly a multiple of the tilesize. See
kis_image_magick_converter.cpp for an example.
** Getting your data into a KisPaintDevice without using KisPainter
Although in the future we might offer a bitBlt that takes a simple
memory buffer and blits that onto the paint device, for now, you will
have to access the tile manager directly, using writePixelData.
First create a buffer, just as above:
QUANTUM * newData = new QUANTUM[width * height * depth * sizeof(QUANTUM)];
But unless you are sure you are going to fill absolutely every pixel,
you might want to initialize the buffer with memset. Chalk, in
contrast with ImageMagick, uses 0 as the value for transparent
opacity, so that's nice:
memset(newData, width * height * depth * sizeof(QUANTUM), 0);
Then create a new tilemanager, or reuse the old one if the size is
still correct. Stride is again width * depth, not width * depth *
sizeof(QUANTUM)
KisTileMgrSP tm = new KisTileMgr(depth, width, height);
tm -> writePixelData(x1, y1, x2, y2, newData, stride);
|