How to save image in clipboard.

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

06 Sep 2021, 13:03

As a result, I don't see any advantages to use GDIp. Even though in some cases it can be faster, but WIC packs files better (and gives an ability to use custom codecs).
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

07 Sep 2021, 03:05

It depends on priority - much better speed in some cases vs better compression.
I prefer speed, because if I need really good compression I will not use wic, but use custom algorithms.
For example this one:
https://pngquant.org/
Also may be You can increase wic speed by modifying wic png encoder options.
https://docs.microsoft.com/en-us/windows/win32/wic/-wic-creating-encoder
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

07 Sep 2021, 07:44

malcev wrote: I prefer speed
If you prefer speed, use c++, not AHK. :)
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

07 Sep 2021, 14:52

The same I can say to You - If You need packing files better, use C++, not ahk. :)
BTW my idea why wic is slower was right.
It is because of it encodes with WICPngFilterUnspecified.
If We replace it with WICPngFilterNone like this, then the size and the speed will be +- the same as with gdi. ;)

Code: Select all

HBitmapToPngWIC(hBitmap, destPngFilePath) {
   static CLSID_WICImagingFactory  := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
         , IID_IWICImagingFactory  := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
         , GUID_ContainerFormatPng := "{1B7CFAF4-713F-473C-BBCD-6137425FAEAF}"
         , WICBitmapUseAlpha := 0x00000000, GENERIC_WRITE := 0x40000000
         , WICBitmapEncoderNoCache := 0x00000002
         
   VarSetCapacity(GUID, 16, 0)
   DllCall("Ole32\CLSIDFromString", "WStr", GUID_ContainerFormatPng, "Ptr", &GUID)
   IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
   ; IWICImagingFactory::CreateBitmapFromHBITMAP
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*21), "Ptr", IWICImagingFactory, "Ptr", hBitmap, "Ptr", 0, "UInt", WICBitmapUseAlpha, "PtrP", IWICBitmap)
   ; IWICImagingFactory::CreateStream
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*14), "Ptr", IWICImagingFactory, "PtrP", IWICStream)
   ; IWICStream::InitializeFromFilename
   DllCall(NumGet(NumGet(IWICStream + 0) + A_PtrSize*15), "Ptr", IWICStream, "WStr", destPngFilePath, "UInt", GENERIC_WRITE)
   ; IWICImagingFactory::CreateEncoder
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*8), "Ptr", IWICImagingFactory, "Ptr", &GUID, "Ptr", 0, "PtrP", IWICBitmapEncoder)
   ; IWICBitmapEncoder::Initialize
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*3), "Ptr", IWICBitmapEncoder, "Ptr", IWICStream, "UInt", WICBitmapEncoderNoCache)

   ; IWICBitmapEncoder::CreateNewFrame
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*10), "Ptr", IWICBitmapEncoder, "PtrP", IWICBitmapFrameEncode, "PtrP", pPropertybag)
   VarSetCapacity(variant, 8+A_PtrSize*2, 0)
   NumPut(VT_UI1 := 0x11, variant, 0, "ushort")
   NumPut(WICPngFilterNone := 1, variant, 8, "uchar")
   VarSetCapacity(PROPBAG2, A_PtrSize*2+24, 0)
   NumPut(11, PROPBAG2, 8, "uint")
   NumPut(&(pstrName := "FilterOption"), PROPBAG2, A_PtrSize+8, "ptr")
   DllCall(NumGet(NumGet(pPropertybag + 0) + A_PtrSize*4), "ptr", pPropertybag, "uint", 1, "ptr", &PROPBAG2, "ptr", &variant)   ; IPropertyBag2::Write
   ; IWICBitmapFrameEncode::Initialize
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*3), "Ptr", IWICBitmapFrameEncode, "Ptr", pPropertybag)

   ; IWICBitmapFrameEncode::WriteSource
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*11), "Ptr", IWICBitmapFrameEncode, "Ptr", IWICBitmap, "Ptr", 0)
   ; IWICBitmapFrameEncode::Commit
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*12), "Ptr", IWICBitmapFrameEncode)
   ; IWICBitmapEncoder::Commit
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*11), "Ptr", IWICBitmapEncoder)
   for k, v in [IWICBitmapFrameEncode, IWICBitmapEncoder, IWICStream, IWICBitmap, IWICImagingFactory, pPropertybag]
      ObjRelease(v)
}
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

