Browse Source

* EncoderParameters.cs: Added ToNativePtr() method to marshal
struct correctly to a native struct. Resulting data should be
FreeHGlobal'd when finished.

* EncoderParameter.cs: Changed data storage to correspond to
native code layout. Also changed layout to match native layout.

* EncoderParameterValueType.cs: force EncoderParameterValueType to
be Int32

* gdipFunctions.cs: Fixed prototype for
GdipGetEncoderParameterList

* Image.cs: Reworked Save functions to handle EncoderParameters.
Implemented GetEncoderParameterList.
Also removed unused setGDIPalette internal method.

svn path=/trunk/mcs/; revision=27467

Vladimir Vukicevic 21 years ago
parent
commit
e932bf2d09

+ 13 - 0
mcs/class/System.Drawing/System.Drawing.Imaging/ChangeLog

@@ -1,3 +1,16 @@
+2004-05-14  Vladimir Vukicevic  <[email protected]>
+
+	* EncoderParameters.cs: Added ToNativePtr() method to marshal
+	struct correctly to a native struct.  Resulting data should be
+	FreeHGlobal'd when finished.
+
+	* EncoderParameter.cs: Changed data storage to correspond to
+	native code layout (so we can pass these structs directly to
+	native code).  Also changed layout to match native layout.
+
+	* EncoderParameterValueType.cs: force EncoderParameterValueType to
+	be Int32
+
 2004-05-13 Jordi Mas i Hernadez <[email protected]>
 
 	* ColorMatrix.cs:Make private data private 

+ 150 - 35
mcs/class/System.Drawing/System.Drawing.Imaging/EncoderParameter.cs

@@ -3,6 +3,7 @@
 //
 // Author: 
 //	Ravindra ([email protected])
+//  Vladimir Vukicevic ([email protected])
 //
 // (C) 2004 Novell, Inc.  http://www.novell.com
 //
@@ -10,61 +11,93 @@
 using System;
 using System.Text;
 
