Cannot save Bitmap in Unity

Hi

I wrote some code to split an image into three files containing either red, green and blue channel.
It’s working properly in a visual studio project but when executing it in unity (Version 5.1.1p2 (82544090e14f) Personal, 64bit) the call of bitmap.save results in the following exception:

InvalidOperationException: The operation is invalid [GDI+ status: Win32Error]
System.Drawing.GDIPlus.CheckStatus (Status status)
System.Drawing.Image.Save (System.String filename, System.Drawing.Imaging.ImageCodecInfo encoder, System.Drawing.Imaging.EncoderParameters encoderParams)
System.Drawing.Image.Save (System.String filename, System.Drawing.Imaging.ImageFormat format)
System.Drawing.Image.Save (System.String filename)
(wrapper remoting-invoke-with-check) System.Drawing.Image:Save (string)
ColorSplitter.splitTextureCopy (System.String imagePath) (at Assets/scripts/Editor/ColorSplitter.cs:171)
ColorSplitter.SplitTexture () (at Assets/scripts/Editor/ColorSplitter.cs:30)

The code triggering the error

    private static Bitmap GetArgbCopy(Image sourceImage)
    {
        Bitmap bmpNew = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb);

        using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bmpNew))
        {
            graphics.DrawImage(sourceImage, new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), GraphicsUnit.Pixel);
            graphics.Flush();
        }

        return bmpNew;
    }

    public static void splitTextureCopy(string imagePath)
    {
        // the original unconverted image
        Image sourceImage = Image.FromFile(imagePath);

        // copies of original image for red channel
        Bitmap redBmp = GetArgbCopy(sourceImage);
        Bitmap greenBmp = GetArgbCopy(sourceImage);
        Bitmap blueBmp = GetArgbCopy(sourceImage);

        Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);

        // safe space for image data in RAM
        BitmapData redBmpData = redBmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        BitmapData greenBmpData = greenBmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        BitmapData blueBmpData = blueBmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        // pointer to first pixel data
        IntPtr redPointer = redBmpData.Scan0;
        IntPtr greenPointer = greenBmpData.Scan0;
        IntPtr bluePointer = blueBmpData.Scan0;

        int bufferSize = redBmpData.Stride * redBmp.Height;
        // byte array containing raw color-data
        byte[] redByteBuffer = new byte[bufferSize];
        byte[] greenByteBuffer = new byte[bufferSize];
        byte[] blueByteBuffer = new byte[bufferSize];

        // copy raw color-data to byte arrays
        Marshal.Copy(redPointer, redByteBuffer, 0, bufferSize);
        Marshal.Copy(greenPointer, greenByteBuffer, 0, bufferSize);
        Marshal.Copy(bluePointer, blueByteBuffer, 0, bufferSize);

        // convert colors in byte array
        // byteBuffer[i] addresses red channel, byteBuffer[i+1] green, byteBuffer[i+2] blue, byteBuffer[i+3] alpha
        for (int i = 3; i < bufferSize; i += 4)
        {
            redByteBuffer[i] = redByteBuffer[i - 1];
            greenByteBuffer[i] = greenByteBuffer[i - 2];
            blueByteBuffer[i] = blueByteBuffer[i - 3];
        }

        // copy color-data back to RAM
        Marshal.Copy(redByteBuffer, 0, redPointer, bufferSize);
        Marshal.Copy(greenByteBuffer, 0, greenPointer, bufferSize);
        Marshal.Copy(blueByteBuffer, 0, bluePointer, bufferSize);

        //free space in RAM
        redBmp.UnlockBits(redBmpData);
        greenBmp.UnlockBits(greenBmpData);
        blueBmp.UnlockBits(blueBmpData);
        redBmpData = null;
        greenBmpData = null;
        blueBmpData = null;
        redByteBuffer = null;
        greenByteBuffer = null;
        blueByteBuffer = null;
        //get name and path of new image
        int index = imagePath.LastIndexOf("/");
        string basePath = imagePath.Substring(0, index);
        string fileName = imagePath.Substring(index + 1);

        //save new image
        redBmp.Save(basePath + "red/" + fileName);
        greenBmp.Save(basePath + "green/" + fileName);
        blueBmp.Save(basePath + "blue/" + fileName);
    }

Could this be due to the NET-Version of Unity?
Thanks

System.Drawing doesn’t really work from within unity. In Microsoft .NET world it’s usually mapped to the GDI+ Windows Drawing API, but supporting than in unity or mono across all the different devices it needs to run on? I’d be wary of using that in a pure Mono app, in Unity I’d be shocked if it worked even on Windows.

So, the code is correlated with this thread. Is there another way to save the generated bitmap or rather create a light cookie with it in another way?

I’d revaluate your problem, creating images/textures on the fly at runtime is not going to get you a good result.

You’d be better of writing your own decal system.

As far as I know, the rsult of a decal-system is very similar to a projector’s one. I.e. I only can define a far-clipping-plane which would lead to the problem of missing shadows when not projecting with an angle of 90°.
The result I want to have is the left one but when using projector or decal, I’ll get the right one.

I still don’t really know what you’re trying to do here. You seem to be asking for a specific solution to something without really explaining what the problem is that you’re trying to solve.

What I’m actually trying to do is to project multiple real-time camera-streams of a surveillance-system back onto a 3D-model of the floor filmed by these cameras.