Visitar URL original
Improve gain map support for rotate-then-extract #4606 · lovell/sharp@49f4903 · GitHub
Skip to content

Commit 49f4903

Browse files
committed
Improve gain map support for rotate-then-extract #4606
1 parent 0e2e55e commit 49f4903

2 files changed

Lines changed: 77 additions & 1 deletion

File tree

‎src/pipeline.cc‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ class PipelineWorker : public Napi::AsyncWorker {
9494
// Calculate angle of rotation
9595
VipsAngle rotation = VIPS_ANGLE_D0;
9696
VipsAngle autoRotation = VIPS_ANGLE_D0;
97+
VipsAngle gainMapRotation = VIPS_ANGLE_D0;
9798
bool autoFlop = false;
99+
bool gainMapFlip = false;
100+
bool gainMapFlop = false;
98101

99102
if (baton->input->autoOrient) {
100103
// Rotate and flip image according to Exif orientation
@@ -115,11 +118,13 @@ class PipelineWorker : public Napi::AsyncWorker {
115118
MultiPageUnsupported(nPages, "Rotate");
116119
}
117120
image = image.rot(autoRotation);
121+
gainMapRotation = autoRotation;
118122
autoRotation = VIPS_ANGLE_D0;
119123
}
120124
if (autoFlop) {
121125
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
122126
autoFlop = false;
127+
gainMapFlop = true;
123128
}
124129
}
125130

@@ -128,20 +133,24 @@ class PipelineWorker : public Napi::AsyncWorker {
128133
if (baton->flip) {
129134
image = image.flip(VIPS_DIRECTION_VERTICAL);
130135
baton->flip = false;
136+
gainMapFlip = true;
131137
}
132138
if (baton->flop) {
133139
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
134140
baton->flop = false;
141+
gainMapFlop = true;
135142
}
136143
if (rotation != VIPS_ANGLE_D0) {
137144
if (rotation != VIPS_ANGLE_D180) {
138145
MultiPageUnsupported(nPages, "Rotate");
139146
}
140147
image = image.rot(rotation);
148+
gainMapRotation = rotation;
141149
rotation = VIPS_ANGLE_D0;
142150
}
143151
if (baton->rotationAngle != 0.0) {
144152
MultiPageUnsupported(nPages, "Rotate");
153+
KeepGainMapUnsupported(baton->keepGainMap, "Rotate");
145154
std::vector<double> background;
146155
std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, false);
147156
image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background)).copy_memory();
@@ -307,6 +316,15 @@ class PipelineWorker : public Napi::AsyncWorker {
307316
if (image.get_typeof("gainmap-scale-factor") == G_TYPE_INT) {
308317
gainMapScaleFactor = image.get_int("gainmap-scale-factor");
309318
}
319+
if (gainMapFlip) {
320+
gainMap = gainMap.flip(VIPS_DIRECTION_VERTICAL);
321+
}
322+
if (gainMapFlop) {
323+
gainMap = gainMap.flip(VIPS_DIRECTION_HORIZONTAL);
324+
}
325+
if (gainMapRotation != VIPS_ANGLE_D0) {
326+
gainMap = gainMap.rot(gainMapRotation);
327+
}
310328
if (baton->topOffsetPre != -1) {
311329
gainMap = gainMap.extract_area(
312330
baton->leftOffsetPre / gainMapScaleFactor, baton->topOffsetPre / gainMapScaleFactor,
@@ -563,6 +581,7 @@ class PipelineWorker : public Napi::AsyncWorker {
563581
// Rotate post-extract non-90 angle
564582
if (!baton->rotateBefore && baton->rotationAngle != 0.0) {
565583
MultiPageUnsupported(nPages, "Rotate");
584+
KeepGainMapUnsupported(baton->keepGainMap, "Rotate");
566585
image = sharp::StaySequential(image);
567586
std::vector<double> background;
568587
std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, shouldPremultiplyAlpha);

‎test/unit/gain-map.js‎

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,57 @@ suite('Gain maps', () => {
259259
);
260260
});
261261

262+
test('Can be detached, rotated and reattached', async (t) => {
263+
t.plan(4);
264+
265+
const data = await sharp(fixtures.inputJpgWithGainMap)
266+
.keepGainMap()
267+
.rotate(90)
268+
.extract({ left: 2000, top: 3000, width: 48, height: 32 })
269+
.toBuffer();
270+
271+
const metadata = await sharp(data).metadata();
272+
t.assert.strictEqual(metadata.format, 'jpeg');
273+
t.assert.strictEqual(typeof metadata.gainMap, 'object');
274+
t.assert.ok(Buffer.isBuffer(metadata.gainMap.image));
275+
276+
const {
277+
format,
278+
width,
279+
height,
280+
channels,
281+
depth,
282+
space,
283+
hasProfile,
284+
chromaSubsampling,
285+
} = await sharp(metadata.gainMap.image).metadata();
286+
287+
t.assert.deepEqual(
288+
{
289+
format,
290+
width,
291+
height,
292+
channels,
293+
depth,
294+
space,
295+
hasProfile,
296+
chromaSubsampling,
297+
},
298+
{
299+
format: 'jpeg',
300+
width: 12,
301+
height: 8,
302+
channels: 1,
303+
depth: 'uchar',
304+
space: 'b-w',
305+
hasProfile: false,
306+
chromaSubsampling: '4:4:4',
307+
},
308+
);
309+
});
310+
262311
test('Cannot keep existing gain map with certain operations', async (t) => {
263-
t.plan(3);
312+
t.plan(4);
264313

265314
await t.assert.rejects(
266315
sharp(fixtures.inputJpgWithGainMap)
@@ -289,6 +338,14 @@ suite('Gain maps', () => {
289338
.toBuffer(),
290339
/Trim is not supported when keeping gain maps/
291340
);
341+
342+
await t.assert.rejects(
343+
sharp(fixtures.inputJpgWithGainMap)
344+
.keepGainMap()
345+
.rotate(1)
346+
.toBuffer(),
347+
/Rotate is not supported when keeping gain maps/
348+
);
292349
});
293350

294351
test('other metadata can be retained when keeping gain map', async (t) => {

0 commit comments

Comments
 (0)