-
-
Notifications
You must be signed in to change notification settings - Fork 721
Crop and resize gainmaps automatically #4709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Designwise, I think the main question is whether this extra gainmap processing code should go into each operation as I've done here, or whether it should all be in Isolated in
|
and improve the gainmap handling
|
I talked myself around heh. I moved the gainmap handling into This means downstream libraries that don't use thumbnail will need to add some extra code. It's not a great deal of extra stuff. The change was: So 60 lines come out of the operators, 40 go into thumbnail. |
|
The extra code is pretty simple: if (vips_resize(in, &t[5], 1.0 / hshrink, "vscale", 1.0 / vshrink, NULL))
return -1;
in = t[5];
/* Also process the gainmap, if any.
*/
if ((gainmap = vips_image_get_gainmap(in))) {
if (vips_resize(gainmap, &t[15], 1.0 / hshrink,
"vscale", 1.0 / vshrink,
"kernel", VIPS_KERNEL_LINEAR,
NULL))
return -1;
vips_image_set_image(in, "gainmap", t[15]);
}So after calling some vips function that will change the image geometry (resize, crop, rotate, insert, flip, etc) you also need to fetch the optional gainmap and transform that in the same way. We either put this extra code in the operators themselves, or we leave it for higher levels (thumbnail in this case, sharp is another obvious one) to handle. Which solution is better? |
|
I tried cropping in python to see what it was like: #!/usr/bin/env python3
import sys
import pyvips
def get_gainmap(image):
if image.get_typeof("gainmap") != 0:
return image.get("gainmap")
elif image.get_typeof("gainmap-data") != 0:
buf = image.get("gainmap-data")
gainmap = pyvips.Image.jpegload_buffer(buf)
image.set_type(pyvips.GValue.image_type, "gainmap", gainmap)
return gainmap
else:
return None
left = int(sys.argv[3])
top = int(sys.argv[4])
width = int(sys.argv[5])
height = int(sys.argv[6])
image = pyvips.Image.uhdrload(sys.argv[1])
image = image.copy()
gainmap = get_gainmap(image)
if gainmap != None:
hscale = gainmap.width / image.width
vscale = gainmap.width / image.width
# crop image
image = image.crop(left, top, width, height)
# crop gainmap, if any
gainmap = get_gainmap(image)
if gainmap != None:
gainmap = gainmap.crop(left * hscale, top * vscale,
width * hscale, height * vscale)
image.set("gainmap", gainmap)
image.uhdrsave(sys.argv[2])We'd add Perhaps this should be moved back into the operators again? At least we'd have one implementation in one place that we could check. @lovell, what do you think? This would have a big effect on sharp. |
|
... an easy way to test is with eg.: To thumbnail and then extract the transformed gainmap, then: And use alt-right and alt-left to flip between the image and the gainmap. |
This PR tries a new strategy for gainmaps.
gainmap-datagainmapgainmapmetadata item, or made by decompressinggainmap-dataand also processeduhdrsave, if there's a decompressed gainmap, we recompress and attach, otherwise we use the pre-compressedgainmap-dataAs a result, gainmap processing is (almost) free (hopefully), and libraries downstream from libvips will get automatic gainmap handling.
Examples
Loading with shrink-on-load also shrinks the gainmap. You can see the small gainmap metadata item in the second vipsheader:
vipsthumbnailautomatically shrinks and crops the gainmap. You can see the thumbnail has a tiny gainmap.TODO
vips_rot()andvips_flip()soorientationhandling worksaffineetc.