07 Sep 2021, 20:11

Thanks for your research!
But your statements
malcev wrote: wic is slower
and
malcev wrote: the speed will be +- the same as with gdi
contradict each other. It just takes longer for better packing, it could be assumed.
Also, I can't agree with this:
malcev wrote: If You need packing files better, use C++, not ahk
PL doesn't pack files, but algorithm does. Why do you think c++ will give the better result?
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 03:50

It just takes longer for better packing
I would say it just chooses wrong filter for compression optimization.
PL doesn't pack files, but algorithm does. Why do you think c++ will give the better result?
If You use c++, You can forget about wic algorithms, because they are not perfect, for example with gif they will not work at all, and use custom libraries like this:
https://github.com/kornelski/pngquant
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

08 Sep 2021, 13:10

malcev wrote: I would say it just chooses wrong filter for compression optimization.
This what I see:
[urlhttps://docs.microsoft.com/en-us/windows/win32/api/wincodec/ne-wincodec-wicpngfilteroption#constants]MSDN[/url] wrote:WICPngFilterUnspecified
Indicates an unspecified PNG filter. This enables WIC to algorithmically choose the best filtering option for the image.
Why do you call it «wrong filter»? What exactly is «wrong»?
malcev wrote: You can forget about wic algorithms, because they are not perfect, for example with gif they will not work at all, and use custom libraries like this
What do you mean? I've already created gif files using WIC. And why not compile this library as a dll file and use it with AHK?
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 13:20

Why do you call it «wrong filter»? What exactly is «wrong»?
It chooses algorithm that takes time, but the size remaining the same.
What do you mean? I've already created gif files using WIC.
I mean that Wic creates very big gif files.
And why not compile this library as a dll file and use it with AHK?
If it exists and it is OK for You, of course You can compile.
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

08 Sep 2021, 13:34

malcev wrote: It chooses algorithm that takes time, but the size remaining the same.
Nope, just have tested, the size is different.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 13:39

You are mistaken.
Test with my picture from here:
viewtopic.php?p=419316#p419316
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

08 Sep 2021, 14:01

Try this, and you will see that you are mistaken:

Code: Select all

UrlDownloadToFile, https://i.imgur.com/QuB8MoV.jpeg, %A_Desktop%\test.jpeg
hBitmap := LoadPicture(A_Desktop . "\test.jpeg", "GDI+")

HBitmapToPngWIC_1(hBitmap, A_Desktop . "\test_1.png")
HBitmapToPngWIC_2(hBitmap, A_Desktop . "\test_2.png")

FileGetSize, size1, %A_Desktop%\test_1.png
FileGetSize, size2, %A_Desktop%\test_2.png

MsgBox, % "size1: " . size1 . "`nsize2: " size2

HBitmapToPngWIC_1(hBitmap, destPngFilePath) {
   static CLSID_WICImagingFactory  := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
         , IID_IWICImagingFactory  := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
         , GUID_ContainerFormatPng := "{1B7CFAF4-713F-473C-BBCD-6137425FAEAF}"
         , WICBitmapUseAlpha := 0x00000000, GENERIC_WRITE := 0x40000000
         , WICBitmapEncoderNoCache := 0x00000002
         
   VarSetCapacity(GUID, 16, 0)
   DllCall("Ole32\CLSIDFromString", "WStr", GUID_ContainerFormatPng, "Ptr", &GUID)
   IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
   Vtable( IWICImagingFactory    , CreateBitmapFromHBITMAP := 21 ).Call("Ptr", hBitmap, "Ptr", 0, "UInt", WICBitmapUseAlpha, "PtrP", IWICBitmap)
   Vtable( IWICImagingFactory    , CreateStream            := 14 ).Call("PtrP", IWICStream)
   Vtable( IWICStream            , InitializeFromFilename  := 15 ).Call("WStr", destPngFilePath, "UInt", GENERIC_WRITE)
   Vtable( IWICImagingFactory    , CreateEncoder           :=  8 ).Call("Ptr", &GUID, "Ptr", 0, "PtrP", IWICBitmapEncoder)
   Vtable( IWICBitmapEncoder     , Initialize              :=  3 ).Call("Ptr", IWICStream, "UInt", WICBitmapEncoderNoCache)
   Vtable( IWICBitmapEncoder     , CreateNewFrame          := 10 ).Call("PtrP", IWICBitmapFrameEncode, "Ptr", 0)
   Vtable( IWICBitmapFrameEncode , Initialize              :=  3 ).Call("Ptr", 0)
   Vtable( IWICBitmapFrameEncode , WriteSource             := 11 ).Call("Ptr", IWICBitmap, "Ptr", 0)
   Vtable( IWICBitmapFrameEncode , Commit                  := 12 ).Call()
   Vtable( IWICBitmapEncoder     , Commit                  := 11 ).Call()
   for k, v in [IWICBitmapFrameEncode, IWICBitmapEncoder, IWICStream, IWICBitmap, IWICImagingFactory]
      ObjRelease(v)
}

Vtable(ptr, n) {
   return Func("DllCall").Bind(NumGet(NumGet(ptr+0), A_PtrSize*n), "Ptr", ptr)
}

HBitmapToPngWIC_2(hBitmap, destPngFilePath) {
   static CLSID_WICImagingFactory  := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
         , IID_IWICImagingFactory  := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
         , GUID_ContainerFormatPng := "{1B7CFAF4-713F-473C-BBCD-6137425FAEAF}"
         , WICBitmapUseAlpha := 0x00000000, GENERIC_WRITE := 0x40000000
         , WICBitmapEncoderNoCache := 0x00000002
         
   VarSetCapacity(GUID, 16, 0)
   DllCall("Ole32\CLSIDFromString", "WStr", GUID_ContainerFormatPng, "Ptr", &GUID)
   IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
   ; IWICImagingFactory::CreateBitmapFromHBITMAP
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*21), "Ptr", IWICImagingFactory, "Ptr", hBitmap, "Ptr", 0, "UInt", WICBitmapUseAlpha, "PtrP", IWICBitmap)
   ; IWICImagingFactory::CreateStream
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*14), "Ptr", IWICImagingFactory, "PtrP", IWICStream)
   ; IWICStream::InitializeFromFilename
   DllCall(NumGet(NumGet(IWICStream + 0) + A_PtrSize*15), "Ptr", IWICStream, "WStr", destPngFilePath, "UInt", GENERIC_WRITE)
   ; IWICImagingFactory::CreateEncoder
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*8), "Ptr", IWICImagingFactory, "Ptr", &GUID, "Ptr", 0, "PtrP", IWICBitmapEncoder)
   ; IWICBitmapEncoder::Initialize
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*3), "Ptr", IWICBitmapEncoder, "Ptr", IWICStream, "UInt", WICBitmapEncoderNoCache)

   ; IWICBitmapEncoder::CreateNewFrame
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*10), "Ptr", IWICBitmapEncoder, "PtrP", IWICBitmapFrameEncode, "PtrP", pPropertybag)
   VarSetCapacity(variant, 8+A_PtrSize*2, 0)
   NumPut(VT_UI1 := 0x11, variant, 0, "ushort")
   NumPut(WICPngFilterNone := 1, variant, 8, "uchar")
   VarSetCapacity(PROPBAG2, A_PtrSize*2+24, 0)
   NumPut(11, PROPBAG2, 8, "uint")
   NumPut(&(pstrName := "FilterOption"), PROPBAG2, A_PtrSize+8, "ptr")
   DllCall(NumGet(NumGet(pPropertybag + 0) + A_PtrSize*4), "ptr", pPropertybag, "uint", 1, "ptr", &PROPBAG2, "ptr", &variant)   ; IPropertyBag2::Write
   ; IWICBitmapFrameEncode::Initialize
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*3), "Ptr", IWICBitmapFrameEncode, "Ptr", pPropertybag)

   ; IWICBitmapFrameEncode::WriteSource
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*11), "Ptr", IWICBitmapFrameEncode, "Ptr", IWICBitmap, "Ptr", 0)
   ; IWICBitmapFrameEncode::Commit
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*12), "Ptr", IWICBitmapFrameEncode)
   ; IWICBitmapEncoder::Commit
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*11), "Ptr", IWICBitmapEncoder)
   for k, v in [IWICBitmapFrameEncode, IWICBitmapEncoder, IWICStream, IWICBitmap, IWICImagingFactory, pPropertybag]
      ObjRelease(v)
}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 14:03

