I\'m looking for a fast way to get the height and width of an image in pixels. It should handle at least JPG, PNG and TIFF, but the more the better. I emphasize
You can use ImageMagick's identify function. Here's how you do it in bash (Note $0 is the image's path):
width=$(identify -format "%w" "$0")> /dev/null
height=$(identify -format "%h" "$0")> /dev/null
And this also hides any potential error messages. Modern implementations of identify
only read the header, not the whole image, so it is fast. Not sure how it compares to other methods though.
If you have EXIF information in the images, you can just read the EXIF header.
It's the pixel dimensions you want (width and height), I assume?
I'd think that most file formats have some header info defining the dimensions, so that the software reading the file can know how much room it must reserve before starting to read the file. Some "raw" type file formats might just be a stream of bytes with some "end of line" byte at the end of each horizontal row of pixels (in which case the software must read the first line and divide the size of the byte stream by the line length to get the height).
I don't think you can make this in any "generic" way, as you need to understand the file format (or use a library of course) in order to know how to read it. You can probably find some code that will in most cases give a rough estimate of the dimensions without reading the whole file, but I think some filetypes may require you to read the whole file to be sure what dimensions it really have. I expect that most web centric image formats have a header with such info so that the browser can create the box dimensions before the whole image is loaded.
I'd guess a good library would have some methods to get the dimensions of the files it handles, and that those methods would be implemented as efficient as possible.
Update: imageinfo seems like it does what you want. (Have not tested it)
https://joseluisbz.wordpress.com/2013/08/06/obtaining-size-or-dimension-of-images/ (BMP, PNG, GIF, JPG, TIF or WMF)
Here for two formats PNG and JPG.
My code is from a class designed to my use, you can to edit according to your needs.
Please check these functions/method using PHP:
public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
$Alto = 0;
$Ancho = 0;
$Formato = -1;
$this->HexImageString = "Error";
if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
$Formato = 1; //PNG
$Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
$Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
}
if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
&& ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
$Formato = 2; //JPG
$PosJPG = 2;
while ($PosJPG<strlen($ByteStream)){
if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
$Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
$Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
}
$PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
}
}
if ($Formato > 0){
$this->HexImageString = "";
$Salto = 0;
for ($i=0;$i < strlen($ByteStream); $i++){
$Salto++;
$this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
if ($Salto==64){
$this->HexImageString .= "\n";
$Salto = 0;
}
}
}
}
private function Byte2PosInt($Byte08,$Byte00) {
return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
}
Using the PHP Code:
$iFormato = NULL;//Format PNG or JPG
$iAlto = NULL; //High
$iAncho = NULL;//Wide
ByteStreamImageString($ImageJPG,$iFormato,$iAlto,$iAncho);//The Dimensions will stored in iFormato,iAlto,iAncho
Now these functions/method using JAVA:
private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
High[0] = 0;
Wide[0] = 0;
Frmt[0] = -1;
this.HexImageString = "Error";
if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
Frmt[0] = 1; //PNG
High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
}
if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
&&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
Frmt[0] = 2; //JPG
int PosJPG = 2;
while (PosJPG<ByteStream.length){
if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
}
PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
}
}
if (Frmt[0] > 0){
this.HexImageString = "";
int Salto = 0;
for (int i=0;i < ByteStream.length; i++){
Salto++;
this.HexImageString += String.format("%02x", ByteStream[i]);
if (Salto==64){
this.HexImageString += "\n";
Salto = 0;
}
}
}
}
private Integer Byte2PosInt(byte Byte08, byte Byte00) {
return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
}
Using the Java code:
int[] iFormato = new int[1]; //Format PNG or JPG
int[] iAlto = new int[1]; //High
int[] iAncho = new int[1]; //Wide
ByteStreamImageString(ImageJPG,iFormato,iAlto,iAncho); //The Dimensions will stored in iFormato[0],iAlto[0],iAncho[0]
tldr: file "imagename" will do
works with webp, all jpg formats (jpeg,jpg200,..),
Sample output looks like
JPEG image data, JFIF standard 1.02, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 650x400, frames 3
load the output of file to a python list & use the 4'th field in the list.
FYI, did optimize around 18000+ images to cut down network traffic.
Imagemagick -ping
option
It seems to have been introduced for that purpose.
However as of ImageMagick 6.7.7 I don't observe slowdown even for every large files, e.g.:
head -c 100000000 /dev/urandom > f.gray
# I don't recommend that you run this command as it eats a lot of memory.
convert -depth 8 -size 20000x10000 f.gray f.png
identify f.png
Can you produce an example input image for which it is still slow?
See also: Can ImageMagick return the image size?