Hier die fertige Funktion:
function imagecreatefrombmp(): Läuft mit allen Bitraten! - Forum: PHP
Wie alles begann:
function imagecreatefrombmp(): Läuft mit allen Bitraten! - Forum: PHP
Wie alles begann:
Hi,
ich suche wie ein Verrückter nach einer funktionierenden imagecreatefrombmp() Funktion. Nun habe ich aus mehreren Quellen was gebaut, was ziemlich zuverlässig funktioniert:
Alle 16 Bit Bilder ohne Palette funktionieren tadellos. Aber bei denen mit Palette sieht es so aus:
Nun dachte ich, da ja 16 Bit ohne Palette funktioniert, dass ich die einfach mal unset()'e aber das resultiert dann das:
Also die Farben stimmen, aber das ganze ist nach wie vor verschoben. Wie viel von dem Bild ausgegeben wird, hängt vom Bild ab. Hier sieht man z.b. noch weniger:
Für 32 Bit habe ich übrigens auch noch keine Lösung, aber 16 Bit ist erstmal wichtiger
Bei meiner Recherche bin ich übrigens noch über die Variante gestolpert, die aber mit 16 Bit-Bildern überhaupt nicht umgehen kann (egal ob Palette oder nicht). 32 Bit habe ich noch nicht getestet. Sowohl die 16 Bit als auch die 32 Bit Regeln habe ich auf Grund weiterer Netzfunde hinzugefügt:
Vielleicht ist ja jemand fit in Bit-Verschiebungen und weiß eine Lösung?!
Dazu auch mal die Definition zu 16 Bit Bitmaps laut Wikipedia:
Windows Bitmap – Wikipedia
ich suche wie ein Verrückter nach einer funktionierenden imagecreatefrombmp() Funktion. Nun habe ich aus mehreren Quellen was gebaut, was ziemlich zuverlässig funktioniert:
PHP-Code:
function imagecreatefrombmp4($filename) {
if (!($fh = fopen($filename, 'rb'))) {
return false;
}
$file = unpack('vfile_type/Vfile_size/Vreserved/Vbitmap_offset', fread($fh, 14));
// bitmap check
if ($file['file_type'] != 19778) {
return false;
}
$bmp = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel/Vcompression/Vsize_bitmap/Vhoriz_resolution/Vvert_resolution/Vcolors_used/Vcolors_important', fread($fh, 40));
$bmp['colors'] = pow(2, $bmp['bits_per_pixel']);
if ($bmp['size_bitmap'] == 0) {
$bmp['size_bitmap'] = $file['file_size'] - $file['bitmap_offset'];
}
$bmp['bytes_per_pixel'] = $bmp['bits_per_pixel'] / 8;
$bmp['bytes_per_pixel2'] = ceil($bmp['bytes_per_pixel']);
$bmp['decal'] = ($bmp['width'] * $bmp['bytes_per_pixel'] / 4);
$bmp['decal'] -= floor($bmp['width'] * $bmp['bytes_per_pixel'] / 4);
$bmp['decal'] = 4 - (4 * $bmp['decal']);
if ($bmp['decal'] == 4) {
$bmp['decal'] = 0;
}
$palette = array();
if ($bmp['colors'] < 16777216) {
if (!($palette = @unpack('V' . $bmp['colors'], fread($fh, $bmp['colors'] * 4)))) {
// no palette found: rewind
$palette = array();
fseek($fh, 54);
}
}
$img = fread($fh, $bmp['size_bitmap']);
$vide = chr(0);
$res = imagecreatetruecolor($bmp['width'], $bmp['height']);
$p = 0;
$y = $bmp['height'] - 1;
while ($y >= 0) {
$x = 0;
while ($x < $bmp['width']) {
switch ($bmp['bits_per_pixel']) {
case 24:
$color = @unpack('V', substr($img, $p, 3) . $vide);
if (!$color) {
break;
}
break;
case 16:
// some have palette
if ($palette) {
$color = @unpack('n', substr($img, $p, 2));
if (!$color) {
break;
}
$color[1] = $palette[ $color[1] ];
}
else {
$color = @unpack('v', substr($img, $p, 2));
if (!$color) {
break;
}
$color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
}
break;
case 8:
$color = @unpack('n', $vide . substr($img, $p, 1));
if (!$color) {
break;
}
$color[1] = $palette[ $color[1] + 1 ];
break;
case 4:
$color = @unpack('n', $vide . substr($img, floor($p), 1));
if (!$color) {
break;
}
$color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
$color[1] = $palette[ $color[1] + 1 ];
break;
case 1:
$color = @unpack('n', $vide . substr($img, floor($p), 1));
if (!$color) {
break;
}
switch (($p * 8) % 8) {
case 0:
$color[1] = $color[1] >> 7;
break;
case 1:
$color[1] = ($color[1] & 0x40) >> 6;
break;
case 2:
$color[1] = ($color[1] & 0x20) >> 5;
break;
case 3:
$color[1] = ($color[1] & 0x10) >> 4;
break;
case 4:
$color[1] = ($color[1] & 0x8) >> 3;
break;
case 5:
$color[1] = ($color[1] & 0x4) >> 2;
break;
case 6:
$color[1] = ($color[1] & 0x2) >> 1;
break;
case 7:
$color[1] = ($color[1] & 0x1);
break;
}
$color[1] = $palette[ $color[1] + 1 ];
break;
default:
return false;
}
imagesetpixel($res, $x, $y, $color[1]);
$x++;
$p += $bmp['bytes_per_pixel'];
}
$y--;
$p += $bmp['decal'];
}
fclose($fh);
return $res;
}
Nun dachte ich, da ja 16 Bit ohne Palette funktioniert, dass ich die einfach mal unset()'e aber das resultiert dann das:
Also die Farben stimmen, aber das ganze ist nach wie vor verschoben. Wie viel von dem Bild ausgegeben wird, hängt vom Bild ab. Hier sieht man z.b. noch weniger:
Für 32 Bit habe ich übrigens auch noch keine Lösung, aber 16 Bit ist erstmal wichtiger
Bei meiner Recherche bin ich übrigens noch über die Variante gestolpert, die aber mit 16 Bit-Bildern überhaupt nicht umgehen kann (egal ob Palette oder nicht). 32 Bit habe ich noch nicht getestet. Sowohl die 16 Bit als auch die 32 Bit Regeln habe ich auf Grund weiterer Netzfunde hinzugefügt:
PHP-Code:
function bmp2gd($src, $dest = false) {
if(!($src_f = fopen($src, 'rb'))) {
return false;
}
if(!($dest_f = fopen($dest, 'wb'))) {
return false;
}
$header = unpack('vtype/Vsize/v2reserved/Voffset', fread($src_f, 14));
$info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant', fread($src_f, 40));
extract($info);
extract($header);
// check for bitmap
if ($type != 0x4D42) {
return false;
}
$palette_size = $offset - 54;
$ncolor = $palette_size / 4;
$gd_header = '';
// true-color vs. palette
$gd_header .= ($palette_size == 0) ? "\xFF\xFE" : "\xFF\xFF";
$gd_header .= pack('n2', $width, $height);
$gd_header .= ($palette_size == 0) ? "\x01" : "\x00";
if($palette_size) {
$gd_header .= pack('n', $ncolor);
}
// no transparency
$gd_header .= "\xFF\xFF\xFF\xFF";
fwrite($dest_f, $gd_header);
if($palette_size) {
$palette = fread($src_f, $palette_size);
$gd_palette = '';
$j = 0;
while($j < $palette_size) {
$b = $palette{$j++};
$g = $palette{$j++};
$r = $palette{$j++};
$a = $palette{$j++};
$gd_palette .= $r . $g . $b . $a;
}
$gd_palette .= str_repeat("\x00\x00\x00\x00", 256 - $ncolor);
fwrite($dest_f, $gd_palette);
}
$scan_line_size = (($bits * $width) + 7) >> 3;
$scan_line_align = ($scan_line_size & 0x03) ? 4 - ($scan_line_size & 0x03) : 0;
for($i = 0, $l = $height - 1; $i < $height; $i++, $l--) {
// BMP stores scan lines starting from bottom
fseek($src_f, $offset + (($scan_line_size + $scan_line_align) * $l));
$scan_line = fread($src_f, $scan_line_size);
switch ($bits) {
case 32:
$gd_scan_line = '';
$j = 0;
while($j < $scan_line_size) {
$b = $scan_line{$j++};
$g = $scan_line{$j++};
$r = $scan_line{$j++};
$a = chr(255 - ord($scan_line{$j++}));
$gd_scan_line .= $a . $r . $g . $b;
}
break;
case 24:
$gd_scan_line = '';
$j = 0;
while($j < $scan_line_size) {
$b = $scan_line{$j++};
$g = $scan_line{$j++};
$r = $scan_line{$j++};
$gd_scan_line .= "\x00" . $r . $g . $b;
}
break;
case 16:
$gd_scan_line = '';
$j = 0;
while ($j < $scan_line_size) {
$byte1 = $scan_line{$j++};
$byte2 = $scan_line{$j++};
$b = chr($byte1 >> 3) * (255 / 31);
$g = (chr($byte1 & 0x07) + chr($byte2 >> 5)) * (255 / 63);
$r = chr($byte2 & 0x1F) * (255 / 31);
$gd_scan_line .= "\x00" . $r . $g . $b;
}
break;
case 8:
$gd_scan_line = $scan_line;
break;
case 4:
$gd_scan_line = '';
$j = 0;
while($j < $scan_line_size) {
$byte = ord($scan_line{$j++});
$p1 = chr($byte >> 4);
$p2 = chr($byte & 0x0F);
$gd_scan_line .= $p1 . $p2;
}
$gd_scan_line = substr($gd_scan_line, 0, $width);
break;
case 1:
$gd_scan_line = '';
$j = 0;
while($j < $scan_line_size) {
$byte = ord($scan_line{$j++});
$p1 = chr((int) (($byte & 0x80) != 0));
$p2 = chr((int) (($byte & 0x40) != 0));
$p3 = chr((int) (($byte & 0x20) != 0));
$p4 = chr((int) (($byte & 0x10) != 0));
$p5 = chr((int) (($byte & 0x08) != 0));
$p6 = chr((int) (($byte & 0x04) != 0));
$p7 = chr((int) (($byte & 0x02) != 0));
$p8 = chr((int) (($byte & 0x01) != 0));
$gd_scan_line .= $p1 . $p2 . $p3 . $p4 . $p5 . $p6 . $p7 . $p8;
}
$gd_scan_line = substr($gd_scan_line, 0, $width);
break;
}
fwrite($dest_f, $gd_scan_line);
}
fclose($src_f);
fclose($dest_f);
return true;
}
function imagecreatefrombmp7($filename) {
$tmp_name = tempnam('/tmp', 'GD');
if (bmp2gd($filename, $tmp_name)) {
$img = imagecreatefromgd($tmp_name);
unlink($tmp_name);
return $img;
}
return false;
}
Dazu auch mal die Definition zu 16 Bit Bitmaps laut Wikipedia:
Windows Bitmap – Wikipedia
Kommentar