Re: Transparent Image Copy to Clipboard Adds Blue BG

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



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
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
>


.



Relevant Pages

  • Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
    ... The Windows bitmap specification was drawn up for Windows 3.1 ... Alpha blended bitmaps were not supported. ... The documentation for AlphaBlend function implies that Windows GDI ... an alpha channel. ...
    (microsoft.public.dotnet.framework.windowsforms)
  • Re: Wierd problem when alpha blitting image with text in it
    ... then I alpha blit it to a memory bitmap. ... At this point the premultiplied loaded image and the memory bitmap ...
    (microsoft.public.win32.programmer.gdi)
  • Wierd problem when alpha blitting image with text in it
    ... engine for displaying graphical interfaces drawn with our design tool. ... The base interface (what you see in the background behind the popup) is ... all all the alpha channel bytes are set ot fully transparent. ... The second bitmap is composited onto the first one using a blit (alpha if ...
    (microsoft.public.win32.programmer.gdi)
  • Re: Problems using ordinary GDI operations on 32bit Bitmap
    ... > I'm having a predefined 32bit Bitmap that has an alpha channel. ... > drawing text or general drawing on this bitmap. ... This of course corrupts the bitmap alpha channel. ...
    (microsoft.public.win32.programmer.gdi)
  • Re: loading BMP in ARGB format - loosing Alpha
    ... WindowsXP is the first operating system to support alpha channel bitmaps. ... If your bitmap was created with an alpha channel and saved, ... does not prevent you from testing for it or using the Windows API to render ...
    (microsoft.public.dotnet.framework.drawing)