Krita Source Code Documentation
Loading...
Searching...
No Matches
flatspec.c File Reference
#include "xcftools.h"
#include "flatten.h"
#include <string.h>
#include <stdlib.h>

Go to the source code of this file.

Functions

int add_layer_request (struct FlattenSpec *spec, const char *layer)
 
int analyse_colormode (struct FlattenSpec *spec, rgba **allPixels, guesser guess_callback)
 
static enum out_color_mode color_by_layers (struct FlattenSpec *spec)
 
int complete_flatspec (struct FlattenSpec *spec, guesser guess_callback)
 
void init_flatspec (struct FlattenSpec *spec)
 
struct xcfLayerlastlayerspec (struct FlattenSpec *spec, const char *option)
 
static int typeHasTransparency (GimpImageType type)
 

Function Documentation

◆ add_layer_request()

int add_layer_request ( struct FlattenSpec * spec,
const char * layer )

Definition at line 40 of file flatspec.c.

41{
42 spec->layers = realloc(spec->layers,
43 sizeof(struct xcfLayer) * (1+spec->numLayers));
44 if( spec->layers == NULL ) {
45 FatalUnexpected(_("Out of memory"));
46 return XCF_ERROR;
47 }
48 spec->layers[spec->numLayers].name = layer ;
49 spec->layers[spec->numLayers].mode = (GimpLayerModeEffects)-1 ;
50 spec->layers[spec->numLayers].opacity = 9999 ;
51 spec->layers[spec->numLayers].hasMask = -1 ;
52 spec->numLayers++ ;
53 return XCF_OK;
54}
GimpLayerModeEffects
Definition enums.h:8
int numLayers
Definition flatten.h:31
struct xcfLayer * layers
Definition flatten.h:32
unsigned int opacity
Definition xcftools.h:185
GimpLayerModeEffects mode
Definition xcftools.h:183
int hasMask
Definition xcftools.h:186
const char * name
Definition xcftools.h:182
void FatalUnexpected(const char *format,...)
Definition utils.c:56
#define XCF_OK
Definition xcftools.h:106
#define XCF_ERROR
Definition xcftools.h:105
#define _(s)
Definition xcftools.h:32

References _, FatalUnexpected(), xcfLayer::hasMask, FlattenSpec::layers, xcfLayer::mode, xcfLayer::name, FlattenSpec::numLayers, xcfLayer::opacity, XCF_ERROR, and XCF_OK.

◆ analyse_colormode()

int analyse_colormode ( struct FlattenSpec * spec,
rgba ** allPixels,
guesser guess_callback )

Definition at line 304 of file flatspec.c.