But I dont speak about Your picture.
Try mine.
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

08 Sep 2021, 14:07

I've tried. You said that the size remains the same, my example proves that this is not the case.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 14:13

I dont understand You.
I am not talking about Your picture.
For Your picture wic chooses algorithm OK.
Try this code.

Code: Select all

UrlDownloadToFile, https://i.imgur.com/psgZToZ.png, %A_Desktop%\test.png
hBitmap := LoadPicture(A_Desktop . "\test.png", "GDI+")

HBitmapToPngWIC_1(hBitmap, A_Desktop . "\test_1.png")
HBitmapToPngWIC_2(hBitmap, A_Desktop . "\test_2.png")

FileGetSize, size1, %A_Desktop%\test_1.png
FileGetSize, size2, %A_Desktop%\test_2.png

MsgBox, % "size1: " . size1 . "`nsize2: " size2

HBitmapToPngWIC_1(hBitmap, destPngFilePath) {
   static CLSID_WICImagingFactory  := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
         , IID_IWICImagingFactory  := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
         , GUID_ContainerFormatPng := "{1B7CFAF4-713F-473C-BBCD-6137425FAEAF}"
         , WICBitmapUseAlpha := 0x00000000, GENERIC_WRITE := 0x40000000
         , WICBitmapEncoderNoCache := 0x00000002
         
   VarSetCapacity(GUID, 16, 0)
   DllCall("Ole32\CLSIDFromString", "WStr", GUID_ContainerFormatPng, "Ptr", &GUID)
   IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
   Vtable( IWICImagingFactory    , CreateBitmapFromHBITMAP := 21 ).Call("Ptr", hBitmap, "Ptr", 0, "UInt", WICBitmapUseAlpha, "PtrP", IWICBitmap)
   Vtable( IWICImagingFactory    , CreateStream            := 14 ).Call("PtrP", IWICStream)
   Vtable( IWICStream            , InitializeFromFilename  := 15 ).Call("WStr", destPngFilePath, "UInt", GENERIC_WRITE)
   Vtable( IWICImagingFactory    , CreateEncoder           :=  8 ).Call("Ptr", &GUID, "Ptr", 0, "PtrP", IWICBitmapEncoder)
   Vtable( IWICBitmapEncoder     , Initialize              :=  3 ).Call("Ptr", IWICStream, "UInt", WICBitmapEncoderNoCache)
   Vtable( IWICBitmapEncoder     , CreateNewFrame          := 10 ).Call("PtrP", IWICBitmapFrameEncode, "Ptr", 0)
   Vtable( IWICBitmapFrameEncode , Initialize              :=  3 ).Call("Ptr", 0)
   Vtable( IWICBitmapFrameEncode , WriteSource             := 11 ).Call("Ptr", IWICBitmap, "Ptr", 0)
   Vtable( IWICBitmapFrameEncode , Commit                  := 12 ).Call()
   Vtable( IWICBitmapEncoder     , Commit                  := 11 ).Call()
   for k, v in [IWICBitmapFrameEncode, IWICBitmapEncoder, IWICStream, IWICBitmap, IWICImagingFactory]
      ObjRelease(v)
}

