[Closed] dotnet troubles
Hi guys
I am trying to translate a code that I found here [ http://msdn.microsoft.com/de-de/library/5ey6h79d%28v=vs.80%29.aspx#Y1375 ]( http://msdn.microsoft.com/de-de/library/5ey6h79d%28v=vs.80%29.aspx#Y1375)to maxscript with dotnet. Unfortunately dotnet is still a big mystery to me. As soon as it gets a little more complicated I fail. So maybe someone could guide me in the right direction. All I want to do is use the gdi+ to do some image manipulation. The example structure looks promising.
This is how far I got:
local clipboardObj = dotNetClass "System.Windows.Forms.Clipboard"
-- Get the image from the clipboard into a dotNet image object.
setClipboardBitmap bm
local imgObj = clipboardObj.GetImage()
rect = dotNetObject "System.Drawing.Rectangle" 0 0 10 10
bmd = imgObj.LockBits rect ((dotnetclass "System.Drawing.Imaging.ImageLockMode").Readonly) ((dotnetclass "System.Drawing.Imaging.Pixelformat").Format24bppRgb) --imgObj.PixelFormat
stride = bmd.Stride;
Scan0 = dotnetclass "System.IntPtr"
Scan0 = bmd.Scan0
--p = dotnetclass "byte"
p = dotnetclass "system.byte[]"
p = bmd.Scan0
nOffset = stride - imgObj.Width*3
nWidth = imgObj.Width * 3
For y = 0 To bmd.Height - 1 do
(
For x = 0 To bmd.Width - 1 do
(
--p[0] = (255-p[0])
--p += 1;
--(dotnetclass "System.Runtime.InteropServices.Marshal").writeByte bmd.Scan0 ((bmd.Stride * y) + (4 * x)) 255
)
--p += nOffset
)
imgObj.UnlockBits bmd
currently I keep getting an error message. Don’t know what it means…:
-- Runtime error: dotNet runtime exception: Object of type 'System.Int64' cannot be converted to type 'System.IntPtr'.
So there may be many mistakes and wrong assumptions in my code. So please correct anything you want, or give it a shot yourself. It would only be really fantastic to get it working.
thanks, David
The error you are getting is because maxscript converts pointers to int64 values, while dotnet is expecting an IntPtr value.
to send a handle to dotnet, you should use:
dotNetObject "System.IntPtr" yourHandle
Other than that, I really do think it will be much faster to write this code as a small static c# class and compile it dynamically, otherwise you will probably lose a great deal of the speed you gain with the lockbits method.
hey. Thanks for the reply. I’ll try your approach now.
I don’t have much experience with C#. Do you mean I should write a small dll which takes care of image manipulation?
It doesnt have to be a precompiled dll. It can be a dynamically compiled assembly.
Take a look at this post (just a random example off the top of my head):
http://forums.cgsociety.org/showpost.php?p=6987282&postcount=107
wooha. That is incredible!!! I didn’t know that was possible at all. You opened up a new world of possibilities to me. thanks a lot, mate.
sure thing, it’s a great technique for development.
For specific image manipulation methods in c#, you can check out the source code of a tool I released:
http://forums.cgsociety.org/showthread.php?t=1001903
look in the VFBCurveControl class, specifically the ApplyBitmapCC method. It uses lockbits for image manipulation.
oh my god. it just keeps getting better :-D. This is so what I was looking for. And it is working really nice. Your source code will be invaluable for me.
Oh, one more note. In my tool I used methods which include ‘unsafe’ code (code which accesses pointers directly, and not using marshaling, which is about 10%-20% faster).
To be able to dynamically compile an assembly using unsafe code in maxscript, you will have to set the ‘/unsafe’ switch on the compiler.
yourCompilerParamsObject.CompilerOptions = "/unsafe"
hey lo. Thanks again for the great support. But I am still not getting the results I want. The following code should do something, but the returned image doesn’t look affected at all. So I must be doing something wrong:
fn myCreateArrAssembly =
(
source = ""
source += "using System;
"
source += "using System.Collections;
"
source += "using System.Drawing;
"
source += "using System.Drawing.Drawing2D;
"
source += "using System.Drawing.Imaging;
"
source += "using System.Text;
"
source += "namespace testTools
"
source += "{
"
source += " public class testToolsClass
"
source += " {
"
source += " public unsafe Bitmap testimage (Bitmap bmp)
"
source += " {
"
source += " // Lock the bitmap's bits.
"
source += " Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
"
source += " System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,bmp.PixelFormat);
"
source += " // Get the address of the first line.
"
source += " IntPtr ptr = bmpData.Scan0;
"
source += " // Declare an array to hold the bytes of the bitmap.
"
source += " // This code is specific to a bitmap with 24 bits per pixels.
"
source += " int bytes = bmp.Width * bmp.Height * 3;
"
source += " byte[] rgbValues = new byte[bytes];
"
source += " // Copy the RGB values into the array.
"
source += " System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
"
source += " // Set every red value to 255.
"
source += " for (int counter = 0; counter < rgbValues.Length; counter+=3)
"
source += " rgbValues[counter] = 255;
"
source += " // Copy the RGB values back to the bitmap
"
source += " System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
"
source += " // Unlock the bits.
"
source += " bmp.UnlockBits(bmpData);
"
source += " // Draw the modified image.
"
source += " //e.Graphics.DrawImage(bmp, 0, 150);
"
source += " return bmp;
"
source += " }
"
source += " public static unsafe Bitmap ApplyBitmapCC(Bitmap source)
"
source += " {
"
source += " BitmapData bData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, source.PixelFormat);
"
source += " //BitmapData bDataCC = dest.LockBits(new Rectangle(0, 0, dest.Width, dest.Height), ImageLockMode.WriteOnly, dest.PixelFormat);
"
source += " int bytesPerPixel = Image.GetPixelFormatSize(source.PixelFormat) / 8;
"
source += " byte* scan0 = (byte*)bData.Scan0.ToPointer();
"
source += " //byte* scan0cc = (byte*)bDataCC.Scan0.ToPointer();
"
source += " for (int i = 0; i <= bData.Stride * bData.Height - bytesPerPixel; i += bytesPerPixel)
"
source += " {
"
source += " byte* data = scan0 + i;
"
source += " *data = 255;
"
source += " //byte* dataCC = scan0cc + i;
"
source += " //*dataCC = values[0][values[3][*data]];
"
source += " //*(dataCC + 1) = values[0][values[2][*(data + 1)]];
"
source += " //*(dataCC + 2) = values[0][values[1][*(data + 2)]];
"
source += " //*(dataCC + 3) = values[4][*(data + 3)];
"
source += " }
"
source += " source.UnlockBits(bData);
"
source += " return source;
"
source += " //dest.UnlockBits(bDataCC);
"
source += " }
"
/*public static unsafe void ApplyBitmapCC(Bitmap source, Bitmap dest, byte[][] values)
{
BitmapData bData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat);
BitmapData bDataCC = dest.LockBits(new Rectangle(0, 0, dest.Width, dest.Height), ImageLockMode.WriteOnly, dest.PixelFormat);
int bytesPerPixel = Image.GetPixelFormatSize(source.PixelFormat) / 8;
byte* scan0 = (byte*)bData.Scan0.ToPointer();
byte* scan0cc = (byte*)bDataCC.Scan0.ToPointer();
for (int i = 0; i <= bData.Stride * bData.Height - bytesPerPixel; i += bytesPerPixel)
{
byte* data = scan0 + i;
byte* dataCC = scan0cc + i;
*dataCC = values[0][values[3][*data]];
*(dataCC + 1) = values[0][values[2][*(data + 1)]];
*(dataCC + 2) = values[0][values[1][*(data + 2)]];
*(dataCC + 3) = values[4][*(data + 3)];
}
source.UnlockBits(bData);
dest.UnlockBits(bDataCC);
}
/*
source += " public Int32[] RandomIndexes(int count)
"
source += " {
"
source += " Random list = new Random();
"
source += " return RandomizeIndexes(count, list);
"
source += " }
"
source += " public Int32[] RandomIndexes(int count, int seed)
"
source += " {
"
source += " Random list = new Random(seed);
"
source += " return RandomizeIndexes(count, list);
"
source += " }
"*/
source += " }
"
source += "}
"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.CompilerOptions = "/unsafe"
compilerParams.ReferencedAssemblies.AddRange #("System.dll")
compilerParams.ReferencedAssemblies.AddRange #("System.Drawing.dll")
compilerParams.ReferencedAssemblies.AddRange #("System.Windows.Forms.dll")
compilerParams.GenerateInMemory = on
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
if (compilerResults.Errors.Count > 0 ) then
(
errs = stringstream ""
for i = 0 to (compilerResults.Errors.Count-1) do
(
err = compilerResults.Errors.Item[i]
format "Error:% Line:% Column:% %
" err.ErrorNumber err.Line \
err.Column err.ErrorText to:errs
)
MessageBox (errs as string) title: "Errors encountered while compiling C# code"
format "%
" errs
return undefined
)
assembly = compilerResults.CompiledAssembly
assembly.CreateInstance "testTools.testToolsClass"
)
global mytestClass = myCreateArrAssembly()
clipboardObj = dotNetClass "System.Windows.Forms.Clipboard"
bm = getlastrenderedImage()
SetClipboardBitmap bm
imgObj = clipboardObj.GetImage()
newimg = mytestClass.testimage imgObj
clipboardObj.setImage(newimg)
-- Get the image from the clipboard back into maxscript
newBm = getClipboardBitmap()
display newBm
would you mind helping me out again. On running the script I get the followin error message in the listener:
-- Error occurred in anonymous codeblock; filename: D:\Dokumente\Projekte\Beruf\stereocamera\stereo\c#test3.ms; position: 6575; line: 138
-- Runtime error: dotNet runtime exception: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I also tried your approach with pointers, but failed as well. I still don’t entirely grasp pointers. I know of this weakness and I am willing to fight against it. But right now, I have no idea what I am actually coding