+using System.Runtime.InteropServices;
+
 namespace System.Drawing.Imaging {
 
 	public sealed class EncoderParameter : IDisposable {
 
 		private Encoder encoder;
-		private Object value;
 		private int valuesCount;
 		private EncoderParameterValueType type;
-		
+		private IntPtr valuePtr;
+
+		internal EncoderParameter ()
+		{
+		}
+
 		public EncoderParameter (Encoder encoder, byte value)
 		{
 			this.encoder = encoder;
-			this.value = value;
 			this.valuesCount = 1;
 			this.type = EncoderParameterValueType.ValueTypeByte;
+			this.valuePtr = Marshal.AllocHGlobal (1);
+			Marshal.WriteByte (this.valuePtr, value);
 		}
 
 		public EncoderParameter (Encoder encoder, byte[] value)
 		{
 			this.encoder = encoder;
-			this.value = value;
 			this.valuesCount = value.Length;
 			this.type = EncoderParameterValueType.ValueTypeByte;
+			this.valuePtr = Marshal.AllocHGlobal (1 * valuesCount);
+			Marshal.Copy (value, 0, this.valuePtr, valuesCount);
 		}
 
 		public EncoderParameter (Encoder encoder, short value)
 		{
 			this.encoder = encoder;
-			this.value = value;
 			this.valuesCount = 1;
 			this.type = EncoderParameterValueType.ValueTypeShort;
+			this.valuePtr = Marshal.AllocHGlobal (2);
+			Marshal.WriteInt16 (this.valuePtr, value);
 		}
 
 		public EncoderParameter (Encoder encoder, short[] value)
 		{
 			this.encoder = encoder;
-			this.value = value;
 			this.valuesCount = value.Length;
 			this.type = EncoderParameterValueType.ValueTypeShort;
+			this.valuePtr = Marshal.AllocHGlobal (2 * valuesCount);
+			Marshal.Copy (value, 0, this.valuePtr, valuesCount);
+		}
+
+		public EncoderParameter (Encoder encoder, int value)
+		{
+			this.encoder = encoder;
+			this.valuesCount = 1;
+			this.type = EncoderParameterValueType.ValueTypeLong;
+			this.valuePtr = Marshal.AllocHGlobal (4);
+			Marshal.WriteInt32 (this.valuePtr, value);
+		}
+
+		public EncoderParameter (Encoder encoder, int[] value)
+		{
+			this.encoder = encoder;
+			this.valuesCount = value.Length;
+			this.type = EncoderParameterValueType.ValueTypeLong;
+			this.valuePtr = Marshal.AllocHGlobal (4 * valuesCount);
+			Marshal.Copy (value, 0, this.valuePtr, valuesCount);
 		}
 
 		public EncoderParameter (Encoder encoder, long value)
 		{
 			this.encoder = encoder;
-			this.value = (int) value;
 			this.valuesCount = 1;
 			this.type = EncoderParameterValueType.ValueTypeLong;
+			this.valuePtr = Marshal.AllocHGlobal (4);
+			Marshal.WriteInt32 (this.valuePtr, (int) value);
 		}
 
 		public EncoderParameter (Encoder encoder, long[] value)
 		{
 			this.encoder = encoder;
-			this.value = convertToIntArr (value);
 			this.valuesCount = value.Length;
 			this.type = EncoderParameterValueType.ValueTypeLong;
+			this.valuePtr = Marshal.AllocHGlobal (4 * valuesCount);
+			int [] ivals = new int[value.Length];
+			for (int i = 0; i < value.Length; i++) ivals[i] = (int) value[i];
+			Marshal.Copy (ivals, 0, this.valuePtr, valuesCount);
 		}
 
 		public EncoderParameter (Encoder encoder, string value)
@@ -76,39 +109,44 @@ namespace System.Drawing.Imaging {
 			byte[] bytes = new byte [asciiByteCount];
 			ascii.GetBytes (value, 0, value.Length, bytes, 0);
 
-			this.value = ascii.GetString (bytes);
 			this.valuesCount = bytes.Length;
 			this.type = EncoderParameterValueType.ValueTypeAscii;
+			this.valuePtr = Marshal.AllocHGlobal (valuesCount);
+			Marshal.Copy (bytes, 0, this.valuePtr, valuesCount);
 		}
 
 		public EncoderParameter (Encoder encoder, byte value, bool undefined)
 		{
 			this.encoder = encoder;
-			this.value = value;
 			this.valuesCount = 1;
 			if (undefined)
 				this.type = EncoderParameterValueType.ValueTypeUndefined;
 			else
 				this.type = EncoderParameterValueType.ValueTypeByte;
+			this.valuePtr = Marshal.AllocHGlobal (1);
+			Marshal.WriteByte (this.valuePtr, value);
 		}
 
 		public EncoderParameter (Encoder encoder, byte[] value, bool undefined)
 		{
 			this.encoder = encoder;
-			this.value = value;
 			this.valuesCount = value.Length;
 			if (undefined)
 				this.type = EncoderParameterValueType.ValueTypeUndefined;
 			else
 				this.type = EncoderParameterValueType.ValueTypeByte;
+			this.valuePtr = Marshal.AllocHGlobal (valuesCount);
+			Marshal.Copy (value, 0, this.valuePtr, valuesCount);
 		}
 
 		public EncoderParameter (Encoder encoder, int numerator, int denominator)
 		{
 			this.encoder = encoder;
-			this.value = new int[] {numerator, denominator};
 			this.valuesCount = 1;
 			this.type = EncoderParameterValueType.ValueTypeRational;
+			this.valuePtr = Marshal.AllocHGlobal (8);
+			int [] valuearray = { numerator, denominator };
+			Marshal.Copy (valuearray, 0, this.valuePtr, valuearray.Length);
 		}
 
 		public EncoderParameter (Encoder encoder, int[] numerator, int[] denominator)
@@ -117,17 +155,26 @@ namespace System.Drawing.Imaging {
 				throw new ArgumentException ("Invalid parameter used.");
 
 			this.encoder = encoder;
-			this.value = new int[][] {numerator, denominator};
 			this.valuesCount = numerator.Length;
 			this.type = EncoderParameterValueType.ValueTypeRational;
+			this.valuePtr = Marshal.AllocHGlobal (4 * valuesCount * 2);
+			IntPtr dest = this.valuePtr;
+			for (int i = 0; i < valuesCount; i++) {
+				Marshal.WriteInt32 (dest, (int) numerator[i]);
+				dest = (IntPtr) ((int) dest + 4);
+				Marshal.WriteInt32 (dest, (int) denominator[i]);
+				dest = (IntPtr) ((int) dest + 4);
+			}
 		}
 
 		public EncoderParameter (Encoder encoder, long rangebegin, long rangeend)
 		{
 			this.encoder = encoder;
-			this.value = new int[] { (int) rangebegin, (int) rangeend};
 			this.valuesCount = 1;
 			this.type = EncoderParameterValueType.ValueTypeLongRange;
+			this.valuePtr = Marshal.AllocHGlobal (8);
+			int [] valuearray = { (int) rangebegin, (int) rangeend };
+			Marshal.Copy (valuearray, 0, this.valuePtr, valuearray.Length);
 		}
 
 		public EncoderParameter (Encoder encoder, long[] rangebegin, long[] rangeend)
@@ -136,17 +183,23 @@ namespace System.Drawing.Imaging {
 				throw new ArgumentException ("Invalid parameter used.");
 
 			this.encoder = encoder;
-			int[] startRange = convertToIntArr (rangebegin);
-			int[] endRange = convertToIntArr (rangeend);
-			this.value = new int[][] {startRange, endRange};
 			this.valuesCount = rangebegin.Length;
 			this.type = EncoderParameterValueType.ValueTypeLongRange;
+
+			this.valuePtr = Marshal.AllocHGlobal (4 * valuesCount * 2);
+			IntPtr dest = this.valuePtr;
+			for (int i = 0; i < valuesCount; i++) {
+				Marshal.WriteInt32 (dest, (int) rangebegin[i]);
+				dest = (IntPtr) ((int) dest + 4);
+				Marshal.WriteInt32 (dest, (int) rangeend[i]);
+				dest = (IntPtr) ((int) dest + 4);
+			}
 		}
 
 		public EncoderParameter (Encoder encoder, int numberOfValues, int type, int value)
 		{
 			this.encoder = encoder;
-			this.value = value;
+			this.valuePtr = (IntPtr) value;
 			this.valuesCount = numberOfValues;
 			this.type = (EncoderParameterValueType) type;
 		}
@@ -154,9 +207,11 @@ namespace System.Drawing.Imaging {
 		public EncoderParameter (Encoder encoder, int numerator1, int denominator1, int numerator2, int denominator2)
 		{
 			this.encoder = encoder;
-			this.value = new int[] {numerator1, denominator1, numerator2, denominator2};
 			this.valuesCount = 1;
 			this.type = EncoderParameterValueType.ValueTypeRationalRange;
+			this.valuePtr = Marshal.AllocHGlobal (4 * 4);
+			int [] valuearray = { numerator1, denominator1, numerator2, denominator2 };
+			Marshal.Copy (valuearray, 0, this.valuePtr, 4);
 		}
 
 		public EncoderParameter (Encoder encoder, int[] numerator1, int[] denominator1, int[] numerator2, int[] denominator2)
@@ -167,9 +222,21 @@ namespace System.Drawing.Imaging {
 				throw new ArgumentException ("Invalid parameter used.");
 
 			this.encoder = encoder;
-			this.value = new int[][] {numerator1, denominator1, numerator2, denominator2};
 			this.valuesCount = numerator1.Length;
 			this.type = EncoderParameterValueType.ValueTypeRationalRange;
+
+			this.valuePtr = Marshal.AllocHGlobal (4 * valuesCount * 4);
+			IntPtr dest = this.valuePtr;
+			for (int i = 0; i < valuesCount; i++) {
+				Marshal.WriteInt32 (dest, numerator1[i]);
+				dest = (IntPtr) ((int) dest + 4);
+				Marshal.WriteInt32 (dest, denominator1[i]);
+				dest = (IntPtr) ((int) dest + 4);
+				Marshal.WriteInt32 (dest, numerator2[i]);
+				dest = (IntPtr) ((int) dest + 4);
+				Marshal.WriteInt32 (dest, denominator2[i]);
+				dest = (IntPtr) ((int) dest + 4);
+			}
 		}
 
 		public Encoder Encoder {
@@ -201,35 +268,83 @@ namespace System.Drawing.Imaging {
 		}
 
 		void Dispose (bool disposing) {
-
-			// release the resources
+			if (valuePtr != IntPtr.Zero) {
+				Marshal.FreeHGlobal (valuePtr);
+				valuePtr = IntPtr.Zero;
+			}
 		}
 
 		public void Dispose () {
-
 			Dispose (true);		
 		}
 
 		~EncoderParameter () {
-
 			Dispose (false);
 		}
 
-		internal Object Value {
-			get {
-				return value;
-			}
+		internal static int NativeSize () {
+			return Marshal.SizeOf (typeof(GdipEncoderParameter));
 		}
 
-		internal int[] convertToIntArr (long[] arr)
-		{
-			int[] intArr = new int [arr.Length];
+		internal void ToNativePtr (IntPtr epPtr) {
+			GdipEncoderParameter ep = new GdipEncoderParameter ();
+			ep.guid = this.encoder.Guid;
+			ep.numberOfValues = (uint) this.valuesCount;
+			ep.type = this.type;
+			ep.value = this.valuePtr;
+			Marshal.StructureToPtr (ep, epPtr, false);
+		}
 
-			for (int i = 0; i < arr.Length; i++)
-				intArr[i] = (int) arr[i];
+		internal static EncoderParameter FromNativePtr (IntPtr epPtr) {
+			GdipEncoderParameter ep;
+			ep = (GdipEncoderParameter) Marshal.PtrToStructure (epPtr, typeof(GdipEncoderParameter));
+
+			Type valType;
+			uint valCount;
+
+			switch (ep.type) {
+			case EncoderParameterValueType.ValueTypeAscii:
+			case EncoderParameterValueType.ValueTypeByte:
+			case EncoderParameterValueType.ValueTypeUndefined:
+				valType = typeof(byte);
+				valCount = ep.numberOfValues;
+				break;
+			case EncoderParameterValueType.ValueTypeShort:
+				valType = typeof(short);
+				valCount = ep.numberOfValues;
+				break;
+			case EncoderParameterValueType.ValueTypeLong:
+				valType = typeof(int);
+				valCount = ep.numberOfValues;
+				break;
+			case EncoderParameterValueType.ValueTypeLongRange:
+			case EncoderParameterValueType.ValueTypeRational:
+				valType = typeof(int);
+				valCount = ep.numberOfValues * 2;
+				break;
+			case EncoderParameterValueType.ValueTypeRationalRange:
+				valType = typeof(int);
+				valCount = ep.numberOfValues * 4;
+				break;
+			default:
+				return null;
+			}
 
-			return intArr;
-		}
+			EncoderParameter eparam = new EncoderParameter();
+			eparam.encoder = new Encoder(ep.guid);
+			eparam.valuesCount = (int) ep.numberOfValues;
+			eparam.type = ep.type;
+			eparam.valuePtr = Marshal.AllocHGlobal ((int)(valCount * Marshal.SizeOf(valType)));
+
+			/* There's nothing in Marshal to do a memcpy() between two IntPtrs.  This sucks. */
+			unsafe {
+				byte *s = (byte *) ep.value;
+				byte *d = (byte *) eparam.valuePtr;
+				for (int i = 0; i < valCount * Marshal.SizeOf(valType); i++)
+					*d++ = *s++;
+			}
 
+			return eparam;
+		}
 	}
 }

+ 1 - 1
mcs/class/System.Drawing/System.Drawing.Imaging/EncoderParameterValueType.cs

@@ -8,7 +8,7 @@ using System;
 namespace System.Drawing.Imaging 
 {
 	[Serializable]
-	public enum EncoderParameterValueType {
+	public enum EncoderParameterValueType : System.Int32 {
 		ValueTypeAscii = 2,
 		ValueTypeByte = 1,
 		ValueTypeLong = 4,

+ 50 - 0
mcs/class/System.Drawing/System.Drawing.Imaging/EncoderParameters.cs

@@ -3,11 +3,13 @@
 //
 // Author: 
 //	Ravindra ([email protected])
+//  Vladimir Vukicevic ([email protected])
 //
 // (C) 2004 Novell, Inc.  http://www.novell.com
 //
 
 using System;
+using System.Runtime.InteropServices;
 
 namespace System.Drawing.Imaging 
 {
@@ -36,5 +38,53 @@ namespace System.Drawing.Imaging
 		public void Dispose () {
 			// Nothing
 		}
+
+		internal IntPtr ToNativePtr () {
+			IntPtr result;
+			IntPtr ptr;
+
+			// 4 is the initial int32 "count" value
+			result = Marshal.AllocHGlobal (4 + parameters.Length * EncoderParameter.NativeSize());
+
+			ptr = result;
+			Marshal.WriteInt32 (ptr, parameters.Length);
+
+			ptr = (IntPtr) ((int) ptr + 4);
+			for (int i = 0; i < parameters.Length; i++) {
+				parameters[i].ToNativePtr (ptr);
+				ptr = (IntPtr) ((int) ptr + EncoderParameter.NativeSize());
+			}
+
+			return result;
+		}
+
+		/* The IntPtr passed in here is a blob returned from
+		 * GdipImageGetEncoderParameterList.  Its internal pointers
+		 * (i.e. the Value pointers in the EncoderParameter entries)
+		 * point to areas within this block of memeory; this means
+		 * that we need to free it as a whole, and also means that
+		 * we can't Marshal.PtrToStruct our way to victory.
+		 */
+		internal static EncoderParameters FromNativePtr (IntPtr epPtr) {
+			if (epPtr == IntPtr.Zero)
+				return null;
+
+			IntPtr ptr = epPtr;
+
+			int count = Marshal.ReadInt32 (ptr);
+			ptr = (IntPtr) ((int) ptr + 4);
+
+			if (count == 0)
+				return null;
+
+			EncoderParameters result = new EncoderParameters (count);
+
+			for (int i = 0; i < count; i++) {
+				result.parameters[i] = EncoderParameter.FromNativePtr (ptr);
+				ptr = (IntPtr) ((int) ptr + EncoderParameter.NativeSize());
+			}
+
+			return result;
+		}
 	}
 }

+ 9 - 0
mcs/class/System.Drawing/System.Drawing/ChangeLog

@@ -1,3 +1,12 @@
+2004-05-14  Vladimir Vukicevic  <[email protected]>
+
+	* gdipFunctions.cs: Fixed prototype for
+	GdipGetEncoderParameterList
+	
+	* Image.cs: Reworked Save functions to handle EncoderParameters.
+	Implemented GetEncoderParameterList
+	Also removed unused setGDIPalette internal method.
+
 2004-05-14  Peter Bartok <[email protected]>
 	* StringFormat.cs: Added CharacterRange handling
 	* Graphics.cs: Implemented MeasureCharacterRanges method

+ 77 - 46
mcs/class/System.Drawing/System.Drawing/Image.cs

@@ -204,10 +204,29 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
 		return source;
 	}
 	
-	[MonoTODO]	
-	public EncoderParameters GetEncoderParameterList(Guid encoder)
+	public EncoderParameters GetEncoderParameterList(Guid format)
 	{
-		throw new NotImplementedException ();
+		Status status;
+		uint sz;
+
+		status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
+		GDIPlus.CheckStatus (status);
+
+		IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
+		EncoderParameters eps;
+
+		try {
+			status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
+			eps = EncoderParameters.FromNativePtr (rawEPList);
+			GDIPlus.CheckStatus (status);
+		} catch {
+			Marshal.FreeHGlobal (rawEPList);
+			throw;
+		}
+
+		Marshal.FreeHGlobal (rawEPList);
+
+		return eps;
 	}
 	
 	public int GetFrameCount(FrameDimension dimension)
@@ -260,31 +279,10 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
 		GDIPlus.CheckStatus (status);				
 	}
 
-	public void Save (string filename)
+	internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
 	{
-		Save (filename, RawFormat);
-	}
-
-	public void Save (Stream stream, ImageFormat format)
-	{
-		Status st;
-		if (Environment.OSVersion.Platform == (PlatformID) 128) {
-			byte[] g = format.Guid.ToByteArray();
-			GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
-			st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.PutBytesDelegate, g, IntPtr.Zero);
-
-		} else {
-			throw new NotImplementedException ("Image.Save(Stream) (win32)");
-		}
-		GDIPlus.CheckStatus (st);
-	}
-
-	public void Save(string filename, ImageFormat format) 
-	{
-		Status st;		
-		ImageCodecInfo[] encoders =  ImageCodecInfo.GetImageEncoders();			
+		ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();			
 		ImageCodecInfo encoder = null;
-		Guid guid;
 		
 		if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
 			format = ImageFormat.Bmp;
@@ -296,38 +294,71 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
 				break;
 			}			
 		}
-		
+
+		return encoder;
+	}
+
+	public void Save (string filename)
+	{
+		Save (filename, RawFormat);
+	}
+
+	public void Save(string filename, ImageFormat format) 
+	{
+		ImageCodecInfo encoder = findEncoderForFormat (format);
+
 		if (encoder == null)
-			throw new ArgumentException ("No coded available for format:" + format.Guid);		
-		
-		guid = encoder.Clsid;
-		st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);				
-		GDIPlus.CheckStatus (st);
+			throw new ArgumentException ("No codec available for format:" + format.Guid);
+
+		Save (filename, encoder, null);
 	}
