Is picture? Know it before calling LoadPicture()

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Is picture? Know it before calling LoadPicture()

29 Aug 2017, 15:56

Example call

Code: Select all

Ext := IsPicture( "F:\Images\DSC_0123.jpg", Width, Height )
When IsPicture() is successful,
variable Ext will contain one of these (supported) type/extension of the image:
PNG TIF JPG GIF ICO BMP EMF WMF
otherwise Ext will be 0 (false)

Width and Height are byRef variables and are optional.
When a supported image type is resolved, they will contain the image dimensions.
Otherwise, they will be reset to 0.
The dimensions will be NULL when image is a vector, namely WMF and EMF

There is no guarantee that LoadPicture() will load an image resolved with IsPicture().
In case, an image (of supported type) loads with LoadPicture(), but IsPicture() does not recognize it, please post with a link or attached sample. I will fix it.
Written for/in AutoHotkey 1.1 U32, but should work in all AutoHotkey versions that supports File object.
I will update the topic with notes and references, if there is interest.

Remarks:
NTDLL functions RtlUlongByteSwap() / RtlUshortByteSwap don't work in x64 and hence the direct bit manipulation.
I could've been more insistent when NumGet() was introduced.

The Function:

Code: Select all

IsPicture( sFile, ByRef W:="", ByRef H:="" ) {         ;  IsPicture() v0.9.0.01   for AutoHotkey 1.1   
Local  File, V1, V2, Type, BigEndian                   ;  Author: SKAN          Created: 24-Aug-2017                 
Local  oIFD, nIFD, nTag, tTag, sLen, Segm, cLen, cTyp  ;  Topic : goo.gl/SK2MXx LastMod: 31-Aug-2017 
Static Bin  

  W := H := 0
  File := FileOpen(sFile,"r")
  If ! ( IsObject(File) )
     Return 0   
  VarSetCapacity(Bin,46,0)
  sLen := File.RawRead(Bin,46)
  If (sLen<46)
     Return (File.Close()>>64)  

  V1 := NumGet(Bin,"Int64") 
  If ( V1 = 0x0A1A0A0D474E5089 && NumGet(Bin,8,"Int64") = 0x524448490D000000 )        ; PNG Clean
  {
      W := NumGet(Bin,16,"UInt")
      W := ( (W & 255)<<24 | (W>>8 & 255)<<16 | (W>>16 & 255)<<8 | W>>24 )
      H := NumGet(Bin,20,"UInt")
      H := ( (H & 255)<<24 | (H>>8 & 255)<<16 | (H>>16 & 255)<<8 | H>>24 )
      Return ( File.Close()+"" ) . ( W>0 && H>0 ? "PNG" : 0 )
  }

  If ( V1 = 0x0A1A0A0D474E5089) && ( Type := "PNG" )                                  ; PNG abnormal
  {
      If ! (IsByRef(W) || IsByRef(H))
         Return ( File.Close()+"" ) . Type 

      cLen := NumGet(Bin,8,"UInt")                               ; Chunk data Length
      cLen := ( (cLen & 255)<<24 | (cLen>>8 & 255)<<16 | (cLen>>16 & 255)<<8 | cLen>>24 )
      cTyp := 0, File.Seek(cLen+20,0)  

      While (cTyp<>0x444E4549)                                    ; Until IEND chunk
      {
        If (File.RawRead(Bin,8)<8)
           Break
        cLen := NumGet(Bin,"UInt")                                ; Chunk data Length
        cLen := ( (cLen & 255)<<24 | (cLen>>8 & 255)<<16 | (cLen>>16 & 255)<<8 | cLen>>24 )
        cTyp := NumGet(Bin,4,"UInt") 
        If ( cTyp=0x52444849 )                                    ; IHDR chunk found
        {
            File.RawRead(Bin,8)
            W := NumGet(Bin,0,"UInt")
            W := ( (W & 255)<<24 | (W>>8 & 255)<<16 | (W>>16 & 255)<<8 | W>>24 )
            H := NumGet(Bin,4,"UInt")
            H := ( (H & 255)<<24 | (H>>8 & 255)<<16 | (H>>16 & 255)<<8 | H>>24 )
            Break
        }
        File.Seek(cLen+4,1)
      }        
      Return ( File.Close()+"" ) . ( W>0 && H>0 ? Type : 0 )
  }

  V1 &= 0xFFFFFFFF                                                ; Convert Int64 to UInt 
  If ( V1 = 0x2A004D4D || V1 = 0x002A4949 ) && ( Type := "TIF" )  ; TIFF/MAC or TIFF/IBM-PC
  {
      If ! (IsByRef(W) || IsByRef(H))
         Return ( File.Close()+"" ) . Type 

      BigEndian := ( NumGet(Bin,"UShort") = 0x4D4D )
      oIFD := NumGet(Bin,4,"UInt")                                ; Offset to IFD0 
      oIFD := BigEndian 
           ? ( (oIFD & 255)<<24 | (oIFD>>8 & 255)<<16 | (oIFD>>16 & 255)<<8 | oIFD>>24 ) : oIFD
      File.SeeK(oIFD,0)    
      File.RawRead(Bin,2)
      nIFD := NumGet(Bin,"UShort")                                ; Number of tags in IFD0
      nIFD := BigEndian ? ( (nIFD & 0xFF)<<8 | nIFD>>8 ) : nIFD 

      While ( W=0 || H=0 && A_Index<=nIFD )                       ; Read IFD0 tags one by one
      {
        File.RawRead(Bin,12)                                      ; Each Tag is 12 bytes     
        nTag := NumGet(Bin,"UShort")                              ; Tag ID
        nTag := BigEndian ? ( (nTag & 0xFF)<<8 | nTag>>8 ) : nTag 
        tTag := NumGet(Bin,2,"UShort")                            ; TagType:  4=UInt, 3=UShort
        tTag := BigEndian ? ( (tTag & 0xFF)<<8 | tTag>>8 ) : tTag 

        If ( nTag=0x0100 )                                        ; 0x0100 = TIFFTAG_IMAGEWIDTH 
        If ( tTag=3 )                                             ; Width is stored as UShort
             W := Numget(Bin,8,"UShort")
           , W := BigEndian ? ( (W & 0xFF)<<8 | W>>8 ) : W
        Else W := Numget(Bin,8,"UInt")                            ; Width is stored as UInt
           , W := BigEndian ? ( (W & 255)<<24 | (W>>8 & 255)<<16 | (W>>16 & 255)<<8 | W>>24 ) : W
        
        If ( nTag=0x0101 )                                        ; 0x0101 = TIFFTAG_IMAGELENGTH 
        If ( tTag=3 )                                             ; Height is stored as UShort
             H := Numget(Bin,8,"UShort")
           , H := BigEndian ? ( (H & 0xFF)<<8 | H>>8 ) : H
        Else H := Numget(Bin,8,"UInt")                            ; Height is stored as UInt
           , H := BigEndian ? ( (H & 255)<<24 | (H>>8 & 255)<<16 | (H>>16 & 255)<<8 | H>>24 ) : H
      }  
      Return ( File.Close()+"" ) . ( W>0 && H>0 ? Type : 0 )
  }

  V1 &= 0xFFFFFF                                                  ; Convert UInt to UInt24
  If ( V1 = 0xFFD8FF) && ( Type := "JPG" )                        ; JPEG/JFIF and JPEG/Exif
  {
      If ! (IsByRef(W) || IsByRef(H))
         Return ( File.Close()+"" ) . Type 

      sLen := 0,  File.Seek(4,0)                                       
      Loop {                                                      ; Read segments one by one
        File.Seek(sLen-2,1)
        If ( File.RawRead(Bin,4)<4 || (Segm:=NumGet(Bin,0,"UShort"))<0x00FF )
             Return (File.Close()>>64)
        Else Segm >>= 8
        If ( Segm>=0xC0 && Segm<=0xCF && Segm<>0xCC && Segm<>0xC4 )
           Break    
        sLen := NumGet(Bin,2,"UShort" )                           ; Segment Length
        sLen := ( (sLen & 0xFF)<<8 | sLen>>8 )
      }   

      File.Seek(-4,1),                 File.RawRead(Bin,sLen)
      W := NumGet(Bin,7,"UShort"),     W := ( (W & 0xFF)<<8 | W>>8 )
      H := NumGet(Bin,5,"UShort"),     H := ( (H & 0xFF)<<8 | H>>8 )
      Return ( File.Close()+"" ) . ( W>0 && H>0 ? Type : 0 )
  }

  V2 := NumGet(Bin,3,"UInt") & 0xFFFFFF
  If ( V1 = 0x464947 && V2 = 0x613738 || V2 = 0x613938 )          ; "GIF" and "87a" or "89a"
  {
      File.Seek(-1,2)                                             ; Seek last Char
      If ( File.ReadUCHAR() = 0x3B )                              ; Last character is semi-colon
           W := NumGet(Bin,6,"UShort")  
         , H := NumGet(Bin,8,"UShort")
      Return ( File.Close()+"" ) . ( W>0 && H>0 ? "GIF" : 0 ) 
  }
  
  File.Close()  ; Close the file and operate from 46 memory bytes for ICO, BMP, WMF and EMF
   
  If ( NumGet(Bin,0, "UInt") = 0x00010000 && NumGet(Bin,4,"UChar") > 0 )            
  && ( NumGet(Bin,9,"UChar") = 0 && NumGet(Bin,10,"UShort") < 2 ) && (Type:="ICO")    ; ICO
  {
      If (IsByRef(W) || IsByRef(H))
        W := NumGet(Bin,0,"UChar") ? NumGet(Bin,0,"UChar") : 256 
      , H := NumGet(Bin,1,"UChar") ? NumGet(Bin,1,"UChar") : 256
      Return ( File.Close()+"" ) . Type
  }  

  If ( V1 & 0xFFFF = 0x4D42 && NumGet(Bin,6,"UInt") = 0 )           ; BMP
  && ( V2 := NumGet(Bin,14,"UInt") ) && ( V2=12 || V2=40 || V2=56 || V2=108 || V2=124 )
  {       
         W := NumGet(Bin,18,V2=12?"UShort":"UInt")                  ; accommodating BITMAPCOREHEADER 
         H := NumGet(Bin,V2=12?20:22, V2=12?"UShort":"UInt")        ; accommodating BITMAPCOREHEADER
         H := Abs(H)                                                ; Bitmap might be top bottom
    Return ( W>0 && H>0 ? "BMP" : 0 )
  } 

  If ( NumGet(Bin,40,"UInt") = 0x464D4520 && NumGet(Bin,"Int") = 1 )                  ; EMF  
      Return "EMF" . ( W := H := "" )
                                                                  
  If ( NumGet(Bin, 0,"UInt") = 0x9AC6CDD7 && NumGet(Bin,24,"UInt") = 0x03000009 )     ; WMF -> APM 
      Return "WMF" . ( W := H := "" )
                                                                  
  If ( NumGet(Bin, 2,"UInt") = 0x03000009 && NumGet(Bin,16,"Short") = 0 )             ; WMF       
       Return "WMF" . ( W := H := "" )

Return 0
} ; ________________________________________________________________________________________________
Attachments
IsPicture v0.9.0.00.ahk
(7.1 KiB) Downloaded 153 times
My Scripts and Functions: V1  V2
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 16:14

