Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Share as much Bitmap code with Windows as possible (#25922)
Browse files Browse the repository at this point in the history
  • Loading branch information
hughbe authored and safern committed Dec 21, 2017
1 parent bd4e892 commit ec22edc
Show file tree
Hide file tree
Showing 14 changed files with 627 additions and 954 deletions.
2 changes: 2 additions & 0 deletions src/System.Drawing.Common/src/System.Drawing.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp'))">
<!-- Shared source code, all configurations -->
<Compile Include="System\Drawing\Bitmap.cs" />
<Compile Include="System\Drawing\BitmapSuffixInSameAssemblyAttribute.cs" />
<Compile Include="System\Drawing\BitmapSuffixInSatelliteAssemblyAttribute.cs" />
<Compile Include="System\Drawing\Brushes.cs" />
<Compile Include="System\Drawing\CharacterRange.cs" />
<Compile Include="System\Drawing\ColorTranslator.cs" />
<Compile Include="System\Drawing\ContentAlignment.cs" />
<Compile Include="System\Drawing\IDeviceContext.cs" />
<Compile Include="System\Drawing\Image.cs" />
<Compile Include="System\Drawing\GdiplusNative.cs" />
<Compile Include="System\Drawing\Graphics.cs" />
<Compile Include="System\Drawing\GraphicsUnit.cs" />
Expand Down
232 changes: 6 additions & 226 deletions src/System.Drawing.Common/src/System/Drawing/Bitmap.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,82 +50,22 @@ namespace System.Drawing
#if !NETCORE
[Editor ("System.Drawing.Design.BitmapEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
#endif
public sealed class Bitmap : Image
public sealed partial class Bitmap
{
#region constructors
// constructors

// required for XmlSerializer (#323246)
private Bitmap()
{
}

internal Bitmap(IntPtr ptr)
{
nativeObject = ptr;
}

// Usually called when cloning images that need to have
// not only the handle saved, but also the underlying stream
// (when using MS GDI+ and IStream we must ensure the stream stays alive for all the life of the Image)
internal Bitmap(IntPtr ptr, Stream stream)
{
nativeObject = ptr;
nativeImage = ptr;
}

public Bitmap(int width, int height) : this(width, height, PixelFormat.Format32bppArgb)
{
}

public Bitmap(int width, int height, Graphics g)
{
if (g == null)
throw new ArgumentNullException("g");

IntPtr bmp;
int s = SafeNativeMethods.Gdip.GdipCreateBitmapFromGraphics(width, height, g.nativeObject, out bmp);
SafeNativeMethods.Gdip.CheckStatus(s);
nativeObject = bmp;
}

public Bitmap(int width, int height, PixelFormat format)
{
IntPtr bmp;
int s = SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(width, height, 0, format, IntPtr.Zero, out bmp);
SafeNativeMethods.Gdip.CheckStatus(s);
nativeObject = bmp;

}

public Bitmap(Image original) : this(original, original.Width, original.Height) { }

public Bitmap(Stream stream) : this(stream, false) { }

public Bitmap(string filename) : this(filename, false) { }

public Bitmap(Image original, Size newSize) : this(original, newSize.Width, newSize.Height) { }

public Bitmap(Stream stream, bool useIcm)
{
// false: stream is owned by user code
nativeObject = InitFromStream(stream);
}

public Bitmap(string filename, bool useIcm)
{
if (filename == null)
throw new ArgumentNullException("filename");

IntPtr imagePtr;
int st;

if (useIcm)
st = SafeNativeMethods.Gdip.GdipCreateBitmapFromFileICM(filename, out imagePtr);
else
st = SafeNativeMethods.Gdip.GdipCreateBitmapFromFile(filename, out imagePtr);

SafeNativeMethods.Gdip.CheckStatus(st);
nativeObject = imagePtr;
nativeImage = InitFromStream(stream);
}

public Bitmap(Type type, string resource)
Expand All @@ -144,178 +84,18 @@ public Bitmap(Type type, string resource)
throw new FileNotFoundException(msg);
}

nativeObject = InitFromStream(s);
}

public Bitmap(Image original, int width, int height) : this(width, height, PixelFormat.Format32bppArgb)
{
Graphics graphics = Graphics.FromImage(this);

graphics.DrawImage(original, 0, 0, width, height);
graphics.Dispose();
}

public Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0)
{
IntPtr bmp;

int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(width, height, stride, format, scan0, out bmp);
SafeNativeMethods.Gdip.CheckStatus(status);
nativeObject = bmp;
nativeImage = InitFromStream(s);
}

private Bitmap(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endregion
// methods
public Color GetPixel(int x, int y)
{

int argb;

int s = SafeNativeMethods.Gdip.GdipBitmapGetPixel(nativeObject, x, y, out argb);
SafeNativeMethods.Gdip.CheckStatus(s);

return Color.FromArgb(argb);
}

public void SetPixel(int x, int y, Color color)
{
int s = SafeNativeMethods.Gdip.GdipBitmapSetPixel(nativeObject, x, y, color.ToArgb());
if (s == SafeNativeMethods.Gdip.InvalidParameter)
{
// check is done in case of an error only to avoid another
// unmanaged call for normal (successful) calls
if ((this.PixelFormat & PixelFormat.Indexed) != 0)
{
string msg = "SetPixel cannot be called on indexed bitmaps.";
throw new InvalidOperationException(msg);
}
}
SafeNativeMethods.Gdip.CheckStatus(s);
}

public Bitmap Clone(Rectangle rect, PixelFormat format)
{
IntPtr bmp;
int status = SafeNativeMethods.Gdip.GdipCloneBitmapAreaI(rect.X, rect.Y, rect.Width, rect.Height,
format, nativeObject, out bmp);
SafeNativeMethods.Gdip.CheckStatus(status);
return new Bitmap(bmp);
}

public Bitmap Clone(RectangleF rect, PixelFormat format)
{
IntPtr bmp;
int status = SafeNativeMethods.Gdip.GdipCloneBitmapArea(rect.X, rect.Y, rect.Width, rect.Height,
format, nativeObject, out bmp);
SafeNativeMethods.Gdip.CheckStatus(status);
return new Bitmap(bmp);
}

public static Bitmap FromHicon(IntPtr hicon)
{
IntPtr bitmap;
int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromHICON(hicon, out bitmap);
SafeNativeMethods.Gdip.CheckStatus(status);
return new Bitmap(bitmap);
}

public static Bitmap FromResource(IntPtr hinstance, string bitmapName) //TODO: Untested
{
IntPtr bitmap;
int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromResource(hinstance, bitmapName, out bitmap);
SafeNativeMethods.Gdip.CheckStatus(status);
return new Bitmap(bitmap);
}

[EditorBrowsable(EditorBrowsableState.Advanced)]
public IntPtr GetHbitmap()
{
return GetHbitmap(Color.Gray);
}

[EditorBrowsable(EditorBrowsableState.Advanced)]
public IntPtr GetHbitmap(Color background)
{
IntPtr HandleBmp;

int status = SafeNativeMethods.Gdip.GdipCreateHBITMAPFromBitmap(nativeObject, out HandleBmp, background.ToArgb());
SafeNativeMethods.Gdip.CheckStatus(status);

return HandleBmp;
}

[EditorBrowsable(EditorBrowsableState.Advanced)]
public IntPtr GetHicon()
{
IntPtr HandleIcon;

int status = SafeNativeMethods.Gdip.GdipCreateHICONFromBitmap(nativeObject, out HandleIcon);
SafeNativeMethods.Gdip.CheckStatus(status);

return HandleIcon;
}

public BitmapData LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format)
{
BitmapData result = new BitmapData();
return LockBits(rect, flags, format, result);
}

public
BitmapData LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format, BitmapData bitmapData)
{
int status = SafeNativeMethods.Gdip.GdipBitmapLockBits(nativeObject, ref rect, flags, format, bitmapData);
if (status == 7)
{
status = 8; // libgdiplus has the wrong error code mapping for this state.
}
//NOTE: scan0 points to piece of memory allocated in the unmanaged space
SafeNativeMethods.Gdip.CheckStatus(status);

return bitmapData;
}

public void MakeTransparent()
{
Color clr = GetPixel(0, 0);
MakeTransparent(clr);
}

public void MakeTransparent(Color transparentColor)
{
// We have to draw always over a 32-bitmap surface that supports alpha channel
Bitmap bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
Graphics gr = Graphics.FromImage(bmp);
Rectangle destRect = new Rectangle(0, 0, Width, Height);
ImageAttributes imageAttr = new ImageAttributes();

imageAttr.SetColorKey(transparentColor, transparentColor);

gr.DrawImage(this, destRect, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr);

IntPtr oldBmp = nativeObject;
nativeObject = bmp.nativeObject;
bmp.nativeObject = oldBmp;

gr.Dispose();
bmp.Dispose();
imageAttr.Dispose();
}

public void SetResolution(float xDpi, float yDpi)
{
int status = SafeNativeMethods.Gdip.GdipBitmapSetResolution(nativeObject, xDpi, yDpi);
SafeNativeMethods.Gdip.CheckStatus(status);
}

public void UnlockBits(BitmapData bitmapdata)
private void ValidateBitmap(IntPtr bitmap)
{
int status = SafeNativeMethods.Gdip.GdipBitmapUnlockBits(nativeObject, bitmapdata);
SafeNativeMethods.Gdip.CheckStatus(status);
// No validation is performed on Unix.
}
}
}

0 comments on commit ec22edc

Please sign in to comment.