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

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

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.