Support PNG and/or “short” BI_BITFIELDS DIBv5 when pasting images (pixel data shifted when copy/pasting from Paint.NET)
Categories
(Core :: Graphics: ImageLib, defect)
Tracking
()
People
(Reporter: mercury13, Unassigned)
References
(Depends on 1 open bug)
Details
Attachments
(4 files)
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Steps to reproduce:
- Go to any site that pastes images from clipboard, e.g. https://madebyevan.com/clipboard-test/
(first seen on Github) - Copy image from Paint.NET (other software does not work)
- Paste at the site.
Actual results:
Pixel data is strangely shifted
Expected results:
Image should be copy-pasted as-is.
Cannot repeat on Win+Sh+S and Fx, XnView and Fx, Pain.NET and Vivaldi.
UPD. Probably Paint.NET is to blame, as I repeated on Paint.NET and XnView, but why?
![]() |
||
Updated•7 months ago
|
Men at Paint.NET forum went to conclusion that something happened to DIBv5, but I cannot confirm. As pixel data is normal at the first glance (and IDK how to save it to file), maybe a common clipboard library does tricks?
More data. BI_BITFIELDS compression is commonly parsed badly.
Confirmed DIB or DIBv5 problem, cannot investigate further. CLIPBRD.EXE from old Windows does the same, but why?
From Paint.NET:
Because they are incorrectly parsing the BITMAPV5HEADER data. They are reading an additional 3 4-byte values at the end of the header, which is where the first 3 pixels of the bottom row are supposed to be. The DIB has its pixels in left-to-right, bottom-to-top order (which is oddly the standard for DIBs). So the image shifts left by 3 pixels because they're skipping 3 pixels worth of data, and then the rightmost 3 pixels of the bottom row are pulled from the left edge of the next row. And so on up until the last 3 pixels (the top rightmost pixels) are garbage values -- so this is also technically a buffer overrun bug on their part (which can actually be a serious security concern depending on context).
Also, a great way to remove this type of bug -- because DIBs and DIBV5s are a monstrous pain to work with and it's no surprise they got it wrong because lots of apps also get it wrong -- is to process the PNG clipboard format instead. It's a PNG ... should be very easily parsable by an app like Paint Tool SAI.
Paint.NET puts PNG onto the clipboard first for a reason: so that other apps will (hopefully) prioritize it over the DIB variants that are so error prone across the whole ecosystem of Windows apps.
Confirmed problem: Lots of software insert three dwords to BI_BITFIELDS DIBv5 at offsets 7C…87. They sat in image data old DIB there because they were absent in header, but in DIBv5 they are in header, at offset 28…37 (bV5RedMask…bV5AlphaMask).
But those twelve bytes are so commonly used that the only way to check whether DIBv5 is good or bad is…
those_three_dwords_present = (bV5Compression == BI_BITFIELDS) && ((format < DIBv5) || ([data_size] ≥ bV5Size + bV5SizeImage + 12));
And why you’ve got that black stripe? DIB is written bottom-to-top, and Fx is critical software and constantly checks for buffer overruns. When three dwords are erroneously skipped, it tries to get a byte range for line beyond limit, and one function says “Nope”, and the other does nothing in response for this “Nope”.
Reporter | ||
Comment 10•7 months ago
|
||
I’ll consult author of Paint.NET.
Reporter | ||
Comment 11•7 months ago
|
||
So Paint.NET is surely wrong.
Reporter | ||
Comment 12•7 months ago
|
||
But you can also do something — prefer PNG over DIB.
Reporter | ||
Comment 13•7 months ago
|
||
Or you can check for too short buffer and hunt for other format.
Updated•7 months ago
|
Reporter | ||
Comment 14•7 months ago
|
||
I’ll repeat what I see.
- Paint.NET is surely wrong, as lots of software, incl. W10’s screenshot function, create/require these twelve bytes.
- But you can do something from your behalf: prefer PNG over DIB, detect too short DIBv5 and fall back to other formats.
Reporter | ||
Comment 15•7 months ago
|
||
Criterion for short DIB is simple: stream_size < header_size (dword 00) + palette_size (computed by header) + image_data_size (dword 0x14)
Reporter | ||
Comment 16•7 months ago
|
||
Possibly also wrong image_data_size for uncompressed data, ≠ width·height·bpp.
Reporter | ||
Comment 17•7 months ago
|
||
More data, interesting!
Windows itself always creates long DIBv5 (e.g. from PrintScreen, DIB). But if you make short DIBv5, it’ll happily recognize short format and convert it to other formats (BITMAP/DIB).
Reporter | ||
Comment 18•7 months ago
|
||
And if you make long DIBv5… it will convert badly! Strange.
So everything I can say. DIBv5 is so broken that you should either support both short and long DIBv5, or use other formats instead.
Reporter | ||
Comment 19•7 months ago
|
||
So, here’s the info and why you should support both short and long DIBv5. Or prefer more manageable formats like PNG. Sorry for being a chameleon here.
Copy in old DIB format (AND NO OTHER FORMATS). Everything works, Windows successfully auto-converts to Bitmap and LONG DIBv5.
Copy in BITMAP format. Same.
Copy in SHORT DIBv5 format. Windows successfully auto-converts to Bitmap and DIB. Bad: Fx, XnView. Good: Paint.NET, some old Photoshop, GIMP, Vivaldi
Copy in LONG DIBv5 format. Auto-conversion to Bitmap and DIB incorrect. Bad: Vivaldi, Photoshop, GIMP (probably use Bitmap/DIB that are incorrect, won’t blame from the start). Good: Fx, XnView
Create different images in BITMAP/DIB/DIBv5 to see who. Vivaldi, GIMP → DIB. Photoshop → BITMAP. Fx → DIBv5, parsing long format only. XnView → DIBv5, long only, with its own bugs.
I played with this program: https://github.com/Mercury13/clipboard-demo
DIBv5 is pink. DIB is cyan. BITMAP is white.
Updated•7 months ago
|
Reporter | ||
Comment 20•7 months ago
|
||
In a nutshell. Screenshot, CLIPBRD.EXE, auto-conversion from BITMAP/DIB produce/require long DIBv5.
Auto-conversion from DIBv5 requires short DIBv5.
That’s why you need to CREATE long, but ACCEPT both.
Comment 21•7 months ago
|
||
This is fascinating, and very relevant to my work on fixing the clipboard handling in https://bugzilla.mozilla.org/show_bug.cgi?id=460969, thank you for the information :)
Reporter | ||
Comment 22•7 months ago
|
||
Ashley Hale [:ahale]
Thank you.
UPD. IDK how to copy data in alternate formats, and need as simple example as possible, so I didn’t test PNG. I just tested three standard formats, BITMAP, DIB and DIBv5. Did not even test transparency for now.
Reporter | ||
Comment 23•7 months ago
|
||
Ashley, you made me check COPYING transparent images, lady.
Translucent DIBv5 short ONLY:
- Totally OK: Paint.NET, Vivaldi
- Shifted pixel data: Fx, XnView
- No transparency: some old Photoshop, GIMP
(Let me skip DIBv5 long, as it won’t make any difference)
Translucent DIB ONLY:
- OK: Paint.NET, Fx, Vivaldi
- No transparency: XnView, Photoshop, GIMP
Translucent BITMAP ONLY:
- OK: Paint.NET
- No transparency: Fx, Photoshop
- No transparency, strange pixel data troubles: Vivaldi, GIMP
Probably Windows works by converting BITMAP → long DIBv5 → buggy DIB (both Vivaldi and GIMP prefer DIB).
How other image editors work here:
Photoshop: creates lot of formats, no one understands except Photoshop itself
GIMP: creates PNG + BI_RGB DIB/long DIBv5 w/transparency, understood by Paint.NET and Vivaldi
Paint.NET: creates PNG + BI_BITFIELDS DIB/short DIBv5, understood by everyone except Photoshop (Fx/XnView make artifacts, as always)
XnView: creates correct but premultiplied images, don’t even bother to support (Paint.NET managed to bother)
What and in which order should you COPY to avoid most bugs?
ALL FOUR FORMATS in any order: PNG, BITMAP, DIB, DIBv5
But that’s copying, not pasting. When pasting, it’s better to understand PNG and/or short DIBv5.
Reporter | ||
Comment 24•7 months ago
|
||
GIMP: I said long DIBv5? As it’s BI_RGB, there’s no difference between long and short.
Description
•