0


I have an application which creates a Bitmap object consisting of all the 16 million colors. The final bitmap would be measuring 4096 × 4096 pixels.
When I try to call the Bitmap's Save() method, it causes an error.
This is the error message that comes up:

A generic error occurred in GDI+.

Please try to help me on this thing. Thanks in advance!


Note: Look at the last few commented lines of the source code below. I have explained the doubt there.
SOURCE CODE:
Public Sub CreateAllColorImage()
    Dim BMP As New Bitmap(4096, 4096) 'This BMP variable is where the image will be created.'
    Dim CurrX = 0
    Dim CurrY = 0
    Dim ExitFors As Boolean = False
    For R = 0 To 255
        For G = 0 To 255
            For B = 0 To 255
                BMP.SetPixel(CurrX, CurrY, Color.FromArgb(R, G, B))
                CurrY += 1 'Increment the Y axis to move to next pixel.'
                If CurrY > 4095 Then CurrX += 1 : CurrY = 0 'Move to next row, or increment X axis, if the last pixel on the Y axis is reached'
                If CurrX > 4095 Then ExitFors = True 'Set the variable to exit the FOR loops if the very last pixel on the whole image is reached.'
                If ExitFors Then Exit For 'Exit the FOR loop if the variable is true.'
            Next
            If ExitFors Then Exit For 'Exit the FOR loop if the variable is true.'
        Next
        If ExitFors Then Exit For 'Exit the FOR loop if the variable is true.'
    Next
    'So therefore, the final image is the BMP variable.'
    'Here, I try to save the Bitmap as a file by calling this:'
    BMP.Save("C:\TEST.BMP")
    'This is when the error occurs. I think so because of the image is too large. If so, is there any way to do anything?'
    'And by the way, I already have the rights to access the C:\ drive because I am working from an Administrator account...'
    BMP.Dispose()
    BMP = Nothing
End Sub
Sreenikethan I
  • 319
  • 5
  • 17

2 Answers2

3

As a normal user one usually does not have access to the root C:\ drive. Even if you are an administrator your application will run under the normal privileges unless otherwise specified.

Unfortunately GDI+ hides most exceptions so it's hard to know the exact cause of what's happening, but my guess is that your problem is due to that your application isn't allowed to save directly in the C:\ drive.

