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