Hello
Copying transparent png images to the clipboard has become a question for me.
How can I save a transparent image to the clipboard and use it in graphic software such as Photoshop or Corel?
I tried several methods but they didn't work. If any of my friends have done this, please help and share the code.
I'll give you an example. I used two methods, one with alpha image control and the other with gdi+. Alpha Image Control v2
It actually uses PNG as the example format for the general technique.
Thanks for your help fafalone
I saw your sample project. The image inside the form itself is copied and pasted fine
but I want to save the image to the clipboard and place it in a graphics software like Photoshop without a background.
I tested it in these softwares and it didn't work. Dragging the image didn't work either.
Didn't work like transparency wasn't preserved or Photoshop just doesn't support paste/drop?
If Photoshop doesn't allow pasting or dropping then it just plain doesn't support the CF_PNG format. You could try other types like CF_DIBV5... Or if it will load a normal file drop like if you pasted from Explorer.
You could check what formats PhotoDemon is using with a clipboard format tool, checking its source, or checking the clipboard yourself.
My code for CF_PNG does work with other apps though so it's likely CF_DIBV5 or file based.
Here are the clipboard formats avaiable after copying a selection from PhotoDemon
Code:
Unknown 513
PRIVATE PNG
CF_BITMAP A bitmap compatible with Windows 2.x
CF_DIBV5 Memory object containing BITMAPV5HEADER structure followed by the bitmap color space information and the bitmap bits (2000/XP only)
CF_DIB Global memory block containing a Windows device-independent bitmap (DIB) as a BITMAPINFO structure followed by the bitmap bits
PNG and CF_DIBV5 support transparency but the latter is mostly unsupported by (other) painting apps.
My DragFormats demo pastes into PhotoDemon with transparency preserved, so maybe it's Photoshop requiring an IStream option for the format which is the only difference, but it's probably only supporting CF_DIBV5.
This code uses CF_DIBV5 The image is copied but with a black background.
HTML Code:
Option Explicit
Private Declare Function GdiplusStartup Lib "gdiplus.dll" (token As Long, inputbuf As GDIPlusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
Private Declare Function GdiplusShutdown Lib "gdiplus.dll" (ByVal token As Long) As Long
Private Declare Function GdipCreateBitmapFromFile Lib "gdiplus.dll" (ByVal filename As Long, bitmap As Long) As Long
Private Declare Function GdipBitmapLockBits Lib "gdiplus.dll" (ByVal bitmap As Long, rect As Any, ByVal flags As Long, ByVal PixelFormat As Long, lockedBitmapData As bitmapData) As Long
Private Declare Function GdipBitmapUnlockBits Lib "gdiplus.dll" (ByVal bitmap As Long, lockedBitmapData As bitmapData) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus.dll" (ByVal image As Long) As Long
Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Const GMEM_MOVEABLE = &H2
Private Const GMEM_ZEROINIT = &H40
Private Const CF_DIBV5 = 17
Private Const PixelFormat32bppARGB = &H26200A
Private Const BI_RGB = 0
Private Const LCS_sRGB = 1934772034
Private Type GDIPlusStartupInput
GdiplusVersion As Long
DebugEventCallback As Long
SuppressBackgroundThread As Long
SuppressExternalCodecs As Long
End Type
Private Type bitmapData
Width As Long
Height As Long
Stride As Long
PixelFormat As Long
Scan0 As Long
Reserved As Long
End Type
Private Type BITMAPV5HEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
bV5RedMask As Long
bV5GreenMask As Long
bV5BlueMask As Long
bV5AlphaMask As Long
bV5CSType As Long
bV5Endpoints(0 To 35) As Byte
bV5GammaRed As Long
bV5GammaGreen As Long
bV5GammaBlue As Long
bV5Intent As Long
bV5ProfileData As Long
bV5ProfileSize As Long
bV5Reserved As Long
End Type
Sub CopyPngToClipboard()
Dim imgPath As String
Dim token As Long
Dim bitmap As Long
Dim bitmapData As bitmapData
Dim hMem As Long
Dim pData As Long
Dim bi As BITMAPV5HEADER
Dim dataSize As Long
Dim startupInput As GDIPlusStartupInput
imgPath = "C:\Users\Ace\Desktop\Image2.png"
If Dir(imgPath) = "" Then
MsgBox "Image file not found: " & imgPath
Exit Sub
End If
startupInput.GdiplusVersion = 1
startupInput.DebugEventCallback = 0
startupInput.SuppressBackgroundThread = 0
startupInput.SuppressExternalCodecs = 0
If GdiplusStartup(token, startupInput) <> 0 Then
MsgBox "Error starting GDI+!"
Exit Sub
End If
If GdipCreateBitmapFromFile(StrPtr(imgPath), bitmap) <> 0 Then
MsgBox "Error loading image!"
GdiplusShutdown token
Exit Sub
End If
If GdipBitmapLockBits(bitmap, ByVal 0&, 3, PixelFormat32bppARGB, bitmapData) <> 0 Then
MsgBox "Error locking Bitmap!"
GdipDisposeImage bitmap
GdiplusShutdown token
Exit Sub
End If
With bi
.biSize = Len(bi)
.biWidth = bitmapData.Width
.biHeight = -bitmapData.Height
.biPlanes = 1
.biBitCount = 32
.biCompression = BI_RGB
.biSizeImage = bitmapData.Stride * bitmapData.Height
.biXPelsPerMeter = 0
.biYPelsPerMeter = 0
.biClrUsed = 0
.biClrImportant = 0
.bV5RedMask = &HFF&
.bV5GreenMask = &HFF00&
.bV5BlueMask = &HFF0000
.bV5AlphaMask = &HFF000000
.bV5CSType = LCS_sRGB
.bV5Intent = 0
End With
dataSize = Len(bi) + bi.biSizeImage
hMem = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, dataSize)
If hMem = 0 Then
MsgBox "Error allocating memory!"
GoTo Cleanup
End If
pData = GlobalLock(hMem)
If pData = 0 Then
MsgBox "Error locking memory!"
GlobalFree hMem
GoTo Cleanup
End If
CopyMemory ByVal pData, bi, Len(bi)
CopyMemory ByVal (pData + Len(bi)), ByVal bitmapData.Scan0, bi.biSizeImage
GlobalUnlock hMem
If OpenClipboard(0&) = 0 Then
MsgBox "Error opening clipboard!"
GlobalFree hMem
GoTo Cleanup
End If
If EmptyClipboard = 0 Then
MsgBox "Error clearing clipboard!"
CloseClipboard
GlobalFree hMem
GoTo Cleanup
End If
If SetClipboardData(CF_DIBV5, hMem) = 0 Then
MsgBox "Error setting clipboard data!"
EmptyClipboard
CloseClipboard
GlobalFree hMem
GoTo Cleanup
End If
CloseClipboard
MsgBox "Image successfully copied to clipboard!"
Cleanup:
GdipBitmapUnlockBits bitmap, bitmapData
GdipDisposeImage bitmap
GdiplusShutdown token
End Sub
Private Sub Command1_Click()
CopyPngToClipboard
End Sub
> The image is copied but with a black background.
Where did you paste it to see this black background? MS Paint?
Also, you can experiment copying a transparent image from Chrome (or any browser) and see what clipboard formats these provide. Pretty sure only (custom) "PNG" clipboard format will be available with valid alpha channel.
> The image is copied but with a black background.
Where did you paste it to see this black background? MS Paint?
Also, you can experiment copying a transparent image from Chrome (or any browser) and see what clipboard formats these provide. Pretty sure only (custom) "PNG" clipboard format will be available with valid alpha channel.
cheers,
</wqw>
I tested it in Photoshop and the image is completely clear.
It's interesting, I copy it from within the browser, but the background is still black !?
I also tested with different png files.
But when I copy from the browser to CorelDRAW 2025, there is no problem and the image is completely clear.
Maybe each software supports a specific format?
But when I copy from PhotoDemon, it works fine in all software and the image is copied clearly without the background.
Last edited by Mojtaba; Mar 19th, 2025 at 09:38 AM.
The "PNG" clipboard format we are talking about here is a "custom" format; actually you can use any name you like. To Copy an image to the clipboard as a custom format, you need to register it first:
If you clear the clipboard first, before you COPY, you will find that despite you only Copy a single format, there are 4 available now (the system automatically makes the extra 3 for a wider coverage of users):
CF_BITMAP
CF_DIB
CF_DIBV5
PNG (assuming the custom format name you used is PNG)
All of the above 4 formats are with transparency and translucency. (I've tested it, one by one, on my own Paint Program and Clipboard Viewer before I do this posting. It is just that, on doing PASTE, I defaulted the "PNG" one as 32-BPP, and treated others by default as 24-BPP - the user has to switch it to 32-BPP on screen.)
Last edited by Brenker; Mar 19th, 2025 at 04:44 PM.
What are you using to set png where it's auto converting? With the others yeah but it's not doing it with my code, and photodemon is manually putting them all on it looks like.
If you clear the clipboard first, before you COPY, you will find that despite you only Copy a single format, there are 4 available now (the system automatically makes the extra 3 for a wider coverage of users):
CF_BITMAP
CF_DIB
CF_DIBV5
PNG (assuming the custom format name you used is PNG)
It's also of interest how you're getting transparency in CF_DIB and CF_BITMAP; haven't seen that.
"Clipboard" is such that, when you do a COPY, it automatically create additional clipboard formats, in order to suit a wider range of users who have different needs.
If you COPY, say an 8-BPP GIF with a designated transparent color (out of a max of 256 colors), or say a 24-BPP PNG with a designated transparent color (out of possible thousands of colors), there is no way for you to PASTE as transparent DIB. This is because the DIB itself doesn't carry with it the information of the designated transparent color.
A 32-BPP one is different. When you COPY it to the clipboard, its 4th bytes of the image data contain alpha values, subsequently enabling the displayed image with alpha effects.
Attached below is a screenshot of my Clipboard Viewer, showing a preview of both the 24-BPP and 32-BPP images from CF_BITMAP format. At the bottom part there is a "Note: If image is of PrnScreen, only Opaque applicable", this is just to remind users to avoid displaying a PrnScreen image at 32-BPP.
Edited:
I finally managed to upload the said screenshot.
Last edited by Brenker; Mar 19th, 2025 at 09:00 PM.
Perhaps there are differences among systems/arrangements. I would suggest that you do an odinary COPY first, say at CF_BITMAP format, right before you do a custom format.
Last edited by Brenker; Mar 19th, 2025 at 09:30 PM.
Yes I'm aware of the additional automatically created formats for CF_DIB/CF_DIBV5/CF_BITMAP but it's not doing that with CF_PNG for me.
For me too. Never seen the OS understanding *custom* format which PNG in current thread is.
Theoretically CF_DIBV5 could contain transparency but most apps don't support it i.e. they just paste opaque CF_DIB which is always available if CF_DIBV5 is set as OS translates CF_DIBV5 -> CF_DIB.
I now traced my COPY code to the very start, and found there was indeed a call made to copy a CF_BITMAP, before the subsequent creation of a custom format. Both fafalone and wqweto are correct, I am sorry for my mistake.
The code is a bit complicated in my case. There are 4 "COPY" submenus involved: "Copy As 32-BPP (whole or region)", "Copy As 24-BPP (whole or region)". "Copy Region Top Layer Only" and "Copy Picture On Screen Only". Region here may be an area selection (in oval, rectangular or other shape), a layer of newly written text, or a layer of newly pasted image, both of which can be dragged to a wanted position before fixing them.
I also found that in one place I used a PictureBox (in lieu of a 32-BPP DIB) to "receive" the incoming 32-BPP Image from the clipboard. (I recall I felt puzzled when I first found that I was able to use a PictureBox as a container for a 32-BPP image and the alpha values were still intact.)
Alpha values are still intact but ignored while mostly preserved (not overwritten) by GDI operations but not always i.e. their contents is subject to undefined behavior.