Try saving the image in a path you are guaranteed to have access to, like C:\Users\YourUserName\Desktop.

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • Agreed, as the size is not a problem : 16 million pixel * 3 (RGB) = 48 million bytes => 48 Mb... – Martin Verjans Jun 14 '16 at 11:51
  • @SuperPeanut : You are confusing me now. Are you being sarcastic or serious? 48 MB should be doable. – Visual Vincent Jun 14 '16 at 11:54
  • Yes I'm serious that's why I said it's not a problem... BMP can go far over that size. Supposed that my calculation is correct... My point is that since the problem does not come from the file size, it most certainly comes from C: drive permissions as you stated... – Martin Verjans Jun 14 '16 at 11:57
  • @SuperPeanut : Yes. 4096^2 isn't a particularly big image compared to what you're able to save. Sorry for misunderstanding, I just had a little hard time understanding your reaction from the comment. :) – Visual Vincent Jun 14 '16 at 12:01
  • No it's okay my english syntax is sometimes confusing (french speaker here...) – Martin Verjans Jun 14 '16 at 12:07
  • 2
    @SuperPeanut : Your english is fine. It was just possible to interpret your comment as sarcasm due to how your sentence was constructed - but otherwise it is perfectly valid. Such cases exists for native speakers too. (: – Visual Vincent Jun 14 '16 at 12:11
  • 2
    Just a completely irrelevant nitpick to go along with my upvote: GDI+ doesn't throw exceptions. It returns [status codes](https://msdn.microsoft.com/en-us/library/windows/desktop/ms534175.aspx) from all of the functions in the GDI+ API. It is the .NET wrapper around GDI+ that is converting those status codes into an exception. But the larger point still stands that GDI+ does an absolutely abysmal job of detecting the causes of errors and returning the right status code. Clearly `AccessDenied` would have been more suitable here. No idea why they didn't use that one. – Cody Gray - on strike Jun 14 '16 at 13:32
  • SuperPeanut, the file size is actually 30 MB (31,499,770 bytes). – Sreenikethan I Jun 14 '16 at 15:01
  • And now I opened that image in MS Paint, **JUST SIMPLY PRESSED _Ctrl + S_**, and the magic happened! It reduced to *198 KB*!!!!!!! Can you believe it??? – Sreenikethan I Jun 14 '16 at 15:18
  • @Sree : That depends on encoding, format and pixelformat. I.e. 32bppArgb will eat up more space than 24bppRgb. – Visual Vincent Jun 14 '16 at 19:17
  • @CodyGray : Interesting... Well Microsoft hasn't always provided perfectly optimized libraries. :) – Visual Vincent Jun 14 '16 at 19:18
  • 2
    @sree That's because, as Visual Vincent alluded to, Paint doesn't support 32-bit alpha-channel transparency for bitmaps. So when you saved it, it saved it as a 24-bit bitmap. If you don't need transparency in your bitmap, you can create it with the same format. Instead of `Using BMP As New Bitmap(4096, 4096)`, specify the format explicitly: `BMP As New Bitmap(4096, 4096, PixelFormat.Format24bppRgb)`. Actually, you should prefer to use this overload of the constructor anyway, since even for 32-bit images, `Format32bppPArgb` is ***far*** more efficient than the default, `Format32bppArgb`. – Cody Gray - on strike Jun 15 '16 at 05:54
  • 1
    The difference is that PArgb means premultiplied alpha (the P = premultiplied), Argb is not premultiplied. You can find out lots of details about that on Google, but basically it's just a different way of storing the alpha-channel information. The reason it is faster (often significantly so, ~10 times according to some benchmarks I've seen) is because it matches the way that modern video hardware stores pixel data internally, so no on-the-fly conversion is required. – Cody Gray - on strike Jun 15 '16 at 10:34
  • @CodyGray : Now I am curious, in what way(s) is/are `32bppPArgb` more efficient than `32bppArgb`? What's the difference between them, and will PArgb be larger in size? I read that the RGB values are premultiplied, but I have no idea what that means. :) – Visual Vincent Jun 15 '16 at 10:37
  • @CodyGray : Very interesting... Thanks for the clarification! This will be useful when dealing with bitmaps. – Visual Vincent Jun 15 '16 at 10:39
  • @VisualVincent Hey, sorry for bringing back up an extremely old topic. As you had mentioned earlier, I have tried setting the `PixelFormat` to `Format24bppRgb`, and also saved it using `ImageFormat.Png`, but it still takes up 35.5 MiB... and upon opening it with MS Paint and hitting Ctrl + S reduces the size to just a mere 198 KiB. What is it that I am missing in my code? Thank you for the help! – Sreenikethan I Jan 29 '19 at 16:57
  • 1
    @Sree : Hi again! No worries! It seems that MS Paint has implemented a very efficient compression algorithm for its PNGs. Unfortunately the algorithm used by GDI+ isn't as efficient and my attempts to change the encoder parameters didn't work. I think your best bet is to find a third-party library to compress the image better for you. – Visual Vincent Jan 29 '19 at 17:51
  • 1
    @VisualVincent I see. Thank you for the reply! I feel cringed out reading my previous comments made by younger me :D – Sreenikethan I Jan 30 '19 at 16:15
  • 1
    @Sree : You're not the only one who was younger back then. ;) – Visual Vincent Jan 30 '19 at 16:40
1

It may likely be a permission problem. To test it, find your compiled .exe and run it as an administrator. If it works, you know it's a permission problem.

If you are trying to save it to your C: drive because you don't know the user name, you can instead use SpecialDirectory.

e.g.

My.Computer.FileSystem.SpecialDirectories.MyDocuments

will let you save it in the user's documents folder. Generally, saving to C: drive isn't the best thing to do.

I would also advise using the other constructor in which you can specify the image format.

e.g.

bitmapToSave.Save(saveLocation, Imaging.ImageFormat.Bmp)
Sastreen
  • 597
  • 4
  • 13