Jump to content

how you handle larg images (over 2GB of memory)


Recommended Posts

Hi there,

first of all, congratulations for this very handy and superb tool, thx for sharing it!

At this moment I'm trying creating very large images (over gigapixel) but everything I tested with winapi (including .Net System.Drawing.Bitmap, Gdipluss::Bitmap, CImage - which uses CreateDIBSection inside) can't get the work done (always getting invalid parameter error, not matter it the platform is x64 or not). When seeking for answers over the internet I read someone suggesting to download Paint.Net source code and check how it handles memory for large images. So installed the 3.5.8 version (the installation for 64 bits) to see if it would handle images like 24000 x 30000 and it is successful on handling such big files (my system is Win7 pro 64 bits with 12GB of RAM). I tried to find the source code, but as you explain in your site you no longer share the source code. However I could find an older version, 3.01, with copyrigths from 2007. But, in this version I could see that you throw an out of memory message box when trying creating image with 24000 x 30000 size. The default compilation platform is AnyCPU, so I've tried compiling the project for x64 platform to see if it would resolve the problem, but I got plenty of errors saying that the assemblies target a different processor than the application.

That's why I came here to ask this question: can you share how you handle such big files in this new version, how you create image with this size? I could see what you use in the older version, I just wonder if you still use the same thing or you use another approach.

Thx for your time, leo

Link to comment
Share on other sites

Leo,

First of all welcome to the forum.

RE: previous versions. They are simply no longer supported. Please don't ask for them or how to solve problems relating to them.

RE: Source code of older versions. The same applies. This is not a place where you can get help with the source code at all.