Very nice :bravo:.
It works for ahk v2 (2.0-a081-cad307c) too. (Tested on one bmp file)

Thanks for sharing, Cheers :thumbup:.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 16:49

Thanks for this. I'd tried to create a function like this once before, but the width/height offsets for jpg files always seemed to be hard to find.

One thing I'd be interested in (that I was unsuccessful in doing) is to be able count the frames in a gif to see if it's an animated gif.

Another thing might be to count the number of icons in an icon file, and get the dimensions of the largest icon(/smallest icon/all icons).

So I would suppose you've found some good specs for the binary date of image files, such links can be hard to find, in case you'd like to share. Some of the best links I found for wav and bmp are only available at Internet Archive now.

Also one thing that might make something like this easier to do is a binary data to hex string function. E.g. JEE_BinDataToHex:
Available at these two links:
Gdip: image binary data to hex string for OCR - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=35339
jeeswg's documentation extension tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=33596
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 17:28

Helgef wrote:Very nice :bravo:.
Thank you.
It works for ahk v2 (2.0-a081-cad307c) too. (Tested on one bmp file)
I know! I too tested, but it didn't work for me complaining something about a percent sign being used.
After half-an-hour of testing I realized there is no MsgBox command in V2.

:)
My Scripts and Functions: V1  V2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 17:32

Code: Select all

;AHK v1:
MsgBox hello
MsgBox % "hello"
MsgBox, hello
MsgBox, % "hello"

;AHK v2:
MsgBox "hello"
MsgBox("hello")
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 17:53

jeeswg wrote:Thanks for this.


:)
jeeswg wrote:I'd tried to create a function like this once before, but the width/height offsets for jpg files always seemed to be hard to find.
Yes! JPG is a Bad ITCH!
I had to research hard for it.
WMF and EMF were easy, But I had to download OpenOffice to create these files to test it.

For the rest, I already had outdated code lying around.. just tinkered it.
One thing I'd be interested in (that I was unsuccessful in doing) is to be able count the frames in a gif to see if it's an animated gif.
Never went past the header. Will let you know if I come up with something.
Another thing might be to count the number of icons in an icon file, and get the dimensions of the largest icon(/smallest icon/all icons).
It a bit tricky.. I will do this first.
So I would suppose you've found some good specs for the binary date of image files, such links can be hard to find, in case you'd like to share
If it will be useful, sure. I will do a dumpster dive in to browser history!
It was mostly from wiki.. Except JPG where I got the main clue from Stack-something.com!
Also one thing that might make something like this easier to do is a binary data to hex string function. E.g. JEE_BinDataToHex:
Maybe easier, but neither fast nor efficient, IMO.
I read only 8-13 bytes from any file... barring the initial read of 46 bytes required for EMF format.

I will update. Thanks for the interest.
My Scripts and Functions: V1  V2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 18:01

For icon info, everything here should be helpful, I was thinking to do something like I said (re. getting icon sizes) in maybe some months time:
graphics: create icons from scratch - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=35758

Btw have you ever had much luck getting/setting icon image data from/in external programs? (I might try it with dll injection.) E.g. I would have thought that for any context menu that I see, I could get the hIcon/hBitmap, and retrieve the image data.
DllCall - Assign icon for “Copy/Cut/Paste/Delete” Windows default context menu items - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=30377

Re. NumGet/NumPut, I think there should be big endian support, perhaps via StrGet/StrPut instead, to allow Hex as an option. Contrariwise I think that perhaps Format should have support for showing hex as little endian, although I am less certain of this. Perhaps StrGet/StrPut could be used to convert hex little endian to hex big endian and vice versa. Anyway, I will be releasing my Wish List 2.0 soon, and these ideas are already planned for it. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 18:26

jeeswg wrote:For icon info, everything here should be helpful
Search forum for IconEx. Multiple versions exist, which has code to extract full icon (with various frames).
I'm not convinced that I am using the text book method while writing the icons. Listing sizes is trivial... But I have to research on the format a bit more.
Contrariwise I think that perhaps Format should have support for showing hex as little endian, although I am less certain of this.
Nice idea!

Actually, In un-optimised version of Ispicture() I was doing it like follows:

Code: Select all

Static HEXUINT := "0x{1:02X}{2:02X}{3:02X}{4:02X}"
...
oIFD := NumGet(Bin,4,"UInt")                                ; Offset to IFD0 
oIFD := BigEndian ? Format(HEXUINT,oIFD & 0xFF, oIFD>>8 & 0xFF, oIFD>>16 & 0xFF, oIFD>>24) + 0 : oFID
:)
My Scripts and Functions: V1  V2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 20:57

Btw this relates to a wider issue, of identifying files by their initial bytes, which could be a separate function, which I did a bit of work on for images, to confirm that extensions were correct, to retrieve the image type without having to load the images into a WIA object.

Btw is there anything native to Windows that can list the frames in an animated gif other than a WIA object.

I would just mention that GetDetailsOf can retrieve some dimension info for images.

Re. images, here is some possibly interesting material:
show svg/wdp/jxr/animated gif image files in a GUI - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=28658
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
Masonjar13
Posts: 1555
Joined: 20 Jul 2014, 10:16
Location: Не Россия
Contact:

Re: Is picture? Know it before calling LoadPicture()

29 Aug 2017, 22:57

I love seeing new stuff from you, SKAN :D low-level operations like you do in most of your posted functions are typically pretty difficult, but also the most efficient! I don't really have a purpose for this particular function (perhaps in the future), but I enjoy looking at your code and figuring out how it all works.

I was curious so I did a quick test. Using it on a multi-layer ICO, it retrieves only the largest (front-most) layer. Would it be reasonably possible to return arrays for the width and height for each layer?

Edit: I see jeeswg already mentioned this :roll:
OS: Windows 10 Pro | Editor: Notepad++
My Personal Function Library | Old Build - New Build
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 07:38

Xtra wrote::thumbup: Thanks
:thumbup: :)
jeeswg wrote:I would just mention that GetDetailsOf can retrieve some dimension info for images.
I've been using it for a while. I use it to read Win XP specific EXIF tags (XPTITLE, XPDESCRIPTION etc)
Just enough while dealing with few photos.
IsPicture() is fast, and you will appreciate the speed when you need to retrieve dimensions from a large collection of pictures.
Masonjar13 wrote:I love seeing new stuff from you, SKAN :D low-level operations like you do in most of your posted functions are typically pretty difficult, but also the most efficient! I don't really have a purpose for this particular function (perhaps in the future), but I enjoy looking at your code and figuring out how it all works.
Thanks for the nice words. :)
Masonjar13 wrote:I was curious so I did a quick test. Using it on a multi-layer ICO, it retrieves only the largest (front-most) layer.
That is what Windows Explorer and File properties show. Windows Photo Viewer also shows only the first frame for a ICO file.
I presumed LoadPicture( "F:\MyIco.ico") will also load only the first frame, but I'm yet to test and confirm this.
I've to also test what LoadPicture( A_AhkPath) loads. I presumed it to be the first frame of first icon.. But I will not implement EXE,DLL as it will slow down the function.
Masonjar13 wrote:Would it be reasonably possible to return arrays for the width and height for each layer?
Easy, I guess.. but I will post it as a separate function.

:)
My Scripts and Functions: V1  V2
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Identifying an ICON file and getting dimensions from it

30 Aug 2017, 11:33

Two important references:
MSDN: Icons by John Hornick
WIKI: ICO (file format)

ICON files begin with a ICONDIR structure a header of 6 bytes, for example: 00 00 01 00 09 00
We may read the first 4 bytes a (UInt) and check if it is 0x00010000, but many JBIG files begin the same way.
We can see from the HEX above idCount member is 0x0009 (UShort) meaning the ICO file has 9 images in it. This can never be 0 for a valid icon.

Code: Select all

typedef struct
{
    WORD           idReserved;   // Reserved (must be 0)
    WORD           idType;       // Resource Type (1 for icons)
    WORD           idCount;      // How many images?
    ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, *LPICONDIR;
ICONDIR structure is followed by one ICONDIRENTRY (16 bytes) for each icon image in the file, providing details about its location in the file, size and color depth.
The ICONDIRENTRY structure is defined as:

Code: Select all

typedef struct
{
    BYTE        bWidth;          // Width, in pixels, of the image
    BYTE        bHeight;         // Height, in pixels, of the image
    BYTE        bColorCount;     // Number of colors in image (0 if >=8bpp)
    BYTE        bReserved;       // Reserved ( must be 0)
    WORD        wPlanes;         // Color Planes
    WORD        wBitCount;       // Bits per pixel
    DWORD       dwBytesInRes;    // How many bytes in this resource?
    DWORD       dwImageOffset;   // Where in the file is this image?
} ICONDIRENTRY, *LPICONDIRENTRY;
Since bWidth and bHeight members are UCHAR values (0-255) they will be 0 for a 256x256 Icon.
IsPicture() tests if bReserved member is 0 and if wPlanes member is less than 2, but this might break in future.

Single Icon

It is better to explain a single image icon with an example.

How to convert a 256x256 .PNG (1234 bytes) to .ICO?

ICON file should begin with a ICONDIR structure a header of 6 bytes: 00 00 01 00 01 00
idCount member is 0x0001 (UShort) meaning the ICO file has only one image in it.
The next 16 bytes should be ICONDIRENTRY structure
Structure members should be filled in appropriately
bWidth and bHeight members should be 0 for 256x256 image
dwBytesInRes member should be 1234 which is the file-size of PNG
dwImageOffset should be 6+16 = 22 ( offset from beginning of file)

Now, we may append the raw PNG file data the above structure and save the complete data as .ICO file.
The file size of the newly created icon file will be 6+16+1234 = 1256 bytes laid out as follows:

{ICONDIR}
{ICONDIRENTRY}
{Full PNG file}

Converting BMP file to ICO involves one extra procedure.
BMP files have a 14 bytes header (BITMAPFILEHEADER)
BITMAPFILEHEADER belongs in BMP file, not in an ICO file.
So remove the first 14 bytes before appending it to an ICO file.

Multi-image Icon

Icon containing multiple image is structured as follows

{ICONDIR structure}
{ICONDIRENTRY for image 1}
{ICONDIRENTRY for image 2}
{ICONDIRENTRY for image 3} and so on
{Image data 1}
{Image data 2}
{Image data 3} and so on

Again: Image data will be complete file-data for PNG and for BMP it will be file-data minus BITMAPFILEHEADER
To read a particular image from an multi-image icon, we will have to fetch the file offset/bytes from the respective ICONDIRENTRY structure.
To get a list of all image dimensions (including bit depth) we check the first 6 bytes. confirm if it is an icon, and get the idCount to ascertain the loop iterations.
We can now loop each ICONDIRENTRY and get the dimensions from it.
Here follows a demo function. Modify it to your needs.

Code: Select all

ICON_GetDim(ICOFile) {
Static Bin := VarSetCapacity(Bin,16,0)
Local File := FileOpen(ICOFile,"r"), Count, W, H, B, ICOL := ""

  If ! ( IsObject(File) )
        Return 0
  If ( File.RawRead(BIN,10) < 10 )   ; Read Initial 10 bytes and check read bytes
      Return ( File.Close() + "" )   ; read error
      
  If ! ( Numget(Bin,"UInt") = 0x00010000 && Numget(Bin,4,"UShort") > 0 &&  NumGet(Bin,9,"Char") = 0 )
  Return (File.Close() + "")    

  Count := NumGet(Bin,4,"UShort")    ; ID Count
  File.Seek(6,0)                     ; Seek 6th byte from BOF
  Loop % ( Count )                   ; Parse ICONDIRENTRY one at a time
  {
    If ( File.RawRead(BIN,16) < 16 ) ; Read ICONDIRENTRY and check read bytes
      Return ( File.Close() + "" )   ; read error
    W := NumGet(Bin,0,"UChar")       ; get width 
    W := ( W ? W : 256 )             ; Width will be 0 for 256px wide icon
    H := NumGet(Bin,1,"Uchar")       ; get Height
    H := ( W ? W : 256 )             ; Height will be 0 for 256px wide icon
    B := NumGet(Bin,6,"UShort")
    ICOL .=  W "x" H "-" B "b`n" 
  }  
  File.Close()
Return RTrim(ICOL,"`n")
}
Please suggest any improvements.
Next will be PNG... Or should it be JPG?
My Scripts and Functions: V1  V2
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 12:11

very cool, thanks for sharing

or CUR next? very similar to ICO
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 12:23

Png or jpg, either is fine! One thing I've been curious about is if it's possible to convert an image to a png with the exact same binary as MS Paint (Windows XP) would create, I couldn't find good info for this. (E.g. I had some Paint bmps I wanted to convert to Paint pngs, might as well do this via Gdip rather than Paint, and an exact file match would be a bonus.)

Btw one thing that has me curious is that icons appear to have one transparency BIT per pixel (on/off?) cf. ARGB which has one transparency BYTE (256 possibilities), so I was curious how conversion is done re. transparency. That suggests a pixel in an icon is either transparent or not, but I believe I've seen partial transparency!?

One thing that would be good that I intend to try and do in some months, is create an image with all icon images stitched together horizontally.

My instinct is also that a function to list the sizes of an icon, would be a separate function. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 13:08

gwarble wrote:very cool, thanks for sharing
:)
gwarble wrote:or CUR next? very similar to ICO
IsPicture() does not support CUR files..
ICO supports PNG, so I consider it a picture.
I keep wondering if CUR format is a picture at all.
My Scripts and Functions: V1  V2
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 13:13

jeeswg wrote:Png or jpg, either is fine! One thing I've been curious about is if it's possible to convert an image to a png with the exact same binary as MS Paint (Windows XP) would create, I couldn't find good info for this. (E.g. I had some Paint bmps I wanted to convert to Paint pngs, might as well do this via Gdip rather than Paint, and an exact file match would be a bonus.)
No idea at all.
Btw one thing that has me curious is that icons appear to have one transparency BIT per pixel (on/off?) cf. ARGB which has one transparency BYTE (256 possibilities), so I was curious how conversion is done re. transparency. That suggests a pixel in an icon is either transparent or not, but I believe I've seen partial transparency!?
You may create an alpha transparent bitmap (a=8 r=8 g=8 b=8) and convert it to an icon.
create an image with all icon images stitched together horizontally.
I've done it. For what purpose is this useful, if I may ask.

:)
My Scripts and Functions: V1  V2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 13:30

Just to preview icons, e.g. for diagnostic purposes in a SplashImage. I've done such a script for downloading icons from a webpage which I'll share, however, it just does one image per multiple icons. Rather than multiple images per one icon.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 13:53

SKAN wrote:IsPicture() does not support CUR files..
ICO supports PNG, so I consider it a picture.
I keep wondering if CUR format is a picture at all.
Maybe when the ICO format changed with Vista+ to support PNG data, CUR did not follow suit. Before that, both were BMP based as far as I understand, with very few differences:
The CUR file format is an almost identical image file format for non-animated cursors in Microsoft Windows.
The only differences between these two file formats are the bytes used to identify them and the addition of a hotspot in the CUR format header.
The Hotspot is defined as the pixel offset (in x,y coordinates) from the top-left corner of the cursor image where the user is actually pointing the mouse.
https://github.com/MathewSachin/NIco/wi ... PE-Formats

basically ICONDIR has a byte set to 2 for cursor instead of 1 for icon, as well as the addition of the X and Y hotspot coordinates
https://en.wikipedia.org/wiki/ICO_(file_format)#Outline

Either way I would definitely consider it a picture format, but understand not wanting to add support for it...
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: Is picture? Know it before calling LoadPicture()

30 Aug 2017, 16:58

jeeswg wrote:Just to preview icons, e.g. for diagnostic purposes in a SplashImage. I've done such a script for downloading icons from a webpage which I'll share, however, it just does one image per multiple icons. Rather than multiple images per one icon.
I see. Thanks.
PNG format

The ability to read PNG images from ICO and CUR format images was introduced in Windows Vista.
A PNG image can be stored in the image in the same way as done for a standard Windows BMP format image, with the exception that the PNG image must be stored in its entirety, with its file header.
Wow! According to that link, CUR can have PNG! I didn't know. Last time I tried CUR format was in XP!
It would be nice to have a 256x256 transparent rectangle with solid 25px black border. Will definitely experiment with this.
gwarble wrote:Either way I would definitely consider it a picture format, but understand not wanting to add support for it...
Thanks for feedback, friend. Guess, I have to reconsider.


Update: Code was optimized for PNG format. Old version is now available as attachment.
My Scripts and Functions: V1  V2

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: ottowa and 151 guests