/src/libvips/libvips/colour/colour.c
Line | Count | Source |
1 | | /* base class for all colour operations |
2 | | */ |
3 | | |
4 | | /* |
5 | | |
6 | | This file is part of VIPS. |
7 | | |
8 | | VIPS is free software; you can redistribute it and/or modify |
9 | | it under the terms of the GNU Lesser General Public License as published by |
10 | | the Free Software Foundation; either version 2 of the License, or |
11 | | (at your option) any later version. |
12 | | |
13 | | This program is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU Lesser General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU Lesser General Public License |
19 | | along with this program; if not, write to the Free Software |
20 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
21 | | 02110-1301 USA |
22 | | |
23 | | */ |
24 | | |
25 | | /* |
26 | | |
27 | | These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
28 | | |
29 | | */ |
30 | | |
31 | | /* |
32 | | #define DEBUG |
33 | | */ |
34 | | |
35 | | #ifdef HAVE_CONFIG_H |
36 | | #include <config.h> |
37 | | #endif /*HAVE_CONFIG_H*/ |
38 | | #include <glib/gi18n-lib.h> |
39 | | |
40 | | #include <stdio.h> |
41 | | #include <stdlib.h> |
42 | | #include <math.h> |
43 | | |
44 | | #include <vips/vips.h> |
45 | | #include <vips/internal.h> |
46 | | |
47 | | #include "pcolour.h" |
48 | | |
49 | | /* Areas under curves for Dxx. 2 degree observer. |
50 | | */ |
51 | | |
52 | | /** |
53 | | * VIPS_D93_X0: |
54 | | * |
55 | | * Areas under curves for D93, 2 degree observer. |
56 | | */ |
57 | | |
58 | | /** |
59 | | * VIPS_D75_X0: |
60 | | * |
61 | | * Areas under curves for D75, 2 degree observer. |
62 | | */ |
63 | | |
64 | | /** |
65 | | * VIPS_D65_X0: |
66 | | * |
67 | | * Areas under curves for D65, 2 degree observer. |
68 | | */ |
69 | | |
70 | | /** |
71 | | * VIPS_D55_X0: |
72 | | * |
73 | | * Areas under curves for D55, 2 degree observer. |
74 | | */ |
75 | | |
76 | | /** |
77 | | * VIPS_D50_X0: |
78 | | * |
79 | | * Areas under curves for D50, 2 degree observer. |
80 | | */ |
81 | | |
82 | | /** |
83 | | * VIPS_A_X0: |
84 | | * |
85 | | * Areas under curves for illuminant A (2856K), 2 degree observer. |
86 | | */ |
87 | | |
88 | | /** |
89 | | * VIPS_B_X0: |
90 | | * |
91 | | * Areas under curves for illuminant B (4874K), 2 degree observer. |
92 | | */ |
93 | | |
94 | | /** |
95 | | * VIPS_C_X0: |
96 | | * |
97 | | * Areas under curves for illuminant C (6774K), 2 degree observer. |
98 | | */ |
99 | | |
100 | | /** |
101 | | * VIPS_E_X0: |
102 | | * |
103 | | * Areas under curves for equal energy illuminant E. |
104 | | */ |
105 | | |
106 | | /** |
107 | | * VIPS_D3250_X0: |
108 | | * |
109 | | * Areas under curves for black body at 3250K, 2 degree observer. |
110 | | */ |
111 | | |
112 | 200 | G_DEFINE_ABSTRACT_TYPE(VipsColour, vips_colour, VIPS_TYPE_OPERATION); |
113 | 200 | |
114 | 200 | /* Maximum number of input images -- why not? |
115 | 200 | */ |
116 | 288k | #define MAX_INPUT_IMAGES (64) |
117 | | |
118 | | static int |
119 | | vips_colour_gen(VipsRegion *out_region, |
120 | | void *seq, void *a, void *b, gboolean *stop) |
121 | 296k | { |
122 | 296k | VipsRegion **ir = (VipsRegion **) seq; |
123 | 296k | VipsColour *colour = VIPS_COLOUR(b); |
124 | 296k | VipsColourClass *class = VIPS_COLOUR_GET_CLASS(colour); |
125 | 296k | VipsRect *r = &out_region->valid; |
126 | | |
127 | 296k | int i, y; |
128 | 296k | VipsPel *p[MAX_INPUT_IMAGES], *q; |
129 | | |
130 | | /* |
131 | | printf("vips_colour_gen: %s, " |
132 | | "left = %d, top = %d, width = %d, height = %d\n", |
133 | | VIPS_OBJECT_CLASS(class)->nickname, |
134 | | r->left, r->top, r->width, r->height); |
135 | | */ |
136 | | |
137 | 296k | if (vips_reorder_prepare_many(out_region->im, ir, r)) |
138 | 160k | return -1; |
139 | | |
140 | 296k | VIPS_GATE_START("vips_colour_gen: work"); |
141 | | |
142 | 4.51M | for (y = 0; y < r->height; y++) { |
143 | 8.75M | for (i = 0; ir[i]; i++) |
144 | 4.37M | p[i] = VIPS_REGION_ADDR(ir[i], r->left, r->top + y); |
145 | 4.37M | p[i] = NULL; |
146 | 4.37M | q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); |
147 | | |
148 | 4.37M | class->process_line(colour, q, p, r->width); |
149 | 4.37M | } |
150 | | |
151 | 136k | VIPS_GATE_STOP("vips_colour_gen: work"); |
152 | | |
153 | 136k | VIPS_COUNT_PIXELS(out_region, VIPS_OBJECT_GET_CLASS(colour)->nickname); |
154 | | |
155 | 136k | return 0; |
156 | 296k | } |
157 | | |
158 | | static int |
159 | | vips_colour_build(VipsObject *object) |
160 | 288k | { |
161 | 288k | VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); |
162 | 288k | VipsColour *colour = VIPS_COLOUR(object); |
163 | | |
164 | 288k | VipsImage **in; |
165 | 288k | VipsImage **extra_bands; |
166 | 288k | VipsImage *out; |
167 | | |
168 | | #ifdef DEBUG |
169 | | printf("vips_colour_build: "); |
170 | | vips_object_print_name(object); |
171 | | printf("\n"); |
172 | | #endif /*DEBUG*/ |
173 | | |
174 | 288k | if (VIPS_OBJECT_CLASS(vips_colour_parent_class)->build(object)) |
175 | 0 | return -1; |
176 | | |
177 | 288k | if (colour->n > MAX_INPUT_IMAGES) { |
178 | 0 | vips_error(class->nickname, "%s", _("too many input images")); |
179 | 0 | return -1; |
180 | 0 | } |
181 | 577k | for (int i = 0; i < colour->n; i++) |
182 | 288k | if (vips_image_pio_input(colour->in[i])) |
183 | 0 | return -1; |
184 | | |
185 | | /* colour->in[] must be NULL-terminated, we can use it as an arg to |
186 | | * vips_start_many(). |
187 | | */ |
188 | 288k | g_assert(!colour->in[colour->n]); |
189 | | |
190 | 288k | in = colour->in; |
191 | 288k | extra_bands = (VipsImage **) vips_object_local_array(object, colour->n); |
192 | | |
193 | | /* If there are more than @input_bands bands, we detach and reattach |
194 | | * after processing. |
195 | | */ |
196 | 288k | if (colour->input_bands > 0) { |
197 | 288k | VipsImage **new_in = (VipsImage **) |
198 | 288k | vips_object_local_array(object, colour->n); |
199 | | |
200 | 577k | for (int i = 0; i < colour->n; i++) { |
201 | 288k | if (vips_check_bands_atleast(class->nickname, |
202 | 288k | in[i], colour->input_bands)) |
203 | 6 | return -1; |
204 | | |
205 | 288k | if (in[i]->Bands > colour->input_bands) { |
206 | 60.0k | if (vips_extract_band(in[i], &new_in[i], 0, |
207 | 60.0k | "n", colour->input_bands, |
208 | 60.0k | NULL)) |
209 | 0 | return -1; |
210 | 60.0k | } |
211 | 228k | else { |
212 | 228k | new_in[i] = in[i]; |
213 | 228k | g_object_ref(new_in[i]); |
214 | 228k | } |
215 | | |
216 | 288k | if (in[i]->Bands > colour->input_bands) |
217 | 60.0k | if (vips_extract_band(in[i], &extra_bands[i], |
218 | 60.0k | colour->input_bands, |
219 | 60.0k | "n", in[i]->Bands - colour->input_bands, |
220 | 60.0k | NULL)) |
221 | 0 | return -1; |
222 | 288k | } |
223 | | |
224 | 288k | in = new_in; |
225 | 288k | } |
226 | | |
227 | 288k | out = vips_image_new(); |
228 | 288k | if (vips_image_pipeline_array(out, |
229 | 288k | VIPS_DEMAND_STYLE_THINSTRIP, in)) { |
230 | 0 | g_object_unref(out); |
231 | 0 | return -1; |
232 | 0 | } |
233 | 288k | out->Coding = colour->coding; |
234 | 288k | out->Type = colour->interpretation; |
235 | 288k | out->BandFmt = colour->format; |
236 | 288k | out->Bands = colour->bands; |
237 | | |
238 | 288k | if (colour->profile_filename && |
239 | 633 | vips__profile_set(out, colour->profile_filename)) |
240 | 0 | return -1; |
241 | | |
242 | 288k | if (vips_image_generate(out, |
243 | 288k | vips_start_many, vips_colour_gen, vips_stop_many, |
244 | 288k | in, colour)) { |
245 | 0 | VIPS_UNREF(out); |
246 | 0 | return -1; |
247 | 0 | } |
248 | | |
249 | | /* Reattach higher bands, if necessary. If we have more than one input |
250 | | * image, just use the first extra bands. |
251 | | */ |
252 | 517k | for (int i = 0; i < colour->n; i++) |
253 | 288k | if (extra_bands[i]) { |
254 | 60.0k | VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); |
255 | | |
256 | 60.0k | double max_alpha_before = |
257 | 60.0k | vips_interpretation_max_alpha(extra_bands[i]->Type); |
258 | 60.0k | double max_alpha_after = |
259 | 60.0k | vips_interpretation_max_alpha(out->Type); |
260 | | |
261 | 60.0k | VipsImage *alpha; |
262 | | |
263 | 60.0k | alpha = extra_bands[i]; |
264 | | |
265 | | /* Rescale, if the alpha scale has changed. |
266 | | */ |
267 | 60.0k | if (max_alpha_before != max_alpha_after) { |
268 | 36.5k | if (vips_linear1(alpha, &t[0], |
269 | 36.5k | max_alpha_after / max_alpha_before, 0.0, NULL)) { |
270 | 0 | VIPS_UNREF(out); |
271 | 0 | return -1; |
272 | 0 | } |
273 | 36.5k | alpha = t[0]; |
274 | 36.5k | } |
275 | | |
276 | 60.0k | if (vips_cast(alpha, &t[1], out->BandFmt, NULL)) { |
277 | 0 | VIPS_UNREF(out); |
278 | 0 | return -1; |
279 | 0 | } |
280 | 60.0k | alpha = t[1]; |
281 | | |
282 | 60.0k | if (vips_bandjoin2(out, alpha, &t[2], NULL)) { |
283 | 0 | VIPS_UNREF(out); |
284 | 0 | return -1; |
285 | 0 | } |
286 | 60.0k | g_object_unref(out); |
287 | 60.0k | out = t[2]; |
288 | 60.0k | t[2] = NULL; |
289 | | |
290 | 60.0k | break; |
291 | 60.0k | } |
292 | | |
293 | 288k | g_object_set(colour, "out", out, NULL); |
294 | | |
295 | 288k | return 0; |
296 | 288k | } |
297 | | |
298 | | static void |
299 | | vips_colour_class_init(VipsColourClass *class) |
300 | 20 | { |
301 | 20 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
302 | 20 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
303 | 20 | VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); |
304 | | |
305 | 20 | gobject_class->set_property = vips_object_set_property; |
306 | 20 | gobject_class->get_property = vips_object_get_property; |
307 | | |
308 | 20 | vobject_class->nickname = "colour"; |
309 | 20 | vobject_class->description = _("color operations"); |
310 | 20 | vobject_class->build = vips_colour_build; |
311 | | |
312 | 20 | operation_class->flags = VIPS_OPERATION_SEQUENTIAL; |
313 | | |
314 | 20 | VIPS_ARG_IMAGE(class, "out", 100, |
315 | 20 | _("Output"), |
316 | 20 | _("Output image"), |
317 | 20 | VIPS_ARGUMENT_REQUIRED_OUTPUT, |
318 | 20 | G_STRUCT_OFFSET(VipsColour, out)); |
319 | 20 | } |
320 | | |
321 | | static void |
322 | | vips_colour_init(VipsColour *colour) |
323 | 290k | { |
324 | 290k | colour->coding = VIPS_CODING_NONE; |
325 | 290k | colour->interpretation = VIPS_INTERPRETATION_sRGB; |
326 | 290k | colour->format = VIPS_FORMAT_UCHAR; |
327 | 290k | colour->bands = 3; |
328 | 290k | colour->input_bands = -1; |
329 | 290k | } |
330 | | |
331 | 560 | G_DEFINE_ABSTRACT_TYPE(VipsColourTransform, vips_colour_transform, |
332 | 560 | VIPS_TYPE_COLOUR); |
333 | 560 | |
334 | 560 | static int |
335 | 560 | vips_colour_transform_build(VipsObject *object) |
336 | 153k | { |
337 | 153k | VipsColour *colour = VIPS_COLOUR(object); |
338 | 153k | VipsColourTransform *transform = VIPS_COLOUR_TRANSFORM(object); |
339 | 153k | VipsImage **t = (VipsImage **) vips_object_local_array(object, 1); |
340 | | |
341 | | /* We only process float. |
342 | | */ |
343 | 153k | if (transform->in && |
344 | 153k | transform->in->BandFmt != VIPS_FORMAT_FLOAT) { |
345 | 2.87k | if (vips_cast_float(transform->in, &t[0], NULL)) |
346 | 0 | return -1; |
347 | 2.87k | } |
348 | 150k | else { |
349 | 150k | t[0] = transform->in; |
350 | 150k | g_object_ref(t[0]); |
351 | 150k | } |
352 | | |
353 | | /* We always do 3 bands -> 3 bands. |
354 | | */ |
355 | 153k | colour->input_bands = 3; |
356 | | |
357 | 153k | colour->n = 1; |
358 | 153k | colour->in = t; |
359 | | |
360 | 153k | if (VIPS_OBJECT_CLASS(vips_colour_transform_parent_class)->build(object)) |
361 | 3 | return -1; |
362 | | |
363 | 153k | return 0; |
364 | 153k | } |
365 | | |
366 | | static void |
367 | | vips_colour_transform_class_init(VipsColourTransformClass *class) |
368 | 20 | { |
369 | 20 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
370 | 20 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
371 | | |
372 | 20 | gobject_class->set_property = vips_object_set_property; |
373 | 20 | gobject_class->get_property = vips_object_get_property; |
374 | | |
375 | 20 | vobject_class->nickname = "space"; |
376 | 20 | vobject_class->description = _("color space transformations"); |
377 | 20 | vobject_class->build = vips_colour_transform_build; |
378 | | |
379 | 20 | VIPS_ARG_IMAGE(class, "in", 1, |
380 | 20 | _("Input"), |
381 | 20 | _("Input image"), |
382 | 20 | VIPS_ARGUMENT_REQUIRED_INPUT, |
383 | 20 | G_STRUCT_OFFSET(VipsColourTransform, in)); |
384 | 20 | } |
385 | | |
386 | | static void |
387 | | vips_colour_transform_init(VipsColourTransform *space) |
388 | 154k | { |
389 | 154k | VipsColour *colour = (VipsColour *) space; |
390 | | |
391 | | /* What we write. interpretation should be overwritten in subclass |
392 | | * builds. |
393 | | */ |
394 | 154k | colour->coding = VIPS_CODING_NONE; |
395 | 154k | colour->interpretation = VIPS_INTERPRETATION_LAB; |
396 | 154k | colour->format = VIPS_FORMAT_FLOAT; |
397 | 154k | colour->bands = 3; |
398 | 154k | } |
399 | | |
400 | 640 | G_DEFINE_ABSTRACT_TYPE(VipsColourCode, vips_colour_code, VIPS_TYPE_COLOUR); |
401 | 640 | |
402 | 640 | static int |
403 | 640 | vips_colour_code_build(VipsObject *object) |
404 | 135k | { |
405 | 135k | VipsColour *colour = VIPS_COLOUR(object); |
406 | 135k | VipsColourCode *code = VIPS_COLOUR_CODE(object); |
407 | 135k | VipsColourCodeClass *class = VIPS_COLOUR_CODE_GET_CLASS(object); |
408 | 135k | VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); |
409 | | |
410 | 135k | VipsImage *in; |
411 | | |
412 | 135k | in = code->in; |
413 | | |
414 | | /* We want labq, rad etc. all decoded (unlike colour_build). |
415 | | */ |
416 | 135k | if (in && |
417 | 135k | code->input_coding == VIPS_CODING_NONE && |
418 | 133k | in->Coding != code->input_coding) { |
419 | 13 | if (vips_image_decode(in, &t[0])) |
420 | 0 | return -1; |
421 | 13 | in = t[0]; |
422 | 13 | } |
423 | | |
424 | 135k | if (in && |
425 | 135k | vips_check_coding(VIPS_OBJECT_CLASS(class)->nickname, |
426 | 135k | in, code->input_coding)) |
427 | 1 | return -1; |
428 | | |
429 | 135k | if (in && |
430 | 135k | code->input_coding == VIPS_CODING_NONE && |
431 | 133k | code->input_format != VIPS_FORMAT_NOTSET && |
432 | 133k | in->BandFmt != code->input_format) { |
433 | 6.77k | if (vips_cast(in, &t[3], code->input_format, NULL)) |
434 | 0 | return -1; |
435 | 6.77k | in = t[3]; |
436 | 6.77k | } |
437 | | |
438 | 135k | if (in && |
439 | 135k | code->input_coding == VIPS_CODING_NONE && |
440 | 133k | code->input_interpretation != VIPS_INTERPRETATION_ERROR && |
441 | 5.31k | in->Type != code->input_interpretation) { |
442 | 67 | if (vips_colourspace(in, &t[4], |
443 | 67 | code->input_interpretation, NULL)) |
444 | 0 | return -1; |
445 | 67 | in = t[4]; |
446 | 67 | } |
447 | | |
448 | 135k | colour->n = 1; |
449 | 135k | colour->in = VIPS_ARRAY(object, 2, VipsImage *); |
450 | 135k | colour->in[0] = in; |
451 | 135k | colour->in[1] = NULL; |
452 | | |
453 | 135k | if (VIPS_OBJECT_CLASS(vips_colour_code_parent_class)->build(object)) |
454 | 3 | return -1; |
455 | | |
456 | 135k | return 0; |
457 | 135k | } |
458 | | |
459 | | static void |
460 | | vips_colour_code_class_init(VipsColourCodeClass *class) |
461 | 20 | { |
462 | 20 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
463 | 20 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
464 | | |
465 | 20 | gobject_class->set_property = vips_object_set_property; |
466 | 20 | gobject_class->get_property = vips_object_get_property; |
467 | | |
468 | 20 | vobject_class->nickname = "code"; |
469 | 20 | vobject_class->description = _("change color coding"); |
470 | 20 | vobject_class->build = vips_colour_code_build; |
471 | | |
472 | 20 | VIPS_ARG_IMAGE(class, "in", 1, |
473 | 20 | _("Input"), |
474 | 20 | _("Input image"), |
475 | 20 | VIPS_ARGUMENT_REQUIRED_INPUT, |
476 | 20 | G_STRUCT_OFFSET(VipsColourCode, in)); |
477 | 20 | } |
478 | | |
479 | | static void |
480 | | vips_colour_code_init(VipsColourCode *code) |
481 | 135k | { |
482 | 135k | code->input_coding = VIPS_CODING_NONE; |
483 | 135k | code->input_interpretation = VIPS_INTERPRETATION_ERROR; |
484 | 135k | code->input_format = VIPS_FORMAT_NOTSET; |
485 | 135k | } |
486 | | |
487 | 120 | G_DEFINE_ABSTRACT_TYPE(VipsColourDifference, vips_colour_difference, |
488 | 120 | VIPS_TYPE_COLOUR); |
489 | 120 | |
490 | 120 | static int |
491 | 120 | vips_colour_difference_build(VipsObject *object) |
492 | 120 | { |
493 | 69 | VipsColour *colour = VIPS_COLOUR(object); |
494 | 69 | VipsColourDifference *difference = VIPS_COLOUR_DIFFERENCE(object); |
495 | | |
496 | 69 | VipsImage **t; |
497 | 69 | VipsImage *left; |
498 | 69 | VipsImage *right; |
499 | | |
500 | 69 | t = (VipsImage **) vips_object_local_array(object, 12); |
501 | | |
502 | 69 | left = difference->left; |
503 | 69 | right = difference->right; |
504 | | |
505 | 69 | if (left) { |
506 | 69 | if (vips_image_decode(left, &t[0])) |
507 | 0 | return -1; |
508 | 69 | left = t[0]; |
509 | 69 | } |
510 | | |
511 | 69 | if (right) { |
512 | 69 | if (vips_image_decode(right, &t[1])) |
513 | 0 | return -1; |
514 | 69 | right = t[1]; |
515 | 69 | } |
516 | | |
517 | | /* Detach and reattach any extra bands. |
518 | | */ |
519 | 69 | colour->input_bands = 3; |
520 | | |
521 | 69 | if (left && |
522 | 69 | left->Type != difference->interpretation) { |
523 | 68 | if (vips_colourspace(left, &t[6], |
524 | 68 | difference->interpretation, NULL)) |
525 | 0 | return -1; |
526 | 68 | left = t[6]; |
527 | 68 | } |
528 | | |
529 | 69 | if (right && |
530 | 69 | right->Type != difference->interpretation) { |
531 | 68 | if (vips_colourspace(right, &t[7], |
532 | 68 | difference->interpretation, NULL)) |
533 | 0 | return -1; |
534 | 68 | right = t[7]; |
535 | 68 | } |
536 | | |
537 | | /* We only process float. |
538 | | */ |
539 | 69 | if (left && |
540 | 69 | left->BandFmt != VIPS_FORMAT_FLOAT) { |
541 | 0 | if (vips_cast_float(left, &t[8], NULL)) |
542 | 0 | return -1; |
543 | 0 | left = t[8]; |
544 | 0 | } |
545 | | |
546 | 69 | if (right && |
547 | 69 | right->BandFmt != VIPS_FORMAT_FLOAT) { |
548 | 0 | if (vips_cast_float(right, &t[9], NULL)) |
549 | 0 | return -1; |
550 | 0 | right = t[9]; |
551 | 0 | } |
552 | | |
553 | 69 | if (vips__sizealike(left, right, &t[10], &t[11])) |
554 | 0 | return -1; |
555 | 69 | left = t[10]; |
556 | 69 | right = t[11]; |
557 | | |
558 | 69 | colour->n = 2; |
559 | 69 | colour->in = VIPS_ARRAY(object, 3, VipsImage *); |
560 | 69 | colour->in[0] = left; |
561 | 69 | colour->in[1] = right; |
562 | 69 | colour->in[2] = NULL; |
563 | | |
564 | 69 | return VIPS_OBJECT_CLASS(vips_colour_difference_parent_class)-> |
565 | 69 | build(object); |
566 | 69 | } |
567 | | |
568 | | static void |
569 | | vips_colour_difference_class_init(VipsColourDifferenceClass *class) |
570 | 20 | { |
571 | 20 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
572 | 20 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
573 | | |
574 | 20 | gobject_class->set_property = vips_object_set_property; |
575 | 20 | gobject_class->get_property = vips_object_get_property; |
576 | | |
577 | 20 | vobject_class->nickname = "difference"; |
578 | 20 | vobject_class->description = _("calculate color difference"); |
579 | 20 | vobject_class->build = vips_colour_difference_build; |
580 | | |
581 | 20 | VIPS_ARG_IMAGE(class, "left", 1, |
582 | 20 | _("Left"), |
583 | 20 | _("Left-hand input image"), |
584 | 20 | VIPS_ARGUMENT_REQUIRED_INPUT, |
585 | 20 | G_STRUCT_OFFSET(VipsColourDifference, left)); |
586 | | |
587 | 20 | VIPS_ARG_IMAGE(class, "right", 2, |
588 | 20 | _("Right"), |
589 | 20 | _("Right-hand input image"), |
590 | 20 | VIPS_ARGUMENT_REQUIRED_INPUT, |
591 | 20 | G_STRUCT_OFFSET(VipsColourDifference, right)); |
592 | 20 | } |
593 | | |
594 | | static void |
595 | | vips_colour_difference_init(VipsColourDifference *difference) |
596 | 91 | { |
597 | 91 | VipsColour *colour = VIPS_COLOUR(difference); |
598 | | |
599 | 91 | colour->coding = VIPS_CODING_NONE; |
600 | 91 | colour->interpretation = VIPS_INTERPRETATION_B_W; |
601 | 91 | colour->format = VIPS_FORMAT_FLOAT; |
602 | 91 | colour->bands = 1; |
603 | 91 | } |
604 | | |
605 | | /* Called from iofuncs to init all operations in this dir. Use a plugin system |
606 | | * instead? |
607 | | */ |
608 | | void |
609 | | vips_colour_operation_init(void) |
610 | 40 | { |
611 | 40 | extern GType vips_colourspace_get_type(void); |
612 | 40 | extern GType vips_Lab2XYZ_get_type(void); |
613 | 40 | extern GType vips_XYZ2Lab_get_type(void); |
614 | 40 | extern GType vips_Lab2LCh_get_type(void); |
615 | 40 | extern GType vips_LCh2Lab_get_type(void); |
616 | 40 | extern GType vips_LCh2CMC_get_type(void); |
617 | 40 | extern GType vips_CMC2LCh_get_type(void); |
618 | 40 | extern GType vips_Yxy2XYZ_get_type(void); |
619 | 40 | extern GType vips_XYZ2Yxy_get_type(void); |
620 | 40 | extern GType vips_LabQ2Lab_get_type(void); |
621 | 40 | extern GType vips_Lab2LabQ_get_type(void); |
622 | 40 | extern GType vips_LabQ2LabS_get_type(void); |
623 | 40 | extern GType vips_LabS2LabQ_get_type(void); |
624 | 40 | extern GType vips_LabS2Lab_get_type(void); |
625 | 40 | extern GType vips_Lab2LabS_get_type(void); |
626 | 40 | extern GType vips_rad2float_get_type(void); |
627 | 40 | extern GType vips_float2rad_get_type(void); |
628 | 40 | extern GType vips_LabQ2sRGB_get_type(void); |
629 | 40 | extern GType vips_XYZ2sRGB_get_type(void); |
630 | 40 | extern GType vips_sRGB2scRGB_get_type(void); |
631 | 40 | extern GType vips_sRGB2HSV_get_type(void); |
632 | 40 | extern GType vips_HSV2sRGB_get_type(void); |
633 | 40 | extern GType vips_scRGB2XYZ_get_type(void); |
634 | 40 | extern GType vips_scRGB2BW_get_type(void); |
635 | 40 | extern GType vips_XYZ2scRGB_get_type(void); |
636 | 40 | extern GType vips_scRGB2sRGB_get_type(void); |
637 | 40 | extern GType vips_CMYK2XYZ_get_type(void); |
638 | 40 | extern GType vips_XYZ2CMYK_get_type(void); |
639 | 40 | extern GType vips_XYZ2Oklab_get_type(void); |
640 | 40 | extern GType vips_Oklab2XYZ_get_type(void); |
641 | 40 | extern GType vips_Oklab2Oklch_get_type(void); |
642 | 40 | extern GType vips_Oklch2Oklab_get_type(void); |
643 | 40 | extern GType vips_uhdr2scRGB_get_type(void); |
644 | 40 | extern GType vips_CICP2scRGB_get_type(void); |
645 | 40 | extern GType vips_scRGB2CICP_get_type(void); |
646 | 40 | extern GType vips_profile_load_get_type(void); |
647 | 40 | #ifdef HAVE_LCMS2 |
648 | 40 | extern GType vips_icc_import_get_type(void); |
649 | 40 | extern GType vips_icc_export_get_type(void); |
650 | 40 | extern GType vips_icc_transform_get_type(void); |
651 | 40 | #endif |
652 | 40 | extern GType vips_dE76_get_type(void); |
653 | 40 | extern GType vips_dE00_get_type(void); |
654 | 40 | extern GType vips_dECMC_get_type(void); |
655 | | |
656 | 40 | vips_colourspace_get_type(); |
657 | 40 | vips_Oklab2Oklch_get_type(); |
658 | 40 | vips_Oklch2Oklab_get_type(); |
659 | 40 | vips_Oklab2XYZ_get_type(); |
660 | 40 | vips_XYZ2Oklab_get_type(); |
661 | 40 | vips_Lab2XYZ_get_type(); |
662 | 40 | vips_XYZ2Lab_get_type(); |
663 | 40 | vips_Lab2LCh_get_type(); |
664 | 40 | vips_LCh2Lab_get_type(); |
665 | 40 | vips_LCh2CMC_get_type(); |
666 | 40 | vips_CMC2LCh_get_type(); |
667 | 40 | vips_XYZ2Yxy_get_type(); |
668 | 40 | vips_Yxy2XYZ_get_type(); |
669 | 40 | vips_LabQ2Lab_get_type(); |
670 | 40 | vips_Lab2LabQ_get_type(); |
671 | 40 | vips_LabQ2LabS_get_type(); |
672 | 40 | vips_LabS2LabQ_get_type(); |
673 | 40 | vips_LabS2Lab_get_type(); |
674 | 40 | vips_Lab2LabS_get_type(); |
675 | 40 | vips_rad2float_get_type(); |
676 | 40 | vips_float2rad_get_type(); |
677 | 40 | vips_LabQ2sRGB_get_type(); |
678 | 40 | vips_sRGB2scRGB_get_type(); |
679 | 40 | vips_scRGB2XYZ_get_type(); |
680 | 40 | vips_scRGB2BW_get_type(); |
681 | 40 | vips_sRGB2HSV_get_type(); |
682 | 40 | vips_HSV2sRGB_get_type(); |
683 | 40 | vips_XYZ2scRGB_get_type(); |
684 | 40 | vips_scRGB2sRGB_get_type(); |
685 | 40 | vips_CMYK2XYZ_get_type(); |
686 | 40 | vips_XYZ2CMYK_get_type(); |
687 | 40 | vips_uhdr2scRGB_get_type(); |
688 | 40 | vips_CICP2scRGB_get_type(); |
689 | 40 | vips_scRGB2CICP_get_type(); |
690 | 40 | vips_profile_load_get_type(); |
691 | 40 | #ifdef HAVE_LCMS2 |
692 | 40 | vips_icc_import_get_type(); |
693 | 40 | vips_icc_export_get_type(); |
694 | 40 | vips_icc_transform_get_type(); |
695 | 40 | #endif |
696 | 40 | vips_dE76_get_type(); |
697 | 40 | vips_dE00_get_type(); |
698 | 40 | vips_dECMC_get_type(); |
699 | 40 | } |