-
Posts
20,632 -
Joined
-
Last visited
-
Days Won
376
Everything posted by Rick Brewster
-
So from what I can tell for BMP storage, you include the 3 bitmasks when doing BITMAPV5HEADER + BI_BITFIELDS. This is with straight alpha. When copying to the clipboard as a CF_DIBV5, you do not include the 3 bitmasks when doing BITMAPV5HEADER + BI_BITFIELDS. This is also with straight alpha. Chrome does it differently. For an image with transparency (e.g. the forum logo, https://content.invisioncic.com/r125076/monthly_2020_09/getpaint_whitetext.png.9b52024e6a4fb3fcc770ebb1beb86df7.png), it will copy to the clipboard specifying BI_RGB, and 32-bits, and then it will use premultiplied pixels. This also seems to be Firefox's strategy. This seems to be the de facto spec. For whatever reason that's what other imaging apps are doing. Ergo, PDN's current implementation is, for lack of a better word ... correct.
-
I'm getting similar results. If I use WIC to save a BMP, and then skip past the BITMAPFILEHEADER and place the remaining bytes on the clipboard, and paste back into various apps: Paint.NET: Works fine, obviously. WIC can handle its own output. mspaint: Refuses to paste the image GIMP: No transparency, and shifted right by 3 pixels Krita: Includes transparency, still shifted right by 3 pixels This is for a BITMAPV5HEADER bitmap w/ BI_BITFIELDS.
-
It doesn't look like it's actually be edited, there's just a bunch of commits for infra stuff: https://github.com/MicrosoftDocs/win32/commits/docs/desktop-src/gdi/bitmap-header-types.md The documentation for BITMAPV5HEADER still states, in several different ways (but of course never really directly saying it) that this is not the way it should be done. It does say that bV5ClrUsed can be non-zero for a 32-bpp DIB, but that those color values are to be used for some kind of palette optimization (obviously a legacy consideration at this point). It also has a nonsensical explanation for how color profiles should be encoded (3rd paragraph in Remarks) ... I actually implemented color profiles support in the v5.1 codebase for BMP files as part of the color management feature work, but it's disabled because that's a Pandora's box I'm not willing to open yet. And yet, as you point out, the Bitmap Header Types page does explicitly say that there should be 3 color mask values in addition to the embedded color mask values (bV5RedMask et. al.). I'm still not convinced that the 2nd copy of the masks is supposed to be there, other than the "normalization of deviancy" Wikipedia link you provided -- in other words, the spec is de facto the implementation, which was accidentally crowdsourced out to every application or library that handles DIBV5s. And everyone got it wrong in a multitude of different ways and we just have to deal with it now. So we must find a way to unambiguously encode and decode in a way that achieves maximum compatibility. At least for decoding you can look at the total size of the payload (header + bitmap + anything else) -- if there's an extra 12 bytes then assume that the 3 masks are there, otherwise they're not. Easy enough. On the Paint.NET side I haven't been seeing any issues here, so my code for that seems to be working (knock on wood). Encoding is another matter because then you're contending with the decoding implementation of every other app. That's currently where the trouble is. And there isn't really a good unit test for this because it would require obtaining all of those other apps, something I am not interested in paying for or dealing with. At least for now we can probably focus on Chrome, Firefox, Office (Word, etc.), GIMP, Krita, mspaint, and any other popular free(ware) software. I'll reopen the issue over on GitHub and poke into this some more for the 5.0.13 servicing release. It sounds like what you're saying is that the fix is to add in the 3 masks. It may also make sense to just punt this over to WIC -- have it save a BMP to an in-memory stream, skip past the BITMAPFILEHEADER, and copy the remaining bytes to the clipboard.
-
A practical solution might be to write a little program that implements something called a clipboard hook. Basically it gets notified whenever the clipboard changes. When it sees a DIBV5 put onto the clipboard, it will either 1) Remove it if a PNG is also on the clipboard, or 2) Decode the DIBV5, re-encode as PNG, put the PNG on the clipboard, and remove the DIBV5. Obviously this would break pasting into apps that don't support PNG, but I'm sure things could be filtered with allow/block lists. Anyway this is just an idea.
-
Because DIB(non-V5) doesn't support transparency, and not all apps handle PNG. When I say "it's a legacy format" I mean that we shouldn't be shedding blood and tears over getting it right, we should just consider it to be a lost cause and accept it how it is, and encourage other apps to support and prefer PNG. You could also say that cash is legacy and problematic compared to debit/credit cards. Why keep using it then? Because it's still useful for a variety of reasons, and we're not yet to the point where we can just stop. And maybe we'll never reach that point, either for DIBV5 or cash, and that's something we have to accept. It's not a lost cause, we can still improve the state of the world with respect to either, but there will always be some app that someone wants to use that only supports DIB/DIBV5, just like there will always be someone out there who only has cash or some merchant who isn't willing/able to handle cards. (Also, there isn't yet a law banning cash in favor of cards, at least not in the U.S.) (I'm not sure cash vs. card is a proper good analogy, and I'm not trying to stake out a political position on the matter, but hopefully you got the point) Another way to improve this situation would be for Windows itself to step in and fix up / homogenize the clipboard data, possibly with compatibility shims for legacy apps which are known to do the wrong thing.
-
Basically it's like this, Paint.NET is placing a correctly formed DIBV5 on the clipboard. I'm going to assume this unless proven otherwise, such as via an in-depth technical discussion by experts here at https://forums.getpaint.net/topic/122848-pasting-dibv5-image/) Apps have varying degrees of buggy ways of copying and pasting DIBV5s DIBV5 is supposed to be a simple format, but it isn't due to how it's evolved over the last ~30 years and its poor documentation/specification This led to DIBV5 essentially being an ambiguously defined format due to both its buggy specification and inconsistent implementations across many, many apps PNG does not have any of these issues and is far superior in all ways except for encoding performance (i.o.w. how long it takes to copy it to the clipboard). This could probably be rectified if we got a PNG library with a "super fast compression" mode (which may already exist, although WIC certainly doesn't support that unfortunately). Therefore, if a PNG is on the clipboard alongside the DIBv5, just use the PNG. All this pain would be avoided if Firefox and Paint Tool SAI would just do that. DIBV5 should be considered a legacy clipboard format at this point, only included for the sake of apps that don't (yet) handle PNG. No matter what changes I make to the DIBV5 clipboard copy/paste code, it's guaranteed that a bunch of other apps will either 1) not copy its data to the clipboard correctly such that PDN will handle it, or 2) not read PDN's DIBV5 from the clipboard correctly. This is what happens Every. Single. Time. I. Have. Ever. Changed. The. Clipboard. Code. It is not possible to get 100% compatibility between all apps. At this point you need the equivalent of winning a case at the US Supreme Court to get me to change this code (which I considered that discussion linked in #1 to be an example of). It's not worth the trouble otherwise.
-
This is unchanged in 5.0. Layer composition still happens on the CPU and that is unlikely to change because of how much GPU VRAM would be required to hold all your layers. I tried it in the early days of 4.0’s development and it was a disaster. And you’d still have linear performance with respect to layer count. Nowadays we have quite decent float32 performance on the CPU and I’m not too worried about it for the next engine upgrade. It would work fine on a pro/workstation class card with lots of memory (up to 48GB!). These cards, such as the NVIDIA RTX 5000 Ada, have twice the RAM but cost 4x as much compared to the equivalent consumer card. So you get 32GB for $4000 versus a GeForce 4080 Super with 16GB for $1000. Not worth it!
-
I've been using your original code as a means of experimenting/researching into compute shaders in the PDN v5.1 code base. It would be easy for me to add compute shader support for the next servicing release of 5.0, which would be 5.0.13, as it's just exposing the necessary interfaces and methods in the Direct2D wrappers. There's still no support in ComputeSharp.D2D1 for this. So I've converted it over to a compute shader. It gets much trickier when doing this as you have to manage your own scheduling (numthread and thread groups). I've implemented it such that each "thread" (one invocation of Execute()) writes an 8x4 block of pixels (pixel shader always writes out 1x1 per invocation). I use a resource texture to supply all of the sampling offsets, along with a bitmask indicating which pixel will use that sample. This lets me, for an 8x4 region anyway, only read each input pixel once instead of 8 times. The performance speedup isn't dramatic: on a large 8192 x 4500 px image, at radius=100 and Full sampling, your original code takes ~13.5 seconds to render, while mine takes ~8.5 seconds. When I bump it up to 12 iterations of HiLo() -- which is necessary to get the right amount of precision to avoid banding artifacts -- it runs in about ~12.5 seconds. So, not really any performance gain but there is a really good quality gain. Oh, and this was on a GeForce 4090!
-
If you're just drawing without any blending -- which means either 1) first drawing call after Clear(), or 2) using CompositingMode.SourceCopy, then it's basically just memcpy()
-
It might be doable with compute shaders, but PDN's D2D wrappers don't have support for that yet, nor does @sergiopedri's ComputeSharp.D2D1.
-
Did you know about Effects -> Noise -> Median? That's what this new plugin is replicating, but running it on the GPU The CPU version (the built-in Median) is actually faster, too -- as it turns out, doing a median calculation is very expensive to do on the GPU!