php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #25581 getimagesize () return incorrect values on bitmap (os2) files
Submitted: 2003-09-17 16:38 UTC Modified: 2003-10-25 10:06 UTC
From: willertan1980 at yahoo dot com Assigned: helly (profile)
Status: Closed Package: Feature/Change Request
PHP Version: 4.3.3 OS: *
Private report: No CVE-ID: None
 [2003-09-17 16:38 UTC] willertan1980 at yahoo dot com
Description:
------------
getimagesize () return incorrect values on bitmap files

SYSTEM PHP 4.3.1(bundled version gd >1.6) , WinXP IIS 5.1 server, Intel P4 CPU
TESTED image : RGB 24bits OS/2 bitmap (BM) generated by Photoshop 7.0

>>HEX DUMP image data 1st 32bytes - bitmaps header 12 bytes
4d    2c    d0    01    00    00    00    00    00    1a    00    00    00    0c    00   
00    f0    00    a5    00    01    00    18    00    b0    7f    6d    a9    75    62   


i realized that getimagesize () read OS/2 1.x bitmap by using Windows 3.x / OS/2 2.x structure, that is the reason the output was incorrect.

>>DUMP form getimagesize () :
Array ( [0] => 10813680 [1] => 1572865 [2] => 6 [3] => width="10813680" height="1572865" [bits] => 43373 [mime] => image/bmp )

>>DUMP from my own function, bmp_info () (identical to values that given by WinXP properties and photoshop 7)
Array ( [width] => 240 [height] => 165 [planes] => 1 [bits] => 24 [bi_type] => Bitmap [bi_hsz] => 12 [bi_htype] => OS/2 1.x [ncolor] => 16777216 [xdensity] => 96 [ydensity] => 96 [density_mod] => 1 [component] => 3 [compression] => 0 )



>>Header for bmp >= Windows 2.x and OS/2 1.x
typedef struct _WinBMPFileHeader, 14 bytes
{
    WORD   FileType;
    DWORD  FileSize;
    WORD   Reserved1;
    WORD   Reserved2;
    DWORD  BitmapOffset;
} WINBMPFILEHEADER;


Bitmap Windows 3.x should use this format, always 40 bytes

typedef struct tagBITMAPINFOHEADER{
  DWORD  biSize; 
  LONG   biWidth; 
  LONG   biHeight; 
  WORD   biPlanes; 
  WORD   biBitCount; 
  DWORD  biCompression; 
  DWORD  biSizeImage; 
  LONG   biXPelsPerMeter; 
  LONG   biYPelsPerMeter; 
  DWORD  biClrUsed; 
  DWORD  biClrImportant; 
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

but Bitmap Windows 2.x and OS/2 1.x should read like this, and its always 12 bytes

typedef struct _Win2xBitmapHeader
{
    DWORD Size;
    SHORT Width;
    SHORT Height;
    WORD  Planes;
    WORD  BitsPerPixel;
} WIN2XBITMAPHEADER;



REFERENCE

http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
http://netghost.narod.ru/gff/graphics/summary/micbmp.htm

Windows BITMAPINFO-
http://msdn.microsoft.com/library/en-us/gdi/bitmaps_0zn6.asp?frame=true
Windows BITMAPINFOHEADER-
http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp?frame=true

http://www.fastgraph.com/help/bmp_header_format.html

*please remove this message if outdated or solved


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-09-18 15:40 UTC] helly@php.net
You realized wrong. We are only reading the 12 bytes that are the same in all formats. Thus the error must by elsewhere. If you find out where feel free to provide a patch. Until then we simply do not support such images.
 [2003-09-22 00:35 UTC] willertan1980 at yahoo dot com
I wish to make it clear. I did not find this bug from somewhere else.
Ok, maybe I was to blame by not making a good explanation
I just installed the latest version (php 4.3.3) as told
And the problem still exists
The problem file ? Bitmap file saved by using OS2/1.x or Win 2.x header
(You can generate this file by using Photoshop, just draw something and save it with
Save As: bmp-> file format -> choose OS/2 instead of windows)

This time, I do a check on PHP source code (php 4.3.3)
And I found this bug at 
\ext\standard\image.c (lines 154)
result->width = 
(((unsigned int)dim[ 3]) << 24) + (((unsigned int)dim[ 2]) << 16) + (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]);
result->height = 
(((unsigned int)dim[ 7]) << 24) + (((unsigned int)dim[ 6]) << 16) + (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]);