306{
307 unsigned x,y ;
308 int status ;
309 /* 8 - looking for any transparency
310 * 4 - looking for partially transparent pixels
311 * 2 - looking for pixels other than black and white
312 * 1 - looking for colored pixels
313 */
314 int known_absent = 0 ;
315 int assume_present = 0 ;
316
317 if( spec->out_color_mode == COLOR_BY_CONTENTS && guess_callback )
318 spec->out_color_mode = guess_callback(spec,allPixels) ;
319
320 if( spec->out_color_mode == COLOR_RGB ) assume_present |= 3 ;
321 if( spec->out_color_mode == COLOR_INDEXED ) assume_present |= 3 ;
322 if( spec->out_color_mode == COLOR_GRAY ) assume_present |= 2 ;
323 switch( color_by_layers(spec) ) {
324 case COLOR_GRAY: known_absent |= 1 ; break ;
325 case COLOR_MONO: known_absent |= 3 ; break ;
326 default: break ;
327 }
328 if( spec->partial_transparency_mode == DISSOLVE_PARTIAL_TRANSPARENCY ||
329 spec->partial_transparency_mode == PARTIAL_TRANSPARENCY_IMPOSSIBLE )
330 known_absent |= 4 ;
331 if( ALPHA(spec->default_pixel) >= 128 ) known_absent |= 12 ;
332 else if( spec->default_pixel == FORCE_ALPHA_CHANNEL ) assume_present |= 8 ;
333
334 status = 15 - (known_absent | assume_present) ;
335
336 for( y=0; status && y<spec->dim.height; y++ ) {
337 rgba *row = allPixels[y] ;
338 if( (status & 3) != 0 ) {
339 /* We're still interested in color */
340 for( x=0; status && x<spec->dim.width; x++ ) {
341 if( NULLALPHA(row[x]) )
342 status &= ~8 ;
343 else {
344 rgba full = row[x] | (255 << ALPHA_SHIFT) ;
345 if( !FULLALPHA(row[x]) ) status &= ~12 ;
346 if( full == NEWALPHA(0,255) || full == NEWALPHA(-1,255) )
347 /* Black or white */ ;
348 else if( degrayPixel(row[x]) != -1 )
349 status &= ~2 ; /* gray */
350 else
351 status &= ~3 ; /* color */
352 }
353 }
354 } else {
355 /* Not interested in color */
356 for( x=0; status && x<spec->dim.width; x++ ) {
357 if( NULLALPHA(row[x]) )
358 status &= ~8 ;
359 else if( !FULLALPHA(row[x]) )
360 status &= ~12 ;
361 }
362 }
363 }
364
365 status |= known_absent ;
366
367 switch( spec->out_color_mode ) {
368 case COLOR_INDEXED: /* The caller takes responsibility */
369 case COLOR_RGB: /* Everything is fine. */
370 break ;
371 case COLOR_GRAY:
372 if( (status & 1) == 0 ) {
373 FatalGeneric(103,
374 _("Grayscale output selected, but colored pixel(s) found"));
375 return XCF_ERROR;
376 }
377 break ;
378 case COLOR_MONO:
379 if( (status & 2) == 0 ) {
380 FatalGeneric(103,_("Monochrome output selected, but not all pixels "
381 "are black or white"));
382 return XCF_ERROR;
383 }
384 break ;
385 case COLOR_BY_FILENAME: /* Should not happen ... */
386 case COLOR_BY_CONTENTS:
387 if( (status & 1) == 0 )
388 spec->out_color_mode = COLOR_RGB ;
389 else if( (status & 2) == 0 )
390 spec->out_color_mode = COLOR_GRAY ;
391 else
392 spec->out_color_mode = COLOR_MONO ;
393 break ;
394 }
395
396 if( (status & 12) == 12 ) /* No transparency found */
397 spec->default_pixel = NEWALPHA(colormap[0],255);
398 else if( (status & 12) == 4 )
399 spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ;
400 return XCF_OK;
401}
static enum out_color_mode color_by_layers(struct FlattenSpec *spec)
Definition flatspec.c:84
#define FORCE_ALPHA_CHANNEL
Definition flatten.h:26
int degrayPixel(rgba pixel)
Definition pixels.c:29
rgba colormap[256]
Definition pixels.c:25
uint32_t rgba
Definition pixels.h:44
#define ALPHA_SHIFT
Definition pixels.h:46
#define FULLALPHA(rgba)
Definition pixels.h:52
#define ALPHA(rgba)
Definition pixels.h:51
#define NULLALPHA(rgba)
Definition pixels.h:53
#define NEWALPHA(rgb, a)
Definition pixels.h:54
rgba default_pixel
Definition flatten.h:30
struct tileDimensions dim
Definition flatten.h:29
enum FlattenSpec::@14 partial_transparency_mode
unsigned height
Definition xcftools.h:167
unsigned width
Definition xcftools.h:167
void FatalGeneric(int status, const char *format,...)
Definition utils.c:46

References _, ALPHA, ALPHA_SHIFT, color_by_layers(), colormap, degrayPixel(), xcfLayer::dim, FatalGeneric(), FORCE_ALPHA_CHANNEL, FULLALPHA, tileDimensions::height, NEWALPHA, NULLALPHA, tileDimensions::width, XCF_ERROR, and XCF_OK.