-	
-	internal void setGDIPalette() 
+
+	public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
 	{
-		IntPtr gdipalette;
+		Status st;
+		Guid guid = encoder.Clsid;
 
-		gdipalette = colorPalette.getGDIPalette ();
-		Status st = GDIPlus.GdipSetImagePalette (NativeObject, gdipalette);
-		Marshal.FreeHGlobal (gdipalette);
+		if (encoderParams == null) {
+			st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
+		} else {
+			IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+			st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
+			Marshal.FreeHGlobal (nativeEncoderParams);
+		}
 
 		GDIPlus.CheckStatus (st);
 	}
 
-	[MonoTODO ("Ignoring EncoderParameters")]
-	public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
+	public void Save (Stream stream, ImageFormat format)
 	{
-		Save (stream, new ImageFormat (encoder.FormatID));
+		ImageCodecInfo encoder = findEncoderForFormat (format);
+
+		if (encoder == null)
+			throw new ArgumentException ("No codec available for format:" + format.Guid);
+
+		Save (stream, encoder, null);
 	}
-	
-	[MonoTODO ("Ignoring EncoderParameters")]	
-	public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
+
+	public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
 	{
-		Save (filename, new ImageFormat (encoder.FormatID));
+		Status st;
+		Guid guid = encoder.Clsid;
+
+		if (Environment.OSVersion.Platform == (PlatformID) 128) {
+			GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
+			if (encoderParams == null) {
+				st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.PutBytesDelegate, ref guid, IntPtr.Zero);
+			} else {
+				IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+				st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.PutBytesDelegate, ref guid, nativeEncoderParams);
+				Marshal.FreeHGlobal (nativeEncoderParams);
+			}
+		} else {
+			throw new NotImplementedException ("Image.Save(Stream) (win32)");
+		}
+		GDIPlus.CheckStatus (st);
 	}
