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