Page 3 of 4
Re: Get image width and height without loading image
Posted: Wed Feb 10, 2016 4:38 pm
by IdeasVacuum
Hello chaps, sorry to bother you with this.
I'm using this code with PB5.42Beta1 on Win7 x86. The code is super fast and is giving accurate results.
However, a few files return a size of zero zero. I have set #ImageHeaderSize = 4096
ImageSize.zip
Edit: I should mention that I'm using Michael Vogel's "Wilbert-style" code, posted: Fri Mar 20, 2015 2:48pm
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 12:20 am
by Michael Vogel
IdeasVacuum, maybe you will try the following tool to check if I do something wrong:
Speed Renamer - just copy all files in the same directory as your example images.
After starting the SpeedRenamer, all image files should be prepared to be renamed to "
<px> x <py>.<e>", what means "
width x height plus extension"...
...if everything works as expected, I will extract all parts from the source you need for your program.
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 12:36 am
by IdeasVacuum
Points of interest
The Win7 sample images verify zero zero with #ImageHeaderSize = 4096. They are all the same Width/Height, all .jpgs, Filesizes range from 549KB to 859KB.
If #ImageHeaderSize = 8182, all but two of the images verify.
If #ImageHeaderSize = 10240, all images verify.
Instead of using the #ImageHeaderSize constant, I tried FileSize() instead. This also worked with the Win7 sample images but not with the bunch of .jpg files I have posted here. Tricky

Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 12:43 am
by Michael Vogel
Are these values ok?

Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 12:51 am
by IdeasVacuum
Hello Michael
Followed your instructions and sure enough, SpeedRenamer lists the files, new "<px> x <py>.<e>" name and their Width/Height/Size, as shown in your screenshot. The sizes match those reported by the OS and by IrfanView.
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 1:12 am
by Michael Vogel
Okay, will extract the code, but you have to be patient, will do so tomorrow morning...
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 1:17 am
by IdeasVacuum
That is very kind of you Michael and much appreciated.
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 8:38 am
by Michael Vogel
Here we are (hope it works)...
Code: Select all
Structure FileType
ImageX.i
ImageY.i
EndStructure
Global Dim File.FileType(0)
Procedure.i iAbs(val.i)
EnableASM
CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
MOV eax, val
NEG eax
CMOVS eax, val
CompilerElse
MOV rax, val
NEG rax
CMOVS rax, val
CompilerEndIf
DisableASM
ProcedureReturn
EndProcedure
Procedure GetImageInformation(entry,filename.s)
#ImageMinimumSize= 24
#ImageHeaderSize= 2048
#ImageHeaderGIF= $38464947; 'GIF8'
#ImageHeaderJPG0= $E0FFD8FF; -
#ImageHeaderJPG1= $E1FFD8FF; -
#ImageHeaderJP2= $0C000000; -
#ImageHeaderPNG= $474E5089; '‰PNG'
#ImageHeaderBMP= $4D42; 'BM'
#ImageHeaderTIF_LSB= $4949; 'II'
#ImageHeaderTIF_MSB= $4D4D; 'MM'
#ImageHeaderPCX= $0A; -
#ImageHeaderTGA= $01; -
Structure MemArray
StructureUnion
a.a[0]
w.w[0]
l.l[0]
EndStructureUnion
EndStructure
Protected *Buffer.MemArray
Protected *MemArray.MemArray
Protected BytesRead
Protected FileShift
Protected a.a,n.l,m
#ImageFile=666
File(entry)\ImageX=#Null
File(entry)\ImageY=#Null
If #True
If ReadFile(#ImageFile,FileName, #PB_File_NoBuffering|#PB_File_SharedRead)
*Buffer=AllocateMemory(#ImageHeaderSize,#PB_Memory_NoClear)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
If BytesRead>=#ImageMinimumSize
Select *Buffer\l[0]&$FFFFFFFF
Case #ImageHeaderJPG0,#ImageHeaderJPG1
n=*Buffer\a[4]<< 8|*Buffer\a[5]+4
If n>20
FileShift=n
FileSeek(#ImageFile,n)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
n=0
EndIf
*MemArray=*Buffer+n
While *MemArray-*Buffer+8<=BytesRead; 8 Bytes Information
If *MemArray\a[0]=$FF
a=*MemArray\a[1]
; Debug Hex(*MemArray\w[0])
If a=$c0 Or (a>>4=$C And a&3)
File(entry)\ImageX=*MemArray\a[7]<<8|*MemArray\a[8]
File(entry)\ImageY=*MemArray\a[5]<<8|*MemArray\a[6]
Break
EndIf
Else
Break
EndIf
*MemArray+*MemArray\a[2]<<8|*MemArray\a[3]+2
If *MemArray-*Buffer>=BytesRead-8; 8 Bytes Information
FileShift+*MemArray-*Buffer
FileSeek(#ImageFile,FileShift)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
*MemArray=*Buffer
EndIf
Wend
Case #ImageHeaderPNG
File(entry)\ImageX=*Buffer\a[18]<<8|*Buffer\a[19]
File(entry)\ImageY=*Buffer\a[22]<<8|*Buffer\a[23]
Case #ImageHeaderGIF
File(entry)\ImageX=*Buffer\w[3]
File(entry)\ImageY=*Buffer\w[4]
Case #ImageHeaderJP2
n=*Buffer\a[14]<<8|*Buffer\a[15]+35
If n<#ImageHeaderSize
File(entry)\ImageX=*Buffer\a[n-1]<<8|*Buffer\a[n]
File(entry)\ImageY=*Buffer\a[n-5]<<8|*Buffer\a[n-4]
EndIf
Default
Select *Buffer\w[0]&$FFFF
Case #ImageHeaderBMP
File(entry)\ImageX=*Buffer\w[9]
File(entry)\ImageY=iAbs(*Buffer\w[11]&$FFFF)
Case #ImageHeaderTIF_LSB
a=0
n=*Buffer\l[1]
If n<#ImageHeaderSize
n>>1
m=*Buffer\w[n]
n+1
While m
Select *Buffer\w[n]
Case $100
File(entry)\ImageX=*Buffer\w[n+4]
a|1
Case $101
File(entry)\ImageY=*Buffer\w[n+4]
a|2
EndSelect
If a=3
m=0
Else
n+6
m-1
EndIf
Wend
EndIf
Case #ImageHeaderTIF_MSB
a=0
n=*Buffer\a[6]<<8|*Buffer\a[7]
If n<#ImageHeaderSize
m=*Buffer\a[n]<<8|*Buffer\a[n+1]
n+2
While m
Select *Buffer\a[n]<<8|*Buffer\a[n+1]
Case $100
File(entry)\ImageX=*Buffer\a[n+8]<<8|*Buffer\a[n+9]
a|1
Case $101
File(entry)\ImageY=*Buffer\a[n+8]<<8|*Buffer\a[n+9]
a|2
EndSelect
If a=3
m=0
Else
n+12
m-1
EndIf
Wend
EndIf
Default
Select *Buffer\a[0]
Case #ImageHeaderPCX
If *Buffer\a[1]<6
File(entry)\ImageX=*Buffer\w[4]+1
File(entry)\ImageY=*Buffer\w[5]+1
EndIf
Case #ImageHeaderTGA
If *Buffer\a[1]<2 And *Buffer\a[2]&%11110100=0
File(entry)\ImageX=*Buffer\w[6]
File(entry)\ImageY=*Buffer\w[7]
EndIf
EndSelect
EndSelect
EndSelect
EndIf
FreeMemory(*Buffer)
CloseFile(#ImageFile)
EndIf
EndIf
EndProcedure
If ExamineDirectory(0,".","*.jpg")
While NextDirectoryEntry(0)
If DirectoryEntryType(0)=#PB_DirectoryEntry_File
file.s=DirectoryEntryName(0)
GetImageInformation(0,file)
Debug file+": "+Str(File(0)\ImageX)+" x "+Str(File(0)\ImageY)
EndIf
Wend
FinishDirectory(0)
EndIf
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 11:37 am
by IdeasVacuum
That was fast Michael, thank you.
So, essentially the change is: replace #ImageHeaderJPG with #ImageHeaderJPG0 and #ImageHeaderJPG1?
I'm getting a crash at FileSeek(0, n) at the moment - possibly a file hitherto untried. Time for me to experiment a bit.
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 12:22 pm
by IdeasVacuum
OK, in fact a number of subtle changes have been made.
I have tested the "rogue" images and as many suspect images that I can find, all of which now process beautifully. Also, it's no longer necessary to increase the buffer size in order to verify the Win7 sample images.
Brilliant job Michael!
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 5:51 pm
by IdeasVacuum
So, of any 100 images, 2% are not being verified via the header. In my app, if the Width or Height result is zero, another procedure is called to load the image and verify with the PB functions. There is no noticable lack of speed, but of course if a whole batch of images failed rather than 2%, that could be a bit slower (2.5 seconds on my PC).
The .jpg files seem to be the most unreliable......
Here is one that SpeedRenamer verifies as 0 x 0 size. Actual size is 960 x 960 (104KB)
Denzil Washington.zip
The start of the other files is typically: FF E0
00 10 4A 46 49 46 00
Denzil Washinton.jpg: FF E2 02 1C 49 43 43 5F 50
Re: Get image width and height without loading image
Posted: Thu Feb 11, 2016 10:57 pm
by Michael Vogel
Please check if you'll get better results than 98% by doing a small update...
Change/add the following constants:
#ImageHeaderAPP1= $E1FFD8FF; was #ImageHeaderJPG1
#ImageHeaderAPP2= $E2FFD8FF; new
Change the first line with a Case statement to:
Case #ImageHeaderJPG0,#ImageHeaderAPP1,#ImageHeaderAPP2
Re: Get image width and height without loading image
Posted: Fri Feb 12, 2016 2:07 am
by IdeasVacuum
Hello Michael
That has fixed Denzil Washington.jpg types
What I have not tested are tif, tga, jp2 (have not got files of those types)
Edit: Just converted mostly .jpg files to .tif and .tga files using IrfanView. Not one of them verifies....
Re: Get image width and height without loading image
Posted: Fri Feb 12, 2016 6:28 pm
by Michael Vogel
So still not 100%, I fear, we'll never get very close
TGA and TIF examples
Code: Select all
Structure FileType
ImageX.i
ImageY.i
EndStructure
Global Dim File.FileType(0)
Procedure.i iAbs(val.i)
EnableASM
CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
MOV eax, val
NEG eax
CMOVS eax, val
CompilerElse
MOV rax, val
NEG rax
CMOVS rax, val
CompilerEndIf
DisableASM
ProcedureReturn
EndProcedure
Procedure GetImageInformation(entry,filename.s)
#ImageMinimumSize= 24
#ImageHeaderSize= 2048
#ImageHeaderSizeTif= 48; Just a guess
#ImageHeaderGIF= $38464947; 'GIF8'
#ImageHeaderJPG= $E0FFD8FF; -
#ImageHeaderAPP1= $E1FFD8FF; -
#ImageHeaderAPP2= $E2FFD8FF; -
#ImageHeaderJP2= $0C000000; -
#ImageHeaderPNG= $474E5089; '‰PNG'
#ImageHeaderBMP= $4D42; 'BM'
#ImageHeaderTIF_LSB= $4949; 'II'
#ImageHeaderTIF_MSB= $4D4D; 'MM'
#ImageHeaderPCX= $0A; -
#ImageHeaderTGA= $01; -
Structure MemArray
StructureUnion
a.a[0]
w.w[0]
l.l[0]
EndStructureUnion
EndStructure
Protected *Buffer.MemArray
Protected *MemArray.MemArray
Protected BytesRead
Protected FileShift
Protected a.a,n.l,m
#ImageFile=666
File(entry)\ImageX=#Null
File(entry)\ImageY=#Null
If #True
If ReadFile(#ImageFile,FileName, #PB_File_NoBuffering|#PB_File_SharedRead)
*Buffer=AllocateMemory(#ImageHeaderSize,#PB_Memory_NoClear)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
If BytesRead>=#ImageMinimumSize
; Debug Hex(*Buffer\l[0]&$FFFFFFFF)
Select *Buffer\l[0]&$FFFFFFFF
Case #ImageHeaderJPG,#ImageHeaderAPP1,#ImageHeaderAPP2
n=*Buffer\a[4]<< 8|*Buffer\a[5]+4
If n>20
FileShift=n
FileSeek(#ImageFile,n)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
n=0
EndIf
*MemArray=*Buffer+n
While *MemArray-*Buffer+8<=BytesRead; 8 Bytes Information
If *MemArray\a[0]=$FF
a=*MemArray\a[1]
; Debug Hex(*MemArray\w[0])
If a=$c0 Or (a>>4=$C And a&3)
File(entry)\ImageX=*MemArray\a[7]<<8|*MemArray\a[8]
File(entry)\ImageY=*MemArray\a[5]<<8|*MemArray\a[6]
Break
EndIf
Else
Break
EndIf
*MemArray+*MemArray\a[2]<<8|*MemArray\a[3]+2
If *MemArray-*Buffer>=BytesRead-8; 8 Bytes Information
FileShift+*MemArray-*Buffer
FileSeek(#ImageFile,FileShift)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
*MemArray=*Buffer
EndIf
Wend
Case #ImageHeaderPNG
File(entry)\ImageX=*Buffer\a[18]<<8|*Buffer\a[19]
File(entry)\ImageY=*Buffer\a[22]<<8|*Buffer\a[23]
Case #ImageHeaderGIF
File(entry)\ImageX=*Buffer\w[3]
File(entry)\ImageY=*Buffer\w[4]
Case #ImageHeaderJP2
n=*Buffer\a[14]<<8|*Buffer\a[15]+35
If n<#ImageHeaderSize
File(entry)\ImageX=*Buffer\a[n-1]<<8|*Buffer\a[n]
File(entry)\ImageY=*Buffer\a[n-5]<<8|*Buffer\a[n-4]
EndIf
Default
Select *Buffer\w[0]&$FFFF
Case #ImageHeaderBMP
File(entry)\ImageX=*Buffer\w[9]
File(entry)\ImageY=iAbs(*Buffer\w[11]&$FFFF)
Case #ImageHeaderTIF_LSB
a=0
n=*Buffer\l[1]
If n>#ImageHeaderSize-#ImageHeaderSizeTif
FileShift=n
FileSeek(#ImageFile,n)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
n=0
EndIf
n>>1
m=*Buffer\w[n]
n+1
While m And n<#ImageHeaderSizeTif>>1
Select *Buffer\w[n]
Case $100
File(entry)\ImageX=*Buffer\w[n+4]
a|1
Case $101
File(entry)\ImageY=*Buffer\w[n+4]
a|2
EndSelect
If a=3
m=0
Else
n+6
m-1
EndIf
Wend
Case #ImageHeaderTIF_MSB
a=0
n=*Buffer\a[6]<<8|*Buffer\a[7]
If n>#ImageHeaderSize-#ImageHeaderSizeTif
FileShift=n
FileSeek(#ImageFile,n)
BytesRead=ReadData(#ImageFile,*Buffer,#ImageHeaderSize)
n=0
EndIf
m=*Buffer\a[n]<<8|*Buffer\a[n+1]
n+2
While m And n<#ImageHeaderSizeTif
Select *Buffer\a[n]<<8|*Buffer\a[n+1]
Case $100
File(entry)\ImageX=*Buffer\a[n+8]<<8|*Buffer\a[n+9]
a|1
Case $101
File(entry)\ImageY=*Buffer\a[n+8]<<8|*Buffer\a[n+9]
a|2
EndSelect
If a=3
m=0
Else
n+12
m-1
EndIf
Wend
Default
Select *Buffer\a[0]
Case #ImageHeaderPCX
If *Buffer\a[1]<6
File(entry)\ImageX=*Buffer\w[4]+1
File(entry)\ImageY=*Buffer\w[5]+1
EndIf
Case #ImageHeaderTGA
If *Buffer\a[1]<2 And *Buffer\a[2]&%11110100=0
File(entry)\ImageX=*Buffer\w[6]
File(entry)\ImageY=*Buffer\w[7]
EndIf
EndSelect
EndSelect
EndSelect
EndIf
FreeMemory(*Buffer)
CloseFile(#ImageFile)
EndIf
EndIf
EndProcedure
If ExamineDirectory(0,".","*.t??")
While NextDirectoryEntry(0)
If DirectoryEntryType(0)=#PB_DirectoryEntry_File
file.s=DirectoryEntryName(0)
GetImageInformation(0,file)
Debug RSet(Str(File(0)\ImageX),5," ")+" x"+RSet(Str(File(0)\ImageY),5," ")+" | "+file
EndIf
Wend
FinishDirectory(0)
EndIf
Re: Get image width and height without loading image
Posted: Fri Feb 12, 2016 8:37 pm
by IdeasVacuum
That's strange Michael - the new code for tif does not work with your sample file P1170938.tif on my PC.
Actually, I think you have got very close already, it's a brilliant job as-is.
IrfanViewTIF.zip
IrfanViewTGA.zip
If you haven't got the time to do more, or just don't fancy it, that's fine by me, you have been brilliant.