-
-
Notifications
You must be signed in to change notification settings - Fork 715
Added write functionality for 2 and 4 bit tiff #1672
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
Conversation
Thank you very much for this nice work @MathemanFlo! I'm horribly busy this weekend, I'll try to look over it next Wednesday. |
I had a quick look, it seems nice! Regarding the API, how about deprecating You can tag operation arguments with In the _build method, you can use vips_object_argument_isset() to see if the caller used the deprecated argument and use that to adjust the default of the non-deprecated one. Old code will continue to work, and new code will only see the new interface. The |
Thank you for the positive feedback, your suggestions and hints. I definitely agree with you and I already started with removing squash from the internal code completely. Further more if you don't mind I would also like to add a load functionality for such files. Currently only paletted tiffs and 1 bit tiffs are supported. To support these kind of files no API changes are necessary. The code is similar to |
Sure, a matching loader is a good idea. pngsave needs a similar API for saving as 1/2/4 bits, though it includes palette generation and dithering, which I suppose you don't need. It would obviously be good to have the same API for both operations if possible. |
Al right. Thank you. Then I will clarify the cases in the code and add several sanity check in order to warn users in case of a wrong usage. For the conversion from LAB to LABQ what should be the bit depth? This does not make too much sense in this context... |
Now I added the things you suggested, the read functionality, improved the performance and added warnings in case the parameter was used incorrectly. The only remaining issue is the LAB issue described above. |
libvips/foreign/tiff2vips.c
Outdated
for( z = 0; z < 4; z++ ) { | ||
/* The grey shade is the value four times concatenated */ | ||
q[x] = (bits & 0xC0) | ((bits & 0xC0) >> 2) | ||
| ((bits & 0xC0) >> 4) | (bits >> 6); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could write this as:
VipsPel fourbits = (bits & 0xC0) | ((bits & 0xC0) >> 2);
q[x] = fourbits | (fourbits >> 4);
Though I've no idea if that gives a useful speedup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes one could do that for sure and I also think it is easier to understand. I'll change it in the next iteration of my proposal. Any further ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I guess you could remove the &
as well if you build from the low bits up:
VipsPel twobits = bits >> 6;
VipsPel fourbits = twobits | (twobits << 2);
VipsPel eightbits = fourbits | (fourbits << 4);
q[x] = eightbits;
@@ -605,10 +622,23 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer ) | |||
* MINISBLACK TIFFs where black is a 0 bit, but if you set @miniswhite, it | |||
* will use 0 for a white bit. Many pre-press applications only work with | |||
* images which use this sense. @miniswhite only affects one-bit images, it | |||
* does nothing for greyscale images. | |||
* does nothing for greyscale images. Consider @bitdepth for depths 1, 2 and 4. | |||
* | |||
* Set @squash to squash 3-band float CIELAB images down to 8-bit CIELAB. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line needs to change too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you are right but I didn't know how to properly change squash for the CIE stuff as commented above.
@@ -195,7 +195,8 @@ | |||
* - add PAGENUMBER support | |||
* 23/5/20 | |||
* - add support for subifd pyramid layers | |||
*/ | |||
* 8/6/20 | |||
* - add bitdepth support for 2 and 4 bit greyscale images |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a */
to close the comment.
libvips/foreign/vips2tiff.c
Outdated
@@ -1039,13 +1041,13 @@ ready_to_write( Wtiff *wtiff ) | |||
|
|||
/* "squash" float LAB down to LABQ. | |||
*/ | |||
if( wtiff->squash && | |||
if( wtiff->bitdepth == 1 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about allowing 8 as well here? Setting bitdepth to 1 to save 32-bit float as 8-bit uint seems unintuitive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok then l will do it as follows: Allow bitdepth = 8 for CIE LAB but not for integral images because there the proper way to change bitdepth from e.g. 16 to 8 is to change the type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! You'll need to allow 1
as well, of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do I have to allow 1
as well? CIE LAB allows for squash to 8 bit. I don't get your point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You set bitdepth = 1
if squash is on, so you'll need to allow that here for lab -> labq squash to still work (I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see I did it differently, I set bitdepth to 8 in case squash is on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But won't that break the old behaviour of squash writing 8-bit uchar as 1-bit? I'm probably confused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No you are not. I'm the one who missed that and now I get your point. Thank you so much.
libvips/foreign/vips2tiff.c
Outdated
!(wtiff->ready->Coding == VIPS_CODING_NONE && | ||
if( wtiff->bitdepth && (wtiff->bitdepth == 1 || wtiff->bitdepth == 2 | ||
|| wtiff->bitdepth == 4 ) | ||
&& !(wtiff->ready->Coding == VIPS_CODING_NONE && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just use wtiff->bitdepth
here, you've checked the values in the test above.
libvips/foreign/vips2tiff.c
Outdated
if( !wtiff->miniswhite ) { //avoid unnecessary branches | ||
for( x = 0; x < n; x++ ) { | ||
bits <<= 2; | ||
bits |= p[x] >> 6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could do this as:
bits |= (p[x] >> 6) ^ mask;
where mask
is wtiff->miniswhite ? 3 : 0
somewhere outside the loop. It would save the loop copy-paste.
libvips/foreign/vips2tiff.c
Outdated
if( !wtiff->miniswhite ) { //avoid unnecessary branches | ||
for( x = 0; x < n; x++ ) { | ||
bits <<= 4; | ||
bits |= p[x] >> 4; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. I don't like the loop duplication :(
Sorry about the delay, I finally read the whole thing again carefully. You did a great job! I should have started a review, I ended up with more comments than I expected. There are some small style issues too (line length, tab size, etc.) but they can be fixed later, of course. We'll need some tests too. Would you like to add some, or shall I? png, spng and ppm save have a I agree about bitdepth being confusing for (for example) saving a uint32 image as a uint16 TIFF. Unfortunately I can't think of a name that expresses the meaning more clearly. |
Thank you very much for all your amazing comments and for your help. I think I addressed the things you mentioned and I also tried to fix the style issues.
To be honest I have no better name and maybe bitdepth is not the worst one because it would allow features like the conversion you described. |
You're right, squash was planned for pngsave, but hasn't gone in yet. ppmsave can only save one bit images, but it should use the same API for consistency. We can fix that later. Thanks for the test images, let's revise the test suite for this in another PR. It all looks fine now, barring some tiny formatting. Let's merge so the fuzzers can start work. Nice work! |
I reworked the things to pack and unpack bits to make them a bit smaller and neater, it might be worth you testing git master again to make sure I didn't foul up. I added some tests as well, and credited you in the changelog. |
Thank you for your awesome work and your incredible support. Initially I had exactly an |
we were not adjusting for pixel size, thanks MathemanFlo see #1672 (comment)
Ooop, you're right, I've comitted a fix, thanks! (don't be too impressed, I'm not normally so responsive, we're just trying to clear the backlog ready for 8.10) |
I added bitdepth to ppmsave already. I think 8.10 just needs testing now, and there's one final PR to land. |
I added support for writing 2 and 4 bit tiffs in both modes: minisblack and miniswhite.
To do so I added the new option
bitdepth
to support 1, 2 and 4 bit tiff output.I did not change the behavior of squash as it would break existing code but tried to be compatible with it in the sense that e.g. in case of 2 bit: values from 0 to 63 are treated as 0, 64 to 127 as 1 and so on. In fact one could merge the whole internal implementation of squash into bitdepth and further more bitdepth is flexible enough to allow for extensions to other bit depths and/or formats (e.g. png) in the future, too.
To implement this feature I added functions
eightbit2twobit
andeightbit2fourbit
similiar toeightbit2onebit
which could be merged into one function but I think this approach is more efficient as it avoids unnecessary branches and variables in the two and four bit case.As this is my first contribution to libvips I welcome any feedback.