1 /*
2 Adapts SimpleAPI to existing engine API.
3
4 SimpleAPI takes only one image and mask.
5 The one image is both the target/context and the corpus/source.
6 The mask selects the target.
7 The inverse of the mask selects the corpus.
8
9 Adaption to existing API is:
10 - duplicating image into corpus with inverted mask.
11 - copying to global vars used by existing engine
12 - converting from row-padded pixmaps to unpadded pixmaps
13 - converting from separate image and mask pixmaps to an interleaved pixmap
14
15 Some of this might be discarded.
16 It will certainly be changed because the final engine
17 will not use static global vars so it is reentrant.
18
19 Copyright (C) 2010, 2011 Lloyd Konneker
20
21 This program is free software; you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation; either version 2 of the License, or
24 (at your option) any later version.
25
26 This program is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with this program; if not, write to the Free Software
33 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 */
35
36 #include <stdlib.h>
37
38 /*
39 Adapt pixmap that is row padded to pixmap:
40 - NOT row padded
41 - optionally offset color pixelels beyond 0th byte (an interleaved mask byte)
42 Convert between slightly different pixmap types.
43
44 !!!! This is not fully general. Strides should be passed in.
45 It just happens to work for now: when we are moving all pixels of the source.
46 */
47 static void
adaptImage(ImageBuffer * image,Map * pixmap,guint offset,guint pixelel_count)48 adaptImage(
49 ImageBuffer * image, // IN image: target or corpus drawable
50 Map *pixmap, // OUT NON-rowpadded pixmap
51 guint offset, // IN Offset in destination pixel. !!! Can be zero
52 guint pixelel_count // IN count pixelels to move
53 )
54 {
55 guint row;
56 guint col;
57 guint pixelel;
58
59 guint srcPixel;
60 guint destPixel;
61
62 /*
63 Copy SOME of the pixels from img sequence to our pixmap (optionally exclude alpha).
64 Allow for row padding in source.
65 OFFSET pixels in destination.
66 */
67 /*
68 Note the src and dest pixel indices are incremented differently, ie pixel strides different.
69 src: row padded: row stride greater than pixels*pixelelsperpixel
70 dest: not row padded
71 */
72 destPixel = offset; // dest pixel index starts at offset
73 guint srcPixelStride = pixelel_count;
74 guint destPixelStride = pixelel_count + offset; // dest is offset
75
76 for(row=0; row<image->height; row++)
77 {
78 srcPixel = row * image->rowBytes; // srcPixel index computed for START of each row
79 // dest pixel index continues at next byte
80 for(col=0; col<image->width; col++)
81 {
82 for (pixelel=0; pixelel < pixelel_count; pixelel++)
83 // Copy one pixelel, but possibly offset in destination
84 g_array_index(
85 pixmap->data,
86 Pixelel,
87 destPixel+pixelel
88 )
89 =
90 image->data[srcPixel+pixelel]; // src data is array of uchar
91
92 srcPixel += srcPixelStride;
93 destPixel += destPixelStride;
94 }
95 }
96 }
97
98
99 /*
100 Reverse of above: copy from engine existing API pixmap format to external API pixmap format.
101 Src is non row padded and offset
102 Dest is row padded.
103
104 This is used:
105 - for the test harness from a GIMP plugin on Linux
106 - in the final simpleAPI to write results back to the passed in ImageBuffer->data
107
108 !!! This is not fully general, the strides are hard coded below.
109 */
110 static void
antiAdaptImage(ImageBuffer * imageBuffer,Map * pixmap,guint offset,guint pixelel_count)111 antiAdaptImage(
112 ImageBuffer* imageBuffer, // OUT image: target or corpus drawable
113 Map* pixmap, // IN NON-rowpadded pixmap
114 guint offset, // IN Offset in internal source pixel
115 guint pixelel_count // IN count pixelels to move
116 // !!! Not size of pixel in src or dest since we omit alpha
117 )
118 {
119 guint row;
120 guint col;
121 guint pixelel;
122
123 // Indexes that move by pixel strides, but might point offset inside a pixel
124 guint srcPixel;
125 guint destPixel;
126
127 /*
128 Copy ALL of the pixels from our pixmap to buffer(including alpha which is unaltered.)
129 Row pad destination.
130 OFFSET pixels in source.
131 */
132 /*
133 Note the src and dest pixel indices are incremented differently, ie pixel strides different.
134 src: NOT row padded
135 dest: row padded
136 */
137
138 /*
139 Assert imageBuffer is properly initialized with dimensions and data.
140 The data can be unitialized, or valid image data to be overwritten here.
141 */
142
143 srcPixel = offset;
144 // source stride is offset plus pixels moved
145 guint srcPixelStride = pixelel_count + offset;
146 guint destPixelStride = pixelel_count;
147
148 for(row=0; row<imageBuffer->height; row++)
149 {
150 destPixel = row * imageBuffer->rowBytes; // destPixel index computed for START of each row
151 // dest pixel index continues at next byte
152 for(col=0; col<imageBuffer->width; col++)
153 {
154 for (pixelel=0; pixelel < pixelel_count; pixelel++)
155 // Copy one pixelel, but offset in src
156 imageBuffer->data[destPixel+pixelel]
157 =
158 g_array_index(
159 pixmap->data,
160 Pixelel,
161 srcPixel+pixelel
162 );
163
164 srcPixel += srcPixelStride;
165 destPixel += destPixelStride;
166 }
167 }
168 }
169
170 /*
171 For test purposes, initialize buffer and antiAdapt into the buffer.
172
173 This is used:
174 - for the test harness from a GIMP plugin on Linux
175
176 The test harness adapts in order:
177 - 1 from GIMP to existing API
178 - 2 from existing to simple API (this adaption is throwaway, not used except in testing)
179 - 3 from simple to existing API
180 initBufferAndAntiAdapt() is step 2.
181 */
182 static void
initBufferAndAntiAdapt(ImageBuffer * imageBuffer,Map * pixmap,guint offset,guint pixelel_count)183 initBufferAndAntiAdapt(
184 ImageBuffer* imageBuffer, // OUT image: target or corpus drawable
185 Map* pixmap, // IN NON-rowpadded pixmap
186 guint offset, // IN Offset in destination pixel
187 guint pixelel_count // IN count pixelels to move
188 )
189 {
190 guint rowBytes;
191
192 // !! imageBuffer struct exists but it is unitialized
193
194 // Use dimensions of IN pixmap to size the buffer
195 // !! Note the depth of the buffer is only the pixelels moved,
196 // not the pixelel count of pixmap, which may be more.
197 rowBytes = pixmap->width * pixelel_count + 11; // arbitrarily pad row, testing
198 int reservedSize = rowBytes * pixmap->height;
199
200 // Set attributes imageBuffer
201 imageBuffer->data = calloc(reservedSize, 1);
202 g_assert(imageBuffer->data);
203 imageBuffer->width = pixmap->width;
204 imageBuffer->height = pixmap->height;
205 imageBuffer->rowBytes = rowBytes;
206
207 antiAdaptImage(
208 imageBuffer,
209 pixmap,
210 offset,
211 pixelel_count
212 );
213 }
214
215
216
217
218 /*
219 Adapt imageBuffer and its mask to our internal pixmap.
220
221 Note the mask is kept separately and also interleaved into the pixmap,
222 because a preparation step uses the mask separately.
223 See prepareTarget.
224 */
225 void
adaptImageAndMask(ImageBuffer * image,ImageBuffer * mask,Map * imagePixmap,Map * maskPixmap,guint pixelelPerPixel)226 adaptImageAndMask(
227 ImageBuffer * image, // IN
228 ImageBuffer * mask, // IN
229 Map *imagePixmap, // OUT our color pixmap of drawable, w/ interleaved mask
230 Map *maskPixmap, // OUT our selection bytemap (only one channel ie pixelel ie byte ie depth)
231 guint pixelelPerPixel // IN pixelels in the image e.g. 4 for RGBA
232 )
233 {
234 // Note our internal map includes mask pixelel so +1
235
236 // Both OUT pixmaps same 2D dimensions.
237 // imagePixmap includes a mask byte.
238 new_pixmap(imagePixmap, image->width, image->height, pixelelPerPixel+1 );
239
240 // Get color, alpha channels. Offset them past mask byte. 4 bytes of RGBA.
241 adaptImage(image, imagePixmap, FIRST_PIXELEL_INDEX, pixelelPerPixel);
242
243 new_pixmap(maskPixmap, image->width, image->height, 1 );
244
245 // Get mask channel. Offset by 0 (mask byte first.) Byte count 1.
246 adaptImage(mask, maskPixmap, 0, 1);
247
248 // Assert two mallocs need to be freed
249 }
250
251
252 /*
253 Adapt simpleAPI to existingAPI:
254 - Duplicate the single image of the simpleAPI into two images (target and corpus) of existingAPI.
255 - Invert the mask of the corpus
256 - Interleave the masks into the main pixmap (but keep the mask pixmap also.)
257 Inner engine (existingAPI) is more general and wants separate corpus and separate selection masks.
258 */
259
260 void
adaptSimpleAPI(ImageBuffer * imageBuffer,ImageBuffer * maskBuffer,Map * targetMap,Map * corpusMap,guint pixelelPerPixel)261 adaptSimpleAPI(
262 ImageBuffer * imageBuffer,
263 ImageBuffer * maskBuffer,
264 Map * targetMap,
265 Map * corpusMap,
266 guint pixelelPerPixel // In imageBuffer
267 )
268 {
269 // Assert image and mask are same size, not need to initialize empty mask with a value
270 // (as is the case when mask is smaller).
271 Map targetMaskMap;
272
273 // Copy image and mask to global pixmaps
274 adaptImageAndMask(
275 imageBuffer,
276 maskBuffer,
277 targetMap,
278 &targetMaskMap,
279 pixelelPerPixel
280 );
281
282 // For performance (cache memory locality), interleave mask into pixmap.
283 interleave_mask(targetMap, &targetMaskMap); /* Interleave mask byte into our Pixels */
284 free_map(&targetMaskMap);
285
286
287 // Duplicate image to corpus with inverted mask
288 Map corpusMaskMap;
289
290 adaptImageAndMask(
291 imageBuffer,
292 maskBuffer,
293 corpusMap,
294 &corpusMaskMap,
295 pixelelPerPixel
296 );
297
298 // !!!!
299 // For the simple API, invert corpus mask: corpus is inverse of target selection
300 invert_bytemap(&corpusMaskMap);
301
302 // For performance (cache memory locality), interleave mask into pixmap.
303 interleave_mask(corpusMap, &corpusMaskMap); /* Interleave mask byte into our Pixels */
304 free_map(&corpusMaskMap);
305
306 // assert two mallocs
307 }
308
309
310
311