Vtable(ptr, n) {
   return Func("DllCall").Bind(NumGet(NumGet(ptr+0), A_PtrSize*n), "Ptr", ptr)
}

HBitmapToPngWIC_2(hBitmap, destPngFilePath) {
   static CLSID_WICImagingFactory  := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
         , IID_IWICImagingFactory  := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
         , GUID_ContainerFormatPng := "{1B7CFAF4-713F-473C-BBCD-6137425FAEAF}"
         , WICBitmapUseAlpha := 0x00000000, GENERIC_WRITE := 0x40000000
         , WICBitmapEncoderNoCache := 0x00000002
         
   VarSetCapacity(GUID, 16, 0)
   DllCall("Ole32\CLSIDFromString", "WStr", GUID_ContainerFormatPng, "Ptr", &GUID)
   IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
   ; IWICImagingFactory::CreateBitmapFromHBITMAP
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*21), "Ptr", IWICImagingFactory, "Ptr", hBitmap, "Ptr", 0, "UInt", WICBitmapUseAlpha, "PtrP", IWICBitmap)
   ; IWICImagingFactory::CreateStream
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*14), "Ptr", IWICImagingFactory, "PtrP", IWICStream)
   ; IWICStream::InitializeFromFilename
   DllCall(NumGet(NumGet(IWICStream + 0) + A_PtrSize*15), "Ptr", IWICStream, "WStr", destPngFilePath, "UInt", GENERIC_WRITE)
   ; IWICImagingFactory::CreateEncoder
   DllCall(NumGet(NumGet(IWICImagingFactory + 0) + A_PtrSize*8), "Ptr", IWICImagingFactory, "Ptr", &GUID, "Ptr", 0, "PtrP", IWICBitmapEncoder)
   ; IWICBitmapEncoder::Initialize
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*3), "Ptr", IWICBitmapEncoder, "Ptr", IWICStream, "UInt", WICBitmapEncoderNoCache)

   ; IWICBitmapEncoder::CreateNewFrame
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*10), "Ptr", IWICBitmapEncoder, "PtrP", IWICBitmapFrameEncode, "PtrP", pPropertybag)
   VarSetCapacity(variant, 8+A_PtrSize*2, 0)
   NumPut(VT_UI1 := 0x11, variant, 0, "ushort")
   NumPut(WICPngFilterNone := 1, variant, 8, "uchar")
   VarSetCapacity(PROPBAG2, A_PtrSize*2+24, 0)
   NumPut(11, PROPBAG2, 8, "uint")
   NumPut(&(pstrName := "FilterOption"), PROPBAG2, A_PtrSize+8, "ptr")
   DllCall(NumGet(NumGet(pPropertybag + 0) + A_PtrSize*4), "ptr", pPropertybag, "uint", 1, "ptr", &PROPBAG2, "ptr", &variant)   ; IPropertyBag2::Write
   ; IWICBitmapFrameEncode::Initialize
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*3), "Ptr", IWICBitmapFrameEncode, "Ptr", pPropertybag)

   ; IWICBitmapFrameEncode::WriteSource
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*11), "Ptr", IWICBitmapFrameEncode, "Ptr", IWICBitmap, "Ptr", 0)
   ; IWICBitmapFrameEncode::Commit
   DllCall(NumGet(NumGet(IWICBitmapFrameEncode + 0) + A_PtrSize*12), "Ptr", IWICBitmapFrameEncode)
   ; IWICBitmapEncoder::Commit
   DllCall(NumGet(NumGet(IWICBitmapEncoder + 0) + A_PtrSize*11), "Ptr", IWICBitmapEncoder)
   for k, v in [IWICBitmapFrameEncode, IWICBitmapEncoder, IWICStream, IWICBitmap, IWICImagingFactory, pPropertybag]
      ObjRelease(v)
}
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

