Skip to content
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

ArraySection length is not enough for large image file #17

Open
bj-gegf opened this issue Sep 27, 2024 · 4 comments
Open

ArraySection length is not enough for large image file #17

bj-gegf opened this issue Sep 27, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@bj-gegf
Copy link

bj-gegf commented Sep 27, 2024

the length is integer in ArraySection, if image is too big will out of range
image
could you please update the type to long? or is there any ideas? thanks!

@koszeggy koszeggy transferred this issue from koszeggy/KGySoft.CoreLibraries Sep 27, 2024
@koszeggy koszeggy added the bug Something isn't working label Sep 27, 2024
@koszeggy
Copy link
Owner

Thank you for your report.

ArraySection<T> is backed by an array so it has the same limitations as an actual array. I used ArraySection<byte> here to prevent pooling other types than byte arrays, but in such cases I can change the buffer element type to a primitive that matches the pixel size (while I disable array pooling to prevent big memory pressure).

If I'm not mistaken this is in the WPF package but a similar issue may exist in the other ones, too. I'm going to fix this soon.

@koszeggy
Copy link
Owner

koszeggy commented Sep 28, 2024

I've just realized that this issue cannot be really fixed due to some internal WPF limitations, at least not easily.

In your screenshot the bottom line, which is mostly covered by the watch window, is a BitmapSource.CopyPixels call, which ends up in a very similar total byte length calculation inside WPF, regardless of the array element type. As it's in a checked context, it will throw an OverflowException, and it doesn't matter if I pass an array with a larger element type to it.

The funny thing is that they eventually cast the bufferSize to uint when calling the underlying unmanaged API, which theoretically could handle images no bigger than 4.2 GB but the signed overflow check does not allow buffers larger than 2.1 GB.

Possible solutions

  1. If the actual type of the source bitmap is a WriteableBitmap, then use the GetReadWriteBitmapData extension instead, which does not perform an internal copy. I can actually redirect the existing GetReadableBitmapData method to GetReadWriteBitmapData if the type of the source bitmap happen to be a WriteableBitmap (let me know if you want this change in the next version).

  2. Convert your BitmapSource to a WriteableBitmap first. It won't be easy, because simply calling the constructor leads to the same problem, but maybe creating an empty WriteableBitmap and copying the pixels in smaller chunks using the CopyPixels(Int32Rect, Array, Int32, Int32) overload can help, as you can specify a source rectangle that can cover a smaller area. I could do the copying this way in GetReadableBitmapData but I'm not sure if it's worth it, considering that we are quite pushing the limits of WPF here (and this may require two times 4GB memory because we are working with two buffers). But let me know if you really would like me to do this (if it really works).

+1: If it turns out that solution 2. works for bitmaps between 2 and 4 GB size, then you can file an issue in the WPF repo to relax the signed buffer size limit to allow the easier creation/copy of huge bitmaps.

Edit: I've just found a related WPF issue.

@bj-gegf
Copy link
Author

bj-gegf commented Sep 28, 2024

Thank you for your feedback. Because the pictures I am dealing with now are much larger than 4GB, I feel that I must change my thinking to solve this problem, such as directly reading the thumbnail of the visible area size from the picture file, and modifying the original picture by scaling the user operation proportionally through the scaling factor.

@koszeggy
Copy link
Owner

I don't know whether it's a possible way for you to migrate to SkiaSharp but the GetReadableBitmapData method for SKBitmap does not require any copying (well, at least when the bitmap uses the default sRGB or linear color spaces) and you can seamlessly work with the result IReadableBitmapData the same way as now.

And you can even display Skia bitmaps in a WPF application, though I don't know how such huge images are supported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants