Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: "Bill Henning" <junk@xxxxxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 21 Dec 2005 11:36:09 -0500
Here's something I tried as an experiment and it worked... It captured the
alpha transparency fine. The only problem is that it flipped the image
over. So I added code to flip it back. Not sure why that happened. But do
you see any issues with doing this like memory leaks or anything?
Note: Our DrawingHelper.DrawImage method allows us to do a flip.
internal static Bitmap PasteAlphaBitmapFromClipboard() {
NativeMethods.OpenClipboard(IntPtr.Zero);
IntPtr hMem = NativeMethods.GetClipboardData(CF_DIBV5);
if (hMem == IntPtr.Zero) {
NativeMethods.CloseClipboard();
return null;
}
IntPtr packedDIBV5 = NativeMethods.GlobalLock(hMem);
BITMAPV5HEADER bmi = (BITMAPV5HEADER)Marshal.PtrToStructure(packedDIBV5,
typeof(BITMAPV5HEADER));
Bitmap bitmap = new Bitmap(bmi.bV5Width, bmi.bV5Height,
(int)(bmi.bV5SizeImage / bmi.bV5Height), PixelFormat.Format32bppArgb,
new IntPtr(packedDIBV5.ToInt32() + bmi.bV5Size));
Bitmap outputBitmap = new Bitmap(bmi.bV5Width, bmi.bV5Height,
PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(outputBitmap);
DrawingHelper.DrawImage(g, bitmap, 0, 0, bmi.bV5Width, bmi.bV5Height, 1.0f,
RotateFlipType.RotateNoneFlipY);
g.Dispose();
bitmap.Dispose();
NativeMethods.GlobalUnlock(hMem);
NativeMethods.CloseClipboard();
return outputBitmap;
}
"Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx> wrote in message
news:%23wmw4AkBGHA.3936@xxxxxxxxxxxxxxxxxxxxxxx
> When you paste a CF_DIBV5 image, you get a handle to
> a packed DIB.
>
> If the application is GDI based, that application must create
> a bitmap with CreateDIBSection and then pre-multiply the alpha
> channel against the colors and use the GDI AlphaBlend function
> for rendering.
>
> If the application is Gdiplus based, that application must create
> a PixelFormat32bppARGB bitmap object and use DrawImage
> for rendering.
>
> For a BI_RGB bitmap, the high order byte (i.e., Alpha ) is not
> used. If that byte is 0x00 (i.e., transparent ), then it will be rendered
> as opaque. The background for the transparent portion of the bitmap
> will be rendered as black.
>
> The original Windows Bitmap 3.1 specification did not include a
> provision for an alpha channel. Any application that receives
> a paste of an alpha channel bitmap must be aware that the alpha
> channel exists and render it accordingly.
>
> That application can either explicitly test for the presence of an
> alpha channel or can use the BITMAPV5HEADER structure
> to ascertain whether or not that bitmap was created with an
> alpha channel.
>
> If you look further in this newsgroup, you will see an
> algorithm that I posted to test for an alpha channel
> bitmap with only a handle (i.e., HBITMAP ) as the
> source.
>
>
>
> "Bill Henning" <junk@xxxxxxxxxxxxxxxxxxxxxxx> wrote in message
> news:OqhuEuiBGHA.2040@xxxxxxxxxxxxxxxxxxxxxxx
>> Getting closer.... removing the 3 bitfield offsets and changing to BI_RGB
>> fixed the offset problem with the pasted image. So now the image matches
>> up however the transparent background of the copied image still renders
>> as black when I paste it. Any ideas?
>>
>> Bill
>>
>>
>>
>> "Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx> wrote in message
>> news:%23SPp3fOBGHA.3916@xxxxxxxxxxxxxxxxxxxxxxx
>>> The clipboard will synthesize the following formats
>>> in addition to the CF_DIBV5:
>>> CF_DIB and CF_BITMAP
>>>
>>> The clipboard may not synthesize the other formats correctly.
>>>
>>> A CF_DIBV5 containes a BITMAPV5HEADER + 3 DWORD bitfields +
>>> the image's bits. The image compression is marked as BI_BITFIELDS
>>> and therefore must contain a color table with 3 DWORDS for the mask.
>>>
>>> This is redundant since the BITMAPV5HEADER contains the masks.
>>>
>>> For 32bpp images, it is normally assumed that the image uses
>>> the default masks with the compression set to BI_RGB.
>>>
>>> You can try editing the code to use BI_RGB compression and get rid of
>>> the
>>> bitfields. The result will be no offset of the image by 3 DWORDs.
>>>
>>> The packed dib will look like the following:
>>> BITMAPV5HEADER <---BI_RGB compression
>>> bitmap bits
>>>
>>>
>>>
>>>
>>> The MSDN documentation
>>> "Bill Henning" <junk@xxxxxxxxxxxxxxxxxxxxxxx> wrote in message
>>> news:O%23u%23JNOBGHA.1028@xxxxxxxxxxxxxxxxxxxxxxx
>>>> Thanks Michael, I tried it out however when I paste an image that was
>>>> copied using this procedure, it seems that the pixels of the icons are
>>>> offset to the right a couple pixels and the transparent area is black.
>>>>
>>>> I'm pasting using the .NET classes so is that perhaps the problem since
>>>> maybe Clipboard.GetDataObject messes up some of the data? I'm using
>>>> DataFormats.Bitmap as the format to retrieve.
>>>>
>>>> Thanks again for your help. The code you posted is exactly what I want
>>>> to do to get the data to the clipboard. Now I just need to retrieve it
>>>> again into an Image class and have it render the same as when it was
>>>> copied.
>>>>
>>>> Bill
>>>>
>>>>
>>>>
>>>> "Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx> wrote in message
>>>> news:%23zCmbdNBGHA.2644@xxxxxxxxxxxxxxxxxxxxxxx
>>>>>I suggest the following:
>>>>>
>>>>> public const uint BI_BITFIELDS = 3;
>>>>> public const uint LCS_WINDOWS_COLOR_SPACE = 2;
>>>>> public const uint LCS_GM_IMAGES = 4;
>>>>> public const uint CF_DIBV5 = 17;
>>>>> public const uint GMEM_MOVEABLE = 0x00000002;
>>>>> public const uint GMEM_ZEROINIT = 0x00000040;
>>>>> public const uint GMEM_DDESHARE = 0x00002000;
>>>>> public const uint GHND = GMEM_MOVEABLE | GMEM_ZEROINIT;
>>>>>
>>>>> [StructLayout(LayoutKind.Sequential)]
>>>>> public struct CIEXYZ
>>>>> {
>>>>> public uint ciexyzX; //FXPT2DOT30
>>>>> public uint ciexyzY; //FXPT2DOT30
>>>>> public uint ciexyzZ; //FXPT2DOT30
>>>>> }
>>>>>
>>>>> [StructLayout(LayoutKind.Sequential)]
>>>>> public struct CIEXYZTRIPLE
>>>>> {
>>>>> public CIEXYZ ciexyzRed;
>>>>> public CIEXYZ ciexyzGreen;
>>>>> public CIEXYZ ciexyzBlue;
>>>>> }
>>>>>
>>>>> [StructLayout(LayoutKind.Sequential)]
>>>>> public struct BITFIELDS
>>>>> {
>>>>> public uint BlueMask;
>>>>> public uint GreenMask;
>>>>> public uint RedMask;
>>>>> }
>>>>>
>>>>> [StructLayout(LayoutKind.Explicit)]
>>>>> public struct BITMAPV5HEADER
>>>>> {
>>>>> [FieldOffset(0)] public uint bV5Size;
>>>>> [FieldOffset(4)] public int bV5Width;
>>>>> [FieldOffset(8)] public int bV5Height;
>>>>> [FieldOffset(12)]public ushort bV5Planes;
>>>>> [FieldOffset(14)]public ushort bV5BitCount;
>>>>> [FieldOffset(16)]public uint bV5Compression;
>>>>> [FieldOffset(20)]public uint bV5SizeImage;
>>>>> [FieldOffset(24)]public int bV5XPelsPerMeter;
>>>>> [FieldOffset(28)]public int bV5YPelsPerMeter;
>>>>> [FieldOffset(32)]public uint bV5ClrUsed;
>>>>> [FieldOffset(36)]public uint bV5ClrImportant;
>>>>> [FieldOffset(40)]public uint bV5RedMask;
>>>>> [FieldOffset(44)]public uint bV5GreenMask;
>>>>> [FieldOffset(48)]public uint bV5BlueMask;
>>>>> [FieldOffset(52)]public uint bV5AlphaMask;
>>>>> [FieldOffset(56)]public uint bV5CSType;
>>>>> [FieldOffset(60)]public CIEXYZTRIPLE bV5Endpoints;
>>>>> [FieldOffset(96)]public uint bV5GammaRed;
>>>>> [FieldOffset(100)]public uint bV5GammaGreen;
>>>>> [FieldOffset(104)]public uint bV5GammaBlue;
>>>>> [FieldOffset(108)]public uint bV5Intent;
>>>>> [FieldOffset(112)]public uint bV5ProfileData;
>>>>> [FieldOffset(116)]public uint bV5ProfileSize;
>>>>> [FieldOffset(120)]public uint bV5Reserved;
>>>>> }
>>>>>
>>>>> [DllImport("user32.dll")]
>>>>> static extern bool OpenClipboard(IntPtr hWndNewOwner);
>>>>>
>>>>> [DllImport("user32.dll")]
>>>>> static extern bool EmptyClipboard();
>>>>>
>>>>> [DllImport("user32.dll")]
>>>>> static extern bool CloseClipboard();
>>>>>
>>>>> [DllImport("user32.dll")]
>>>>> static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
>>>>>
>>>>> [DllImport("kernel32.dll")]
>>>>> static extern IntPtr GlobalAlloc(uint uFlags, uint dwBytes);
>>>>>
>>>>> [DllImport("kernel32.dll")]
>>>>> static extern IntPtr GlobalLock(IntPtr hMem);
>>>>>
>>>>> [DllImport("kernel32.dll")]
>>>>> static extern bool GlobalUnlock(IntPtr hMem);
>>>>>
>>>>> public IntPtr CreatePackedDIBV5( Bitmap bm )
>>>>> {
>>>>> BitmapData bmData = bm.LockBits( new Rectangle(0,0,bm.Width,
>>>>> bm.Height),
>>>>> ImageLockMode.ReadOnly, bm.PixelFormat);
>>>>> uint bufferLen = (uint)(Marshal.SizeOf(typeof(BITMAPV5HEADER)) +
>>>>> (Marshal.SizeOf(typeof(uint)) * 3) + bmData.Height *
>>>>> bmData.Stride);
>>>>> IntPtr hMem = GlobalAlloc(GHND | GMEM_DDESHARE, bufferLen);
>>>>> IntPtr packedDIBV5 = GlobalLock(hMem);
>>>>> BITMAPV5HEADER bmi = (BITMAPV5HEADER)Marshal.PtrToStructure(
>>>>> packedDIBV5, typeof(BITMAPV5HEADER));
>>>>> bmi.bV5Size = (uint)Marshal.SizeOf(typeof(BITMAPV5HEADER));
>>>>> bmi.bV5Width = bmData.Width;
>>>>> bmi.bV5Height = bmData.Height;
>>>>> bmi.bV5BitCount = 32;
>>>>> bmi.bV5Planes = 1;
>>>>> bmi.bV5Compression = BI_BITFIELDS;
>>>>> bmi.bV5XPelsPerMeter = 0;
>>>>> bmi.bV5YPelsPerMeter = 0;
>>>>> bmi.bV5ClrUsed = 0;
>>>>> bmi.bV5ClrImportant = 0;
>>>>> bmi.bV5BlueMask = 0x000000FF;
>>>>> bmi.bV5GreenMask = 0x0000FF00;
>>>>> bmi.bV5RedMask = 0x00FF0000;
>>>>> bmi.bV5AlphaMask = 0xFF000000;
>>>>> bmi.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
>>>>> bmi.bV5GammaBlue = 0;
>>>>> bmi.bV5GammaGreen = 0;
>>>>> bmi.bV5GammaRed = 0;
>>>>> bmi.bV5ProfileData = 0;
>>>>> bmi.bV5ProfileSize = 0;
>>>>> bmi.bV5Reserved = 0;
>>>>> bmi.bV5Intent = LCS_GM_IMAGES;
>>>>> bmi.bV5SizeImage = (uint)(bmData.Height * bmData.Stride);
>>>>> bmi.bV5Endpoints.ciexyzBlue.ciexyzX =
>>>>> bmi.bV5Endpoints.ciexyzBlue.ciexyzY =
>>>>> bmi.bV5Endpoints.ciexyzBlue.ciexyzZ = 0;
>>>>> bmi.bV5Endpoints.ciexyzGreen.ciexyzX =
>>>>> bmi.bV5Endpoints.ciexyzGreen.ciexyzY =
>>>>> bmi.bV5Endpoints.ciexyzGreen.ciexyzZ = 0;
>>>>> bmi.bV5Endpoints.ciexyzRed.ciexyzX =
>>>>> bmi.bV5Endpoints.ciexyzRed.ciexyzY =
>>>>> bmi.bV5Endpoints.ciexyzRed.ciexyzZ = 0;
>>>>> Marshal.StructureToPtr(bmi, packedDIBV5, false);
>>>>>
>>>>> BITFIELDS Masks = (BITFIELDS)Marshal.PtrToStructure(
>>>>> (IntPtr)(packedDIBV5.ToInt32() + bmi.bV5Size), typeof(BITFIELDS));
>>>>> Masks.BlueMask = 0x000000FF;
>>>>> Masks.GreenMask = 0x0000FF00;
>>>>> Masks.RedMask = 0x00FF0000;
>>>>> Marshal.StructureToPtr(Masks, (IntPtr)(packedDIBV5.ToInt32() +
>>>>> bmi.bV5Size), false);
>>>>>
>>>>> long offsetBits = bmi.bV5Size + Marshal.SizeOf(typeof(uint)) * 3;
>>>>> IntPtr bits = (IntPtr)(packedDIBV5.ToInt32() + offsetBits);
>>>>>
>>>>> for ( int y = 0; y < bmData.Height; y++ )
>>>>> {
>>>>> IntPtr DstDib = (IntPtr)(bits.ToInt32() + (y* bmData.Stride));
>>>>> IntPtr SrcDib = (IntPtr)(bmData.Scan0.ToInt32() +
>>>>> ((bmData.Height-1-y)* bmData.Stride));
>>>>>
>>>>> for ( int x = 0; x < bmData.Width; x++ )
>>>>> {
>>>>> Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib));
>>>>> DstDib = (IntPtr)(DstDib.ToInt32() + 4);
>>>>> SrcDib = (IntPtr)(SrcDib.ToInt32() + 4);
>>>>> }
>>>>> }
>>>>>
>>>>> bm.UnlockBits(bmData);
>>>>>
>>>>> GlobalUnlock(hMem);
>>>>>
>>>>> return hMem;
>>>>> }
>>>>>
>>>>> An example on how to use this function follows:
>>>>> IntPtr packedDIBV5 = CreatePackedDIBV5(AlphaBitmap);
>>>>> OpenClipboard(this.Handle);
>>>>> EmptyClipboard();
>>>>> SetClipboardData(CF_DIBV5, packedDIBV5);
>>>>> CloseClipboard();
>>>>>
>>>>> I hope this helps!
>>>>>
>>>>> "Bill Henning" <junk@xxxxxxxxxxxxxxxxxxxxxxx> wrote in message
>>>>> news:OiZybeEBGHA.2656@xxxxxxxxxxxxxxxxxxxxxxx
>>>>>> Thanks for the reply Michael. I'm not an expert with the GDI APIs so
>>>>>> can you help me out? Here's what I wrote so far:
>>>>>>
>>>>>> internal void CopyAlphaBitmapToClipboard(Bitmap image) {
>>>>>> BITMAPV4HEADER bih = new BITMAPV4HEADER();
>>>>>> bih.bV5Size =
>>>>>> System.Runtime.InteropServices.Marshal.SizeOf(typeof(BITMAPV4HEADER));
>>>>>> bih.bV5Width = image.Width;
>>>>>> bih.bV5Height = image.Height;
>>>>>> bih.bV5Planes = 1;
>>>>>> bih.bV5BitCount = 32;
>>>>>> bih.bV5Compression = 0;
>>>>>> bih.bV5RedMask = 0x00FF0000;
>>>>>> bih.bV5GreenMask = 0x0000FF00;
>>>>>> bih.bV5BlueMask = 0x000000FF;
>>>>>> bih.bV5AlphaMask = 0xFF000000;
>>>>>> BITMAPINFO bi = new BITMAPINFO();
>>>>>> bi.bmiHeader = bih;
>>>>>>
>>>>>> Graphics g = Graphics.FromImage(image);
>>>>>> IntPtr imageHdc = g.GetHdc();
>>>>>>
>>>>>> IntPtr hdc = NativeMethods.CreateCompatibleDC(imageHdc);
>>>>>>
>>>>>> // Create the DIB section with an alpha channel
>>>>>> IntPtr ppvBits = IntPtr.Zero;
>>>>>> const int DIB_RGB_COLORS = 0;
>>>>>> IntPtr hBitmap = NativeMethods.CreateDIBSection(hdc, bi,
>>>>>> DIB_RGB_COLORS, out ppvBits, IntPtr.Zero, 0);
>>>>>>
>>>>>> const int SRCCOPY = 0x00CC0020;
>>>>>> NativeMethods.BitBlt(hdc, 0, 0, image.Width, image.Height, imageHdc,
>>>>>> 0, 0, SRCCOPY); // SRCCOPY
>>>>>> NativeMethods.DeleteDC(hdc);
>>>>>>
>>>>>> g.ReleaseHdc(imageHdc);
>>>>>> g.Dispose();
>>>>>>
>>>>>> // TODO: Do more stuff here
>>>>>> }
>>>>>>
>>>>>> Is that correct so far or do you see any bugs with bad
>>>>>> initializations or memory leaks? I used the V4 header since I think
>>>>>> it has the alpha stuff I need and was less to define. :)
>>>>>>
>>>>>> What I think I have in the procedure above is a handle to a bitmap
>>>>>> (hBitmap) that is still open. Somehow I need to send that to a
>>>>>> SetClipboardData API call. But I think I need a global memory handle
>>>>>> as you said. What do I need to add to get that working?
>>>>>>
>>>>>> Thanks so much for your help!
>>>>>>
>>>>>> Bill
>>>>>>
>>>>>>
>>>>>> "Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx> wrote in
>>>>>> message news:uDNOSv0AGHA.2040@xxxxxxxxxxxxxxxxxxxxxxx
>>>>>>> The CF_DIBV5 clipboard format preserves the alpha channel
>>>>>>> by design.
>>>>>>>
>>>>>>> This clipboard format requires that you create
>>>>>>> a packed DIB from a DIBSECTION created with the BITMAPV5HEADER.
>>>>>>>
>>>>>>> You can use P-INVOKE with CreateDIBSection for your bitmap
>>>>>>> and then transfer the bits with LockBits, BitBlt or DrawImage.
>>>>>>>
>>>>>>> You create a global memory object to represent the packed DIB.
>>>>>>> This packed DIB will include the BITMAPV5HEADER and the bitmap's
>>>>>>> bits.
>>>>>>>
>>>>>>> Place the global memory handle on the clipboard.
>>>>>>>
>>>>>>> Clipboard.SetDataObject(image) places a BI_RGB bitmap
>>>>>>> on the clipboard. Per the documentation, the high byte in each
>>>>>>> DWORD is not used.
>>>>>>>
>>>>>>> There is no way for an aplication to natively know that the bitmap
>>>>>>> that is retrieved from the clipboard with a CF_DIB or
>>>>>>> CF_BITMAP clipboard format has an alpha channel.
>>>>>>>
>>>>>>> An application could test but a CF_DIBV5 clipboard format
>>>>>>> advertises that an alpha channel is present!
>>>>>>>
>>>>>>>
>>>>>>> "Bill Henning" <junk@xxxxxxxxxxxxxxxxxxxxxxx> wrote in message
>>>>>>> news:%23Qdy%23T0AGHA.2676@xxxxxxxxxxxxxxxxxxxxxxx
>>>>>>>> Hi there... I am running in the .NET 1.0 framework have an object
>>>>>>>> that has an Image property. Upon a certain event, I want to copy
>>>>>>>> the Image to the Clipboard. This is easy enough:
>>>>>>>> Clipboard.SetDataObject(image)
>>>>>>>>
>>>>>>>> However, if the Image has a transparent background, when I go to
>>>>>>>> paste the Image into a drawing app like Paint or Photoshop, the
>>>>>>>> transparent area of the Image has been replaced by a blue color.
>>>>>>>> So it seems that the Image isn't telling the clipboard what parts
>>>>>>>> need to be transparent. This doesn't make sense since it can draw
>>>>>>>> the Image transparent areas fine.
>>>>>>>>
>>>>>>>> Can anyone explain what is wrong here and if this is some sort of
>>>>>>>> .NET framework limitation, provide either C# or VB.NET code to work
>>>>>>>> around it?
>>>>>>>>
>>>>>>>> Thanks in advance!
>>>>>>>>
>>>>>>>> Bill
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
>
.
- Follow-Ups:
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Michael Phillips, Jr.
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- References:
- Transparent Image Copy to Clipboard Adds Blue BG
- From: Bill Henning
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Michael Phillips, Jr.
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Bill Henning
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Michael Phillips, Jr.
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Bill Henning
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Michael Phillips, Jr.
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Bill Henning
- Re: Transparent Image Copy to Clipboard Adds Blue BG
- From: Michael Phillips, Jr.
- Transparent Image Copy to Clipboard Adds Blue BG
- Prev by Date: Superscript text
- Next by Date: Re: Transparent Image Copy to Clipboard Adds Blue BG
- Previous by thread: Re: Transparent Image Copy to Clipboard Adds Blue BG
- Next by thread: Re: Transparent Image Copy to Clipboard Adds Blue BG
- Index(es):
Relevant Pages
|