◆ color_by_layers()

static enum out_color_mode color_by_layers ( struct FlattenSpec * spec)
static

Definition at line 84 of file flatspec.c.

85{
86 int colormap_is_colored = 0 ;
87 enum out_color_mode grayish ;
88 int i ;
89
91 grayish = COLOR_GRAY ;
92 else {
93 int degrayed = degrayPixel(spec->default_pixel);
94 if( degrayed < 0 ) {
95 return COLOR_RGB ;
96 } else if( spec->gimpish_indexed &&
97 (degrayed == 0 || degrayed == 255) ) {
98 grayish = COLOR_MONO ;
99 } else {
100 grayish = COLOR_GRAY ;
101 }
102 }
103 for( i=0; i<colormapLength; i++ ) {
104 if( colormap[i] == NEWALPHA(0,0) || colormap[i] == NEWALPHA(-1,0) )
105 continue ;
106 if( degrayPixel(colormap[i]) == -1 ) {
107 colormap_is_colored = 1 ;
108 break ;
109 } else {
110 grayish = COLOR_GRAY ;
111 }
112 }
113 for( i=0; i<spec->numLayers; i++ )
114 switch( spec->layers[i].type ) {
115 case GIMP_RGB_IMAGE:
116 case GIMP_RGBA_IMAGE:
117 return COLOR_RGB ;
118 case GIMP_GRAY_IMAGE:
119 case GIMP_GRAYA_IMAGE:
120 grayish = COLOR_GRAY ;
121 break ;
124 if( colormap_is_colored ) return COLOR_RGB ;
125 break ;
126 }
127 return grayish ;
128}
@ GIMP_RGB_IMAGE
Definition enums.h:49
@ GIMP_INDEXED_IMAGE
Definition enums.h:53
@ GIMP_GRAYA_IMAGE
Definition enums.h:52
@ GIMP_INDEXEDA_IMAGE
Definition enums.h:54
@ GIMP_GRAY_IMAGE
Definition enums.h:51
@ GIMP_RGBA_IMAGE
Definition enums.h:50
#define CHECKERED_BACKGROUND
Definition flatten.h:27
unsigned colormapLength
Definition pixels.c:26
int gimpish_indexed
Definition flatten.h:54
GimpImageType type
Definition xcftools.h:184

References CHECKERED_BACKGROUND, colormap, colormapLength, degrayPixel(), xcfLayer::dim, GIMP_GRAY_IMAGE, GIMP_GRAYA_IMAGE, GIMP_INDEXED_IMAGE, GIMP_INDEXEDA_IMAGE, GIMP_RGB_IMAGE, GIMP_RGBA_IMAGE, and NEWALPHA.

◆ complete_flatspec()

int complete_flatspec ( struct FlattenSpec * spec,
guesser guess_callback )

Definition at line 131 of file flatspec.c.

132{
133 unsigned i ;
134 int anyPartial ;
135
136 /* Find the layers to convert.
137 */
138 if( spec->numLayers == 0 ) {
139 spec->layers = XCF.layers ;
140 spec->numLayers = XCF.numLayers ;
141 } else {
142 for( i=0; i<spec->numLayers; i++ ) {
144 int opacity, hasMask ;
145 unsigned j ;
146
147 for( j=0; ; j++ ) {
148 if( j == XCF.numLayers ) {
149 FatalGeneric(22,_("The image has no layer called '%s'"),
150 spec->layers[i].name);
151 return XCF_ERROR;
152 }
153 if( strcmp(spec->layers[i].name,XCF.layers[j].name) == 0 )
154 break ;
155 }
156 mode = spec->layers[i].mode == (GimpLayerModeEffects)-1 ?
157 XCF.layers[j].mode : spec->layers[i].mode ;
158 opacity = spec->layers[i].opacity == 9999 ?
159 XCF.layers[j].opacity : spec->layers[i].opacity ;
160 hasMask = spec->layers[i].hasMask == -1 ?
161 XCF.layers[j].hasMask : spec->layers[i].hasMask ;
162 if( hasMask && !XCF.layers[j].hasMask &&
163 XCF.layers[j].mask.hierarchy == 0 ) {
164 FatalGeneric(22,_("Layer '%s' has no layer mask to enable"),
165 spec->layers[i].name);
166 return XCF_ERROR;
167 }
168 spec->layers[i] = XCF.layers[j] ;
169 spec->layers[i].mode = mode ;
170 spec->layers[i].opacity = opacity ;
171 spec->layers[i].hasMask = hasMask ;
172 spec->layers[i].isVisible = 1 ;
173 }
174 }
175
176 /* Force the mode of the lowest visible layer to be Normal or Dissolve.
177 * That may not be logical, but the Gimp does it
178 */
179 for( i=0; i < spec->numLayers; i++ ) {
180 if( spec->layers[i].isVisible ) {
181 if( spec->layers[i].mode != GIMP_DISSOLVE_MODE )
182 spec->layers[i].mode = GIMP_NORMAL_MODE ;
183 break ;
184 }
185 }
186
187 /* Mimic the Gimp's behavior on indexed layers */
188 if( XCF.type == GIMP_INDEXED && spec->gimpish_indexed ) {
189 for( i=0; i<spec->numLayers; i++ )
190 if( spec->layers[i].mode != GIMP_DISSOLVE_MODE )
192 } else
193 spec->gimpish_indexed = 0 ;
194
195 /* compute dimensions of the window */
196 if( spec->window_mode == AUTOCROP ) {
197 int first = 1 ;
198 for( i=0; i<spec->numLayers; i++ )
199 if( spec->layers[i].isVisible ) {
200 if (computeDimensions(&spec->layers[i].dim) != XCF_OK) {
201 return XCF_ERROR;
202 }
203 if( first ) {
204 spec->dim = spec->layers[i].dim ;
205 first = 0 ;
206 } else {
207 if( spec->dim.c.l > spec->layers[i].dim.c.l )
208 spec->dim.c.l = spec->layers[i].dim.c.l ;
209 if( spec->dim.c.r < spec->layers[i].dim.c.r )
210 spec->dim.c.r = spec->layers[i].dim.c.r ;
211 if( spec->dim.c.t > spec->layers[i].dim.c.t )
212 spec->dim.c.t = spec->layers[i].dim.c.t ;
213 if( spec->dim.c.b < spec->layers[i].dim.c.b )
214 spec->dim.c.b = spec->layers[i].dim.c.b ;
215 }
216 }
217 if( first ) {
218 spec->window_mode = USE_CANVAS ;
219 } else {
220 spec->dim.width = spec->dim.c.r - spec->dim.c.l ;
221 spec->dim.height = spec->dim.c.b - spec->dim.c.t ;
222 }
223 }
224 if( spec->window_mode != AUTOCROP ) {
225 if( (spec->window_mode & MANUAL_OFFSET) == 0 )
226 spec->dim.c.t = spec->dim.c.l = 0 ;
227 if( (spec->window_mode & MANUAL_CROP) == 0 ) {
228 spec->dim.height = XCF.height ;
229 spec->dim.width = XCF.width ;
230 }
231 }
232 if (computeDimensions(&spec->dim) != XCF_OK) {
233 return XCF_ERROR;
234 }
235
236 /* Turn off layers that we don't hit at all */
237 for( i=0; i<spec->numLayers; i++ )
238 if( spec->layers[i].isVisible &&
239 disjointRects(spec->dim.c,spec->layers[i].dim.c) )
240 spec->layers[i].isVisible = 0 ;
241
242 /* See if there is a completely covering layer somewhere in the stack */
243 /* Also check if partial transparency is possible */
244 anyPartial = 0 ;
245 for( i=spec->numLayers; i-- ; ) {
246 if( !spec->layers[i].isVisible )
247 continue ;
248 if( typeHasTransparency(spec->layers[i].type) ) {
249 if( spec->layers[i].mode == GIMP_NORMAL_MODE )
250 anyPartial = 1;
251 } else if( isSubrect(spec->dim.c,spec->layers[i].dim.c) &&
252 !spec->layers[i].hasMask &&
253 (spec->layers[i].mode == GIMP_NORMAL_MODE ||
255 spec->layers[i].mode == GIMP_DISSOLVE_MODE) ) {
256 /* This layer fills out the entire image.
257 * Turn off only lower layers, and note that we cannot have
258 * transparency at all.
259 */
260 while(i) spec->layers[--i].isVisible = 0 ;
262 spec->default_pixel = NEWALPHA(colormap[0],255);
263 anyPartial = 0 ;
264 break ;
265 }
266 }
267 if( spec->partial_transparency_mode == ALLOW_PARTIAL_TRANSPARENCY &&
268 (!anyPartial || ALPHA(spec->default_pixel) >= 128) )
269 spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ;
270
271 /* Initialize layers and print overview if we're verbose */
272 for( i=spec->numLayers; i--; )
273 if( spec->layers[i].isVisible ) {
274 if (initLayer(&spec->layers[i]) != XCF_OK) {
275 return XCF_ERROR;
276 }
277 if( verboseFlag ) {
278 fprintf(stderr,"%dx%d%+d%+d %s %s",
279 spec->layers[i].dim.width, spec->layers[i].dim.height,
280 spec->layers[i].dim.c.l - spec->dim.c.l,
281 spec->layers[i].dim.c.t - spec->dim.c.t,
282 _(showGimpImageType(spec->layers[i].type)),
284 if( spec->layers[i].opacity < 255 )
285 fprintf(stderr,"/%02d%%",spec->layers[i].opacity * 100 / 255);
286 if( XCF.layers[i].hasMask )
287 fprintf(stderr,_("/mask"));
288 fprintf(stderr," %s\n",spec->layers[i].name);
289 }
290 }
291
292 /* Resolve color mode unless we wait until we have the entire image */
293 if( spec->out_color_mode == COLOR_BY_CONTENTS &&
294 !spec->process_in_memory ) {
295 if( guess_callback )
296 spec->out_color_mode = guess_callback(spec,NULL);
297 if( spec->out_color_mode == COLOR_BY_CONTENTS )
298 spec->out_color_mode = color_by_layers(spec) ;
299 }
300 return XCF_OK;
301}
const char * showGimpLayerModeEffects(GimpLayerModeEffects x)
Definition enums.c:6
const char * showGimpImageType(GimpImageType x)
Definition enums.c:54
@ GIMP_NORMAL_MODE
Definition enums.h:9
@ GIMP_DISSOLVE_MODE
Definition enums.h:10
@ GIMP_NORMAL_NOPARTIAL_MODE
Definition enums.h:35
@ GIMP_INDEXED
Definition enums.h:43
static int typeHasTransparency(GimpImageType type)
Definition flatspec.c:68
int initLayer(struct xcfLayer *layer)
Definition pixels.c:167
int process_in_memory
Definition flatten.h:53
enum FlattenSpec::@15 window_mode
int l
Definition xcftools.h:130
int r
Definition xcftools.h:130
int t
Definition xcftools.h:130
int b
Definition xcftools.h:130
struct rect c
Definition xcftools.h:166
GimpImageBaseType type
Definition xcftools.h:198
unsigned height
Definition xcftools.h:197
unsigned width
Definition xcftools.h:197
int numLayers
Definition xcftools.h:200
struct xcfLayer * layers
Definition xcftools.h:201
int isVisible
Definition xcftools.h:186
struct tileDimensions dim
Definition xcftools.h:181
struct xcfTiles mask
Definition xcftools.h:189
uint32_t hierarchy
Definition xcftools.h:177
int verboseFlag
Definition utils.c:26
struct xcfImage XCF
int computeDimensions(struct tileDimensions *d)
#define isSubrect(A, B)
Definition xcftools.h:133
#define disjointRects(A, B)
Definition xcftools.h:135

References _, ALPHA, rect::b, tileDimensions::c, color_by_layers(), colormap, computeDimensions(), xcfLayer::dim, disjointRects, FatalGeneric(), FORCE_ALPHA_CHANNEL, GIMP_DISSOLVE_MODE, GIMP_INDEXED, GIMP_NORMAL_MODE, GIMP_NORMAL_NOPARTIAL_MODE, xcfLayer::hasMask, tileDimensions::height, xcfImage::height, xcfTiles::hierarchy, initLayer(), isSubrect, rect::l, xcfImage::layers, xcfLayer::mask, xcfLayer::mode, xcfLayer::name, NEWALPHA, xcfImage::numLayers, xcfLayer::opacity, rect::r, showGimpImageType(), showGimpLayerModeEffects(), rect::t, xcfImage::type, typeHasTransparency(), verboseFlag, tileDimensions::width, xcfImage::width, XCF, XCF_ERROR, and XCF_OK.

◆ init_flatspec()

void init_flatspec ( struct FlattenSpec * spec)

Definition at line 25 of file flatspec.c.

26{
27 spec->window_mode = USE_CANVAS ;
29 spec->numLayers = 0 ;
30 spec->layers = NULL ;
31 spec->transmap_filename = NULL ;
32 spec->output_filename = "-" ;
33 spec->out_color_mode = COLOR_BY_CONTENTS ;
34 spec->partial_transparency_mode = ALLOW_PARTIAL_TRANSPARENCY ;
35 spec->process_in_memory = 0 ;
36 spec->gimpish_indexed = 1 ;
37}
#define PERHAPS_ALPHA_CHANNEL
Definition flatten.h:25
const char * transmap_filename
Definition flatten.h:34
const char * output_filename
Definition flatten.h:35

References FlattenSpec::default_pixel, FlattenSpec::gimpish_indexed, FlattenSpec::layers, FlattenSpec::numLayers, FlattenSpec::output_filename, FlattenSpec::partial_transparency_mode, PERHAPS_ALPHA_CHANNEL, FlattenSpec::process_in_memory, FlattenSpec::transmap_filename, and FlattenSpec::window_mode.

◆ lastlayerspec()

struct xcfLayer * lastlayerspec ( struct FlattenSpec * spec,
const char * option )

Definition at line 57 of file flatspec.c.

58{
59 if( spec->numLayers == 0 ) {
60 FatalGeneric(20,_("The %s option must follow a layer name on the "
61 "command line"),option);
62 return XCF_PTR_EMPTY;
63 }
64 return spec->layers + (spec->numLayers-1) ;
65}
#define XCF_PTR_EMPTY
Definition xcftools.h:107

References _, xcfLayer::dim, FatalGeneric(), and XCF_PTR_EMPTY.

◆ typeHasTransparency()

static int typeHasTransparency ( GimpImageType type)
static

Definition at line 68 of file flatspec.c.

69{
70 switch( type ) {
71 case GIMP_RGB_IMAGE:
72 case GIMP_GRAY_IMAGE:
74 return 0 ;
75 case GIMP_RGBA_IMAGE:
78 return 1 ;
79 }
80 return 1 ;
81}

References GIMP_GRAY_IMAGE, GIMP_GRAYA_IMAGE, GIMP_INDEXED_IMAGE, GIMP_INDEXEDA_IMAGE, GIMP_RGB_IMAGE, GIMP_RGBA_IMAGE, and xcfLayer::type.