PHP was reading 4 bytes for each width and height, that is true if for readings >win3.x and >os2 2.x, because it is LONG integer, but for os2 1.x and win 2.x it is SHORT int, should be read as 2 bytes SHORT

OLDER VERSION - os2 1.x and win 2.x
DWORD biSize; // 
SHORT biWidth;
SHORT biHeight;
WORD  biPlanes;
WORD  biBitCount;

NEWER VERSION >win3.x and >os2 2.x
DWORD  biSize; 
LONG   biWidth; 
LONG   biHeight; 
WORD   biPlanes; 
WORD   biBitCount;

little-endian byte order
A HEX DUMP from Bitmap file that generated by Photoshop 7.0
width = 200 px = c8
height = 200 px = c8

(draw something and save it as bitmap (os2) 24bit)

// 2 bytes, magic bytes = ?BM?
42 4d
// 4 bytes FileSize; 2 bytes Reserved1; 2 bytes Reserved2; 4 bytes BitmapOffset
dc d4 01 00  00 00  00 00  1a 00 00 00 
// 4 bytes, BiLength, bmp header length = 12
0c 00 00 00

Assumed win2.x 
// 2 bytes Width; 2 bytes height; 2 bytes biplanes; 2 bytes biBitCount
c8 00  c8 00  01 00  18 00  ff ff ff ff ff  

it is predicable by assuming getimagesize reads 4 bytes for width and height, by the fact getimagesize did so.
Assumed win3.x 
// 4 bytes width; 4 bytes height; 2 bytes biplanes; 2 bytes biBitCount
c8 00 c8 00  01 00 18 00  ff ff  ff ff  ff  
Width = c8 00 c8 00
Height = 01 00 18 00
Bits = ff ff

by the fact getimagesize did this mistake in \ext\standard\image.c (lines 154)

This is how getimagesize () flush out from 
print_r(getimagesize('D:\Inetpub\New PHP artbook gen 7\Test pic\_color\bitmap_os2.bmp' ));
Array ( [0] => 13107400 [1] => 1572865 [2] => 6 [3] => width="13107400" height="1572865" [bits] => 65535 [mime] => image/bmp )

Width = 13107400 = 00 c8 00 c8 // 4 bytes
Height = 1572865 = 00 18 00 01 // 4 bytes
Bits = 65535 = ff ff

You can observed that by convert width values to hex (little-endian) = c8 00 c8 00
Because os2 1.x (older version of bitmap) is 2 bytes in length but PHP fetch it by 4 bytes.

It should be fix by -> If header length equal to 12, do below
result->width = (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]);
result->height = (((unsigned int)dim[ 3]) << 8) + ((unsigned int) dim[ 2]);
result->bits = (((unsigned int)dim[7]) << 8) + ((unsigned int)dim[6]);

I think, more length check should be done, if PHP wishing to extend the getimagesize() function on bmp.file

Here are some of my suggestions;
If length ==12 then read as bitmap win2.x or os/2 1.x
If length == 40 then read as bitmap win3.x
If length == 108 then read as bitmap win95 (version 4)
If length >12 and not 40 or 108 (typically 64, varying in size/fields) 
then read as bitmap IBM OS/2 2.x <- this part making me really headache :P

In addition, this is a ?very old? windows bitmap structure, win1.x
typedef struct _Win1xHeader
{
    WORD Type;        /* File type identifier (always 0) */
    WORD Width;      /* Width of the bitmap in pixels */
    WORD Height;     /* Height of the bitmap in scan lines */
    WORD ByteWidth; /* Width of bitmap in bytes */
    BYTE Planes;      /* Number of color planes */
    BYTE BitsPerPixel; /* Number of bits per pixel */
} WIN1XHEADER;

my system 
PHP 4.3.3 (bundled version)
OS: Windows sp1 on NTFS part ion
Server : IIS 5.1
Intel P4 cpu
 [2003-10-25 10:06 UTC] helly@php.net
This bug has been fixed in CVS.

In case this was a PHP problem, snapshots of the sources are packaged
every three hours; this change will be in the next snapshot. You can
grab the snapshot at http://snaps.php.net/.
 
In case this was a documentation problem, the fix will show up soon at
http://www.php.net/manual/.

In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites in short time.
 
Thank you for the report, and for helping us make PHP better.

Will be fixed in PHP 5b2
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Sun Sep 23 22:01:25 2018 UTC