08 Sep 2021, 14:23

Are you serious? Do you take an nearly empty file and suggest compressing it? Take any usual png and the size will be different.
For examle, this one. In your particular case, WIC is not optimal by default, but this case is not at all indicative.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 14:34

Absolutely serious.
Wic badly analyzes images, badly compress them - just spends extra time.
Try compress with this utility and compare results.
https://pngquant.org/
I do not understand what do You try to prove me?
teadrinker
Posts: 4354
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to save image in clipboard.

08 Sep 2021, 15:01

malcev wrote: Wic badly analyzes images, badly compress them - just spends extra time.
You forgot that we initially compared GDIplus and WIC. Compared to GDIplus, WIC packs files better, and at least in most cases is not inferior in speed with the same quality. Therefore, WIC is preferable, that's all.
Why do you suggest comparing with external libraries? It is clear that if they exist, they do better.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: How to save image in clipboard.

08 Sep 2021, 15:43

When We started to compare gdi and wic, I did not know that wic worked slower because of compression and We can turn off it.
So if We need speed, then We have to use gdi+ or Wic with WICPngFilterNone.
As for me I stopped to use wic because of speed in real situation, when I needed save screenshots of explorer window.
It took +-2x times more than with gdi.
But at that date I did not make researches about it, just compare speed with gdi+ and chose gdi+.
iseahound
Posts: 1451
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to save image in clipboard.