-	
+
 	[MonoTODO]	
 	public void SaveAdd(EncoderParameters encoderParams)
 	{

+ 2 - 2
mcs/class/System.Drawing/System.Drawing/gdipFunctions.cs

@@ -901,7 +901,7 @@ namespace System.Drawing
 		internal static extern Status GdipGetEncoderParameterListSize ( IntPtr image, ref Guid encoder, out uint size );
 
 		[DllImport("gdiplus.dll")]
-		internal static extern Status GdipGetEncoderParameterList ( IntPtr image, IntPtr encoder, uint size, out IntPtr buffer );
+		internal static extern Status GdipGetEncoderParameterList ( IntPtr image, ref Guid encoder, uint size, IntPtr buffer );
 		
 		[DllImport("gdiplus.dll")]
 		internal static extern Status GdipImageGetFrameCount (IntPtr image, ref Guid guidDimension, out int count );
@@ -1479,7 +1479,7 @@ namespace System.Drawing
 		[DllImport("gdiplus.dll")]
 		static internal extern Status GdipLoadImageFromDelegate_linux ( StreamGetBytesDelegate getBytes, StreamSeekDelegate doSeek, out IntPtr image);
 		[DllImport("gdiplus.dll")]
-		static internal extern Status GdipSaveImageToDelegate_linux ( IntPtr image, StreamPutBytesDelegate putBytes, byte[] encoderClsID, IntPtr encoderParameters ); // clsid should be Guid
+		static internal extern Status GdipSaveImageToDelegate_linux ( IntPtr image, StreamPutBytesDelegate putBytes, ref Guid encoderClsID, IntPtr encoderParameters );
 		
 #endregion      
 	}               

+ 8 - 0
mcs/class/System.Drawing/System.Drawing/gdipStructs.cs

@@ -124,5 +124,13 @@ namespace System.Drawing
 			
     		}
 	}
+
+	[StructLayout(LayoutKind.Sequential)]
+	internal struct GdipEncoderParameter {
+		internal Guid guid;
+		internal uint numberOfValues;
+		internal EncoderParameterValueType type;
+		internal IntPtr value;
+	}
 }