Rick has stopped making the source available and will be unlikely to assist you (http://forums.getpaint.net/index.php?/topic/13335-the-source-code-is-not-available/) - please respect his decision concerning this.

It sounds like you're trying to create images programatically. If this is so try somewhere like StackOverflow - there are lots of sharp people there who may be able to help.

Link to comment
Share on other sites

Hi Ego,

I know about his decision, I read the post where he explains why. I'm not asking any support about old version, I'm not asking the source code of the newer. I'm only asking what does he do it for this very specifc part. As I understand, he doesn't release the source code anymore for right violation reasons, not because he doesn't want people know how things are done, afterall the Paint.Net project was open source (unless he has changed his mind in this regard). That's why I came here ask this question.

I've being searching a lot in the net about how to do this, including Stakoverflow and MSDN forum, but no answer. Since this project has open source roots and have a forum, I though I could have some answers on this regard.

Leo

Edited by laobrasuca
Link to comment
Share on other sites

Paint.NET does not use System.Drawing.Bitmap except for simple UI stuff. Never for the image contents itself.

I use either CreateDIBSection() or VirtualAlloc() to allocate the memory. Width * Height * 4 is the number of bytes. You only need CreateDIBSection() if you plan on drawing the bitmap to the screen using BitBlt. (otherwise, I think BitBlt() will first copy the memory into a private buffer ... based on observation, and this might be out of date since this is what I observed on XP)

You can easily create a System.Drawing.Bitmap which aliases the memory you allocated yourself. It has an overload which takes a pointer and a stride; look for my CreateAliasedBitmap method on Surface. (Using Reflector on the latest public version is probably just as good as having the old source code)

However, if you try to use any of the built-in .NET controls, whether it's PictureBox on WinForms or whatever else on WPF, you will likely run into horrible problems. I noticed that PictureBox, for instance, always has performance proportional to the size of the bitmap instead of performance proportional to the viewport. Because of that, Paint.NET uses custom controls for drawing to the screen. In v3.5.8, I'm using BitBlt. In 4.0, I'm using a sophisticated and very complex system involving tiles, multithreading, asynchrony, and Direct2D.

You will also find many times that you'll have to convert things to 64-bit ints to do the right math. For instance, calculating the pointer for (x,y) is scan0+(y * stride)+x, and I found that you must cast y and stride to 64-bit ints otherwise you will overflow on large images.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Hi Rick, thx for replying, I appreciate that.

You can easily create a System.Drawing.Bitmap which aliases the memory you allocated yourself. It has an overload which takes a pointer and a stride; look for my CreateAliasedBitmap method on Surface. (Using Reflector on the latest public version is probably just as good as having the old source code)

Thx for the tip! I've tried it both on .Net and C++ Gdiplus. I suceed on both, I can indeed create images 2Giga pixel or higher (also thx to you I could see how to overcome the famous 2GB arbitrary limit of .Net on array allocation). But now I have another problem... Even if I can generate the big image I can't save it to a file! When using Gdiplus::Status status = BigImage.Save(L"filename.png", &encoder, 0) I have status = Gdiplus::Status::Win32Error. And, when using BigImage.Save(L"filename.png") on .Net I have an unhanded exception of type 'System.Runtime.InteropServices.ExternalException' produced in System.Drawing.dll, and I can notice that it happens while the memory is not taken into RAM. Both failure happens when trying to save image of size 24000 x 60000 or larger, while for images with dimensions up to 24000 x 59000 it works just fine. I can't just figure what Win32Error means in this case (my disk has NTFS format and I have over 100GB of free space), and it surprises me that System.Drawing.Image.Save crashes like this (I tried BMP, PNG, TIFF, JPEG and GIF in both cases, all with the same result). I could not test your 3.5.8 version because I have not enough RAM memory to create a 24000x60000 image and save it (it creates the image, but takes all my 11GB of free space, then it takes a lot of time to save, so I had abort it). Tomorrow I'll try it on a 24GB RAM system.

If you have any suggestions I would be happy to hear.

You will also find many times that you'll have to convert things to 64-bit ints to do the right math. For instance, calculating the pointer for (x,y) is scan0+(y * stride)+x, and I found that you must cast y and stride to 64-bit ints otherwise you will overflow on large images.

yes, I've already done this a lot of times as I'm used to allocate over 4GB arrays.

However, if you try to use any of the built-in .NET controls, whether it's PictureBox on WinForms or whatever else on WPF, you will likely run into horrible problems. I noticed that PictureBox, for instance, always has performance proportional to the size of the bitmap instead of performance proportional to the viewport. Because of that, Paint.NET uses custom controls for drawing to the screen. In v3.5.8, I'm using BitBlt. In 4.0, I'm using a sophisticated and very complex system involving tiles, multithreading, asynchrony, and Direct2D.

Ouch! Still, your code is pretty neat and elegantly written, I which I could produce such clean and well done code. Fortunately for me I don't need to do such complex things. My problem is that I have lots of data. I don't need to draw such huge images on controls. I actually have lots of 8192x8192 or 16384x16384 tile images (on disk) that I need to put together in a single image of > 1 gigapixels. That's why I need such huge bitmap. I've done it manually with PhotoShop, but it took all my RAM and 600GB of disk space with their temporary files, not to mention the time it took me to do it. Now I'm willing to do it automatically.

thx, leo

Edited by laobrasuca
Link to comment
Share on other sites

Instead of using System.Drawing, which wraps GDI+ (which sucks for many reasons), try using the codecs in System.Windows.Media.Imaging (or wherever) which is part of WPF and which wraps the WIC (Windows Imaging Component) library. I don't know if it'll work better, but I can guarantee it has a better chance of working. GDI+ was written way back in 1998-2001 or so, before all the new quality- and security-aware coding practices really went into effect at Microsoft. WIC is much more modern, much more resilient.

Win32Error is GDI+'s way of saying "umm we forgot to do something correctly here." There's a high probably that it is not a bug in your code. (I've gotten crash reports before which said something like, "Error in GDI+: The operation succeeded". errrmmm!?")

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

See? TOLD you he wouldn't help boltbait.lol.png

I just happen to be in a good mood, and he's actually asking a reasonably intelligent and interesting question ... as opposed to, "HI CAN YOU TEACH ME SEE SHARP"

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

If you're feeling so magnanimous: lend me 50 bucks?

no?

Ah well, I'll just go create another account and anonymously hassle you to teach me c#...., :lol:

  • Upvote 1
Link to comment
Share on other sites

@Ego: I'd rather say that you're not in a good mood :P

@riki:

Win32Error is GDI+'s way of saying "umm we forgot to do something correctly here." There's a high probably that it is not a bug in your code. (I've gotten crash reports before which said something like, "Error in GDI+: The operation succeeded". errrmmm!?")

pretty nasty!

I've just tested the save thing into a 24GB RAM machine. I can create the 24000 x 60000 image (blank image, it took me 17GB of RAM, which is roughly 3 times the space the image raw data should take). So, I hit the save button, chose filename (PNG file type) and chose 24bpp, then it takes a while to calculate the disk space it will take and finally start the file saving. At this moment I have a "There was an unspecified error while saving the file" error message box that shows up, which seems to come from the unhanded exception from Image.Save method (your SaveImage.Error.Exception). So I'll try to figure how to use System.Windows.Media.Imaging, as you suggest. But if you have any hints on how to use it, I would be glad to hear!

and he's actually asking a reasonably intelligent and interesting question

in your face, Ego :D Hey, I'm just kidding :mrgreen:

Thx for your time guys,

leo

Edited by laobrasuca
Link to comment
Share on other sites

  • 3 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...