12 Dec 2021, 01:20

Wow. That's a lot of code.

Anyways, to answer the OP's question, it's possible there is a PNG stream on the clipboard.

Code: Select all

filepath := "test.png"

; Open the clipboard with exponential backoff.
loop
   if DllCall("OpenClipboard", "ptr", A_ScriptHwnd)
      break
   else
      if A_Index < 6
         Sleep (2**(A_Index-1) * 30)
      else throw Exception("Clipboard could not be opened.")

; Prefer the PNG stream if available because of transparency support.
png := DllCall("RegisterClipboardFormat", "str", "png", "uint")
if DllCall("IsClipboardFormatAvailable", "uint", png) {
   if !(hData := DllCall("GetClipboardData", "uint", png, "ptr"))
      throw Exception("Shared clipboard data has been deleted.")

   ; Allow the stream to be freed while leaving the hData intact.
   ; Please read: https://devblogs.microsoft.com/oldnewthing/20210930-00/?p=105745
   DllCall("ole32\CreateStreamOnHGlobal", "ptr", hData, "int", false, "ptr*", pStream:=0, "uint")


   DllCall("shlwapi\SHCreateStreamOnFileEx"
            ,   "wstr", filepath
            ,   "uint", 0x1001          ; STGM_CREATE | STGM_WRITE
            ,   "uint", 0x80            ; FILE_ATTRIBUTE_NORMAL
            ,    "int", true            ; fCreate is ignored when STGM_CREATE is set.
            ,    "ptr", 0               ; pstmTemplate (reserved)
            ,   "ptr*", pFileStream:=0
            ,   "uint")
   DllCall("shlwapi\IStream_Size", "ptr", pStream, "ptr*", size:=0, "uint")
   DllCall("shlwapi\IStream_Reset", "ptr", pStream, "uint")
   DllCall("shlwapi\IStream_Copy", "ptr", pStream, "ptr", pFileStream, "uint", size, "uint")
   ObjRelease(pFileStream)

   ObjRelease(pStream)
}

DllCall("CloseClipboard")
I can guarantee this code is the absolute fastest. Why? Because it never decodes the HBitmap, instead it only looks for a png on the clipboard and saves it.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], slowwd and 110 guests