Skip to content

Commit a7e8f46

Browse files
jcupittkleisauke
andauthored
fix linear resize of 16-bit rgba (#4467)
* fix linear resize of 16-bit rgba We were changing the interpretation in icc_import and icc_export, but we were not rescaling the alpha. As a result, 16-bit RGBA images had a alpha of 65535 in PCS, not 255. This PR moves alpha channel scaling into the base VipsColour class, so we get correct scaling automatically, and moves XYZ <-> scRGB conversion back on top of VipsColourCode, partially reverting #3627 see #4343 * Update libvips/colour/colour.c Co-authored-by: Kleis Auke Wolthuizen <github@kleisauke.nl> * review comments --------- Co-authored-by: Kleis Auke Wolthuizen <github@kleisauke.nl>
1 parent 9df3b96 commit a7e8f46

File tree

3 files changed

+58
-258
lines changed

3 files changed

+58
-258
lines changed

libvips/colour/XYZ2scRGB.c

+12-113
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,10 @@
4747

4848
#include "pcolour.h"
4949

50-
/* We can't use VipsColourCode as our parent class. We want to handle
51-
* alpha ourselves.
52-
*/
53-
54-
typedef struct _VipsXYZ2scRGB {
55-
VipsOperation parent_instance;
56-
57-
VipsImage *in;
58-
VipsImage *out;
59-
} VipsXYZ2scRGB;
50+
typedef VipsColourTransform VipsXYZ2scRGB;
51+
typedef VipsColourTransformClass VipsXYZ2scRGBClass;
6052

61-
typedef VipsOperationClass VipsXYZ2scRGBClass;
62-
63-
G_DEFINE_TYPE(VipsXYZ2scRGB, vips_XYZ2scRGB, VIPS_TYPE_OPERATION);
53+
G_DEFINE_TYPE(VipsXYZ2scRGB, vips_XYZ2scRGB, VIPS_TYPE_COLOUR_TRANSFORM);
6454

6555
/* We used to have the comment:
6656
@@ -79,12 +69,12 @@ G_DEFINE_TYPE(VipsXYZ2scRGB, vips_XYZ2scRGB, VIPS_TYPE_OPERATION);
7969
*/
8070

8171
static void
82-
vips_XYZ2scRGB_line(float *restrict q, float *restrict p,
83-
int extra_bands, int width)
72+
vips_XYZ2scRGB_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width)
8473
{
85-
int i, j;
74+
float *restrict p = (float *) in[0];
75+
float *restrict q = (float *) out;
8676

87-
for (i = 0; i < width; i++) {
77+
for (int i = 0; i < width; i++) {
8878
const float X = p[0];
8979
const float Y = p[1];
9080
const float Z = p[2];
@@ -100,118 +90,27 @@ vips_XYZ2scRGB_line(float *restrict q, float *restrict p,
10090
q[2] = B;
10191

10292
q += 3;
103-
104-
for (j = 0; j < extra_bands; j++)
105-
q[j] = VIPS_CLIP(0, p[j] / 255.0, 1.0);
106-
p += extra_bands;
107-
q += extra_bands;
10893
}
10994
}
11095

111-
static int
112-
vips_XYZ2scRGB_gen(VipsRegion *out_region,
113-
void *seq, void *a, void *b, gboolean *stop)
114-
{
115-
VipsRegion *ir = (VipsRegion *) seq;
116-
VipsRect *r = &out_region->valid;
117-
VipsImage *in = ir->im;
118-
119-
int y;
120-
121-
if (vips_region_prepare(ir, r))
122-
return -1;
123-
124-
VIPS_GATE_START("vips_XYZ2scRGB: work");
125-
126-
for (y = 0; y < r->height; y++) {
127-
float *p = (float *)
128-
VIPS_REGION_ADDR(ir, r->left, r->top + y);
129-
float *q = (float *)
130-
VIPS_REGION_ADDR(out_region, r->left, r->top + y);
131-
132-
vips_XYZ2scRGB_line(q, p, in->Bands - 3, r->width);
133-
}
134-
135-
VIPS_GATE_STOP("vips_XYZ2scRGB: work");
136-
137-
return 0;
138-
}
139-
140-
static int
141-
vips_XYZ2scRGB_build(VipsObject *object)
142-
{
143-
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object);
144-
VipsXYZ2scRGB *XYZ2scRGB = (VipsXYZ2scRGB *) object;
145-
146-
VipsImage **t = (VipsImage **) vips_object_local_array(object, 2);
147-
148-
VipsImage *in;
149-
VipsImage *out;
150-
151-
if (VIPS_OBJECT_CLASS(vips_XYZ2scRGB_parent_class)->build(object))
152-
return -1;
153-
154-
in = XYZ2scRGB->in;
155-
if (vips_check_bands_atleast(class->nickname, in, 3))
156-
return -1;
157-
158-
if (vips_cast_float(in, &t[0], NULL))
159-
return -1;
160-
in = t[0];
161-
162-
out = vips_image_new();
163-
if (vips_image_pipelinev(out,
164-
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) {
165-
g_object_unref(out);
166-
return -1;
167-
}
168-
out->Type = VIPS_INTERPRETATION_scRGB;
169-
out->BandFmt = VIPS_FORMAT_FLOAT;
170-
171-
if (vips_image_generate(out,
172-
vips_start_one, vips_XYZ2scRGB_gen, vips_stop_one,
173-
in, XYZ2scRGB)) {
174-
g_object_unref(out);
175-
return -1;
176-
}
177-
178-
g_object_set(object, "out", out, NULL);
179-
180-
return 0;
181-
}
182-
18396
static void
18497
vips_XYZ2scRGB_class_init(VipsXYZ2scRGBClass *class)
18598
{
186-
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
18799
VipsObjectClass *object_class = (VipsObjectClass *) class;
188-
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class);
189-
190-
gobject_class->set_property = vips_object_set_property;
191-
gobject_class->get_property = vips_object_get_property;
100+
VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class);
192101

193102
object_class->nickname = "XYZ2scRGB";
194103
object_class->description = _("transform XYZ to scRGB");
195-
object_class->build = vips_XYZ2scRGB_build;
196-
197-
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
198104

199-
VIPS_ARG_IMAGE(class, "in", 1,
200-
_("Input"),
201-
_("Input image"),
202-
VIPS_ARGUMENT_REQUIRED_INPUT,
203-
G_STRUCT_OFFSET(VipsXYZ2scRGB, in));
204-
205-
VIPS_ARG_IMAGE(class, "out", 100,
206-
_("Output"),
207-
_("Output image"),
208-
VIPS_ARGUMENT_REQUIRED_OUTPUT,
209-
G_STRUCT_OFFSET(VipsXYZ2scRGB, out));
105+
colour_class->process_line = vips_XYZ2scRGB_line;
210106
}
211107

212108
static void
213109
vips_XYZ2scRGB_init(VipsXYZ2scRGB *XYZ2scRGB)
214110
{
111+
VipsColour *colour = VIPS_COLOUR(XYZ2scRGB);
112+
113+
colour->interpretation = VIPS_INTERPRETATION_scRGB;
215114
}
216115

217116
/**

libvips/colour/colour.c

+31-23
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,6 @@ vips_colour_build(VipsObject *object)
165165
VipsImage **extra_bands;
166166
VipsImage *out;
167167

168-
int i;
169-
170168
#ifdef DEBUG
171169
printf("vips_colour_build: ");
172170
vips_object_print_name(object);
@@ -177,11 +175,10 @@ vips_colour_build(VipsObject *object)
177175
return -1;
178176

179177
if (colour->n > MAX_INPUT_IMAGES) {
180-
vips_error(class->nickname,
181-
"%s", _("too many input images"));
178+
vips_error(class->nickname, "%s", _("too many input images"));
182179
return -1;
183180
}
184-
for (i = 0; i < colour->n; i++)
181+
for (int i = 0; i < colour->n; i++)
185182
if (vips_image_pio_input(colour->in[i]))
186183
return -1;
187184

@@ -201,7 +198,7 @@ vips_colour_build(VipsObject *object)
201198
VipsImage **new_in = (VipsImage **)
202199
vips_object_local_array(object, colour->n);
203200

204-
for (i = 0; i < colour->n; i++) {
201+
for (int i = 0; i < colour->n; i++) {
205202
if (vips_check_bands_atleast(class->nickname,
206203
in[i], colour->input_bands))
207204
return -1;
@@ -246,39 +243,50 @@ vips_colour_build(VipsObject *object)
246243
if (vips_image_generate(out,
247244
vips_start_many, vips_colour_gen, vips_stop_many,
248245
in, colour)) {
249-
g_object_unref(out);
246+
VIPS_UNREF(out);
250247
return -1;
251248
}
252249

253250
/* Reattach higher bands, if necessary. If we have more than one input
254251
* image, just use the first extra bands.
255252
*/
256-
for (i = 0; i < colour->n; i++)
253+
for (int i = 0; i < colour->n; i++)
257254
if (extra_bands[i]) {
258-
VipsImage *t1, *t2;
255+
VipsImage **t = (VipsImage **) vips_object_local_array(object, 3);
256+
257+
double max_alpha_before =
258+
vips_interpretation_max_alpha(extra_bands[i]->Type);
259+
double max_alpha_after =
260+
vips_interpretation_max_alpha(out->Type);
261+
262+
VipsImage *alpha;
259263

260-
/* We can't just reattach the extra bands: they might
261-
* be float (for example) and we might be trying to
262-
* make a short image. Cast extra to match the body of
263-
* the image.
264+
alpha = extra_bands[i];
265+
266+
/* Rescale, if the alpha scale has changed.
264267
*/
268+
if (max_alpha_before != max_alpha_after) {
269+
if (vips_linear1(alpha, &t[0],
270+
max_alpha_after / max_alpha_before, 0.0, NULL)) {
271+
VIPS_UNREF(out);
272+
return -1;
273+
}
274+
alpha = t[0];
275+
}
265276

266-
if (vips_cast(extra_bands[i], &t1, out->BandFmt,
267-
"shift", TRUE,
268-
NULL)) {
269-
g_object_unref(out);
277+
if (vips_cast(alpha, &t[1], out->BandFmt, NULL)) {
278+
VIPS_UNREF(out);
270279
return -1;
271280
}
281+
alpha = t[1];
272282

273-
if (vips_bandjoin2(out, t1, &t2,
274-
NULL)) {
275-
g_object_unref(t1);
276-
g_object_unref(out);
283+
if (vips_bandjoin2(out, alpha, &t[2], NULL)) {
284+
VIPS_UNREF(out);
277285
return -1;
278286
}
279287
g_object_unref(out);
280-
g_object_unref(t1);
281-
out = t2;
288+
out = t[2];
289+
t[2] = NULL;
282290

283291
break;
284292
}

0 commit comments

Comments
 (0)