php.de

Zurück   php.de > Webentwicklung > PHP-Fortgeschrittene

PHP-Fortgeschrittene Arbeiten mit PHP ohne Einschränkungen

Antwort
 
LinkBack Themen-Optionen Bewertung: Bewertung: 1 Stimmen, 1,00 durchschnittlich.
Alt 16.04.2010, 22:18  
Benutzer
 
Registriert seit: 17.06.2009
Beiträge: 97
PHP-Kenntnisse:
Fortgeschritten
hondatuner befindet sich auf einem aufstrebenden Ast
Standard [Erledigt] imagecreatefrombmp(): 16 Bit & 32 Bit Bitmaps

Hier die fertige Funktion:
function imagecreatefrombmp(): Läuft mit allen Bitraten! - Forum: PHP

Wie alles begann:
Zitat:
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:
PHP-Code:
function imagecreatefrombmp4($filename) {
    if (!(
$fh fopen($filename'rb'))) {
        return 
false;
    }
    
$file unpack('vfile_type/Vfile_size/Vreserved/Vbitmap_offset'fread($fh14));
    
// 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($fh40));
    
$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'] = - ($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($fh54);
        }
    }
    
$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$p3) . $vide);
                    if (!
$color) {
                        break;
                    }
                    break;
                case 
16:
                    
// some have palette
                    
if ($palette) {
                        
$color = @unpack('n'substr($img$p2));
                        if (!
$color) {
                            break;
                        }
                        
$color[1] = $palette$color[1] ];
                    }
                    else {
                        
$color = @unpack('v'substr($img$p2));
                        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$p1));
                    if (!
$color) {
                        break;
                    }
                    
$color[1] = $palette$color[1] + ];
                    break;
                case 
4:
                    
$color = @unpack('n'$vide substr($imgfloor($p), 1));
                    if (!
$color) {
                        break;
                    }
                    
$color[1] = ($p 2) % == $color[1] >> $color[1] & 0x0F;
                    
$color[1] = $palette$color[1] + ];
                    break;
                case 
1:
                    
$color = @unpack('n'$vide substr($imgfloor($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] + ];
                    break;
                default:
                    return 
false;
            }
            
imagesetpixel($res$x$y$color[1]);
            
$x++;
            
$p += $bmp['bytes_per_pixel'];
        }
        
$y--;
        
$p += $bmp['decal'];
    }
    
fclose($fh);
    return 
$res;

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:
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_f14));
    
$info unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant'fread($src_f40));
    
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) ? - ($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_line0$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_line0$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;

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
__________________
meine PHP Scripte

Geändert von hondatuner (20.04.2010 um 11:20 Uhr).
hondatuner ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 16.04.2010, 22:24  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 35.987
PHP-Kenntnisse:
Fortgeschritten
nikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunftnikosch hat eine strahlende Zukunft
Standard

Sorry, aber mit komplett unkommentierten Code und ohne weitere Ausführungen hier anzurücken, finde ich ja etwas dreist.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist offline   Mit Zitat antworten
Alt 16.04.2010, 23:08  
Benutzer
 
Registriert seit: 17.06.2009
Beiträge: 97
PHP-Kenntnisse:
Fortgeschritten
hondatuner befindet sich auf einem aufstrebenden Ast
Standard

Nun der Code ist nicht von mir und die Bit-Extraktion verstehe ich zu wenig, um sie kommentieren zu können. Was willst Du denn wissen?

EDIT:
Upps, ich sehe gerade, dass ich beim Editieren einen Teil meines Beitrags überschrieben habe. Mist.

Ich versuche es mal wiederherzustellen. Also im ersten Schritt wird bei jedem Bild geprüft ob in den Meta-Daten eine Palette vorhanden ist:
PHP-Code:
    $palette = array(); 
    if (
$bmp['colors'] < 16777216) { 
        if (!(
$palette = @unpack('V' $bmp['colors'], fread($fh$bmp['colors'] * 4)))) { 
            
// no palette found: rewind 
            
$palette = array(); 
            
fseek($fh54); 
        } 
    } 
Ein 16 Bit Bild kann im Gegensatz zu den Kommentaren bei php.net sehr wohl auch eine Palette haben.

Im Falle von 16 Bit greift dann dieser Part:
PHP-Code:
                case 16
                    
// some have palette 
                    
if ($palette) { 
                        
$color = @unpack('n'substr($img$p2)); 
                        if (!
$color) { 
                            break; 
                        } 
                        
$color[1] = $palette$color[1] ]; 
                    } 
                    else { 
                        
$color = @unpack('v'substr($img$p2)); 
                        if (!
$color) { 
                            break; 
                        } 
                        
$color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3); 
                    } 
                    break; 
Die ohne Palette funktionieren wie gesagt wie gewünscht. Wenn es aber eine Palette gibt, ensteht das oben genannte 1. Bild. Schmeiße ich diese Palette dann manuell raus, so dass der Else-Teil greift, so sehe ich das 2. Bild mit korrekten Farben, aber immer noch verschobenem Inhalt.

EDIT2:
Ok so viel habe ich schon mal:
16 Bit hat doch keine Palette. Es gab nur zufälligerweise Bilder, in denen die ausgelesenen Bytes als Palette erkannt wurden. Allerdings hat 16 Bit einen größeren Header. Den versuche ich jetzt gerade zu extrahieren und herauszufinden, was da drin steht. Später mehr dazu...
__________________
meine PHP Scripte

Geändert von hondatuner (17.04.2010 um 00:13 Uhr).
hondatuner ist offline   Mit Zitat antworten
Alt 17.04.2010, 00:20  
Erfahrener Benutzer
 
Benutzerbild von lstegelitz
 
Registriert seit: 07.09.2009
Beiträge: 4.005
PHP-Kenntnisse:
Fortgeschritten
lstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nett
Standard

PHP-Code:
    if ($bmp['colors'] < 16777216) {
        if (!(
$palette = @unpack('V' $bmp['colors'], fread($fh$bmp['colors'] * 4)))) { 
Du gehst bei einer 16Bit Palette davon aus, das jeder Farbwert mit 4 Byte kodiert ist... isses aber nicht (siehe auch wikipedia)
Zitat:
16 bpp:
Das Format ist wie bei BI_BITFIELDS, wenn folgende Farbmasken verwendet würden:

0x00007C00 für den Rot-Kanal
0x000003E0 für den Grün-Kanal
0x0000001F für den Blau-Kanal

Jeder Farbkanal ist 5 Bit pro Pixel groß; insgesamt ergeben sich 32.768 mögliche Farben (ein Bit ist ungenutzt).
Dadurch liest du bereits Bilddaten in die Palette und bekommst nur ein halbes Bild. Die falschen Farben ergeben sich übrigens auch daraus
__________________
Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.
lstegelitz ist offline   Mit Zitat antworten
Alt 17.04.2010, 01:25  
Benutzer
 
Registriert seit: 17.06.2009
Beiträge: 97
PHP-Kenntnisse:
Fortgeschritten
hondatuner befindet sich auf einem aufstrebenden Ast
Standard

Jo, hatte ich in meinem EDIT schon erkannt.

Bei 16-Bit griff das Auslesen der Palette eigentlich nur zufällig und ich dachte deswegen, dass es eine geben müsse. Tat es aber nicht. Stattdessen hatte ich eigentlich nur das Problem, dass bei 16-Bit 5:6:5 maskierten Bitmaps ein zusätzlicher Header (rMask, gMask & bMask) ausgelesen werden muss bzw. dieser hätte übersprungen werden müssen, um an das erste Byte des Bilder zu kommen.

Erst wusste ich nichts mit den Mask-Werten anzufangen, bin dann aber hier und hier schnell fündig geworden.

Damit steht nun die Version, die auch mit 16-Bit Bitmaps umgehen kann:
PHP-Code:
if (!function_exists('imagecreatefrombmp')) { function imagecreatefrombmp($filename) {
    if (!(
$fh fopen($filename'rb'))) {
        
trigger_error('imagecreatefrombmp: Can not open ' $filenameE_USER_WARNING);
        return 
false;
    }
    
// read file header
    
$meta unpack('vtype/Vfilesize/Vreserved/Voffset'fread($fh14));
    
// check for bitmap
    
if ($meta['type'] != 19778) {
        
trigger_error('imagecreatefrombmp: ' $filename ' is not a bitmap!'E_USER_WARNING);
        return 
false;
    }
    
// read image header
    
$meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant'fread($fh40));
    
// read 16-Bit header
    
if ($meta['bits'] == 16) {
        
$meta += unpack('VrMask/VgMask/VbMask'fread($fh12));
    }
    
// build general meta data
    
$meta['colors'] = pow(2$meta['bits']);
    if (
$meta['imagesize'] == 0) {
        
$meta['imagesize'] = $meta['filesize'] - $meta['offset'];
    }
    
$meta['bytes'] = $meta['bits'] / 8;
    
$meta['decal'] = - (* (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4)));
    if (
$meta['decal'] == 4) {
        
$meta['decal'] = 0;
    }
    
// read palette
    
$palette = array();
    if (
$meta['colors'] < 16777216 && $meta['colors'] != 65536) {
        
$palette unpack('V' $meta['colors'], fread($fh$meta['colors'] * 4));
    }
    
// create gd image
    
$im imagecreatetruecolor($meta['width'], $meta['height']);
    
$data fread($fh$meta['imagesize']);
    
$p 0;
    
$vide chr(0);
    
$y $meta['height'] - 1;
    while (
$y >= 0) {
        
$x 0;
        while (
$x $meta['width']) {
            switch (
$meta['bits']) {
                case 
24:
                    
$color unpack('V'substr($data$p3) . $vide);
                    break;
                case 
16:
                    
$color unpack('v'substr($data$p2));
                    
$color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
                    break;
                case 
8:
                    
$color unpack('n'$vide substr($data$p1));
                    
$color[1] = $palette$color[1] + ];
                    break;
                case 
4:
                    
$color unpack('n'$vide substr($datafloor($p), 1));
                    if (!
$color) {
                        break;
                    }
                    
$color[1] = ($p 2) % == $color[1] >> $color[1] & 0x0F;
                    
$color[1] = $palette$color[1] + ];
                    break;
                case 
1:
                    
$color unpack('n'$vide substr($datafloor($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] + ];
                    break;
                default:
                    
trigger_error('imagecreatefrombmp: ' $meta['bits'] . ' bits are not supported!'E_USER_WARNING);
                    return 
false;
            }
            
imagesetpixel($im$x$y$color[1]);
            
$x++;
            
$p += $meta['bytes'];
        }
        
$y--;
        
$p += $meta['decal'];
    }
    
fclose($fh);
    return 
$im;
}} 
Jetzt fehlt mir noch ein 32-Bit Bitmap zum Testen und der entsprechende Filter zum Einlesen.

EDIT:
Dieses eine 8-Bit Bitmap macht komischerweise Probleme:
http://www.maxrev.de/files/2006/10/amijdm_140.bmp

extrahierte Daten:
Zitat:
Array
(
[type] => 19778
[filesize] => 2206
[reserved] => 0
[offset] => 182
[headersize] => 40
[width] => 44
[height] => 46
[planes] => 1
[bits] => 8
[compression] => 0
[imagesize] => 2024
[xres] => 3780
[yres] => 3780
[ncolor] => 32
[important] => 32
[colors] => 256
[bytes] => 1
[decal] => 0
)
Muss wohl noch eine Sonderlösung her

EDIT2:
Ok, hab noch ein paar andere gefunden, die nicht gehen. Auch ein 32-Bit Bitmap dabei mit dem ich dann testen kann. Ich mache aber erst morgen weiter. Halte Euch auf dem Laufenden...
__________________
meine PHP Scripte

Geändert von hondatuner (17.04.2010 um 01:36 Uhr).
hondatuner ist offline   Mit Zitat antworten
Alt 17.04.2010, 05:09  
Erfahrener Benutzer
 
Registriert seit: 24.05.2008
Beiträge: 173
PHP-Kenntnisse:
Anfänger
Griffith sorgt für eine eindrucksvolle AtmosphäreGriffith sorgt für eine eindrucksvolle Atmosphäre
Standard

Seit wann gibt es Bitmaps mit 16 Bit Farbtiefe UND Palette?

Soweit ich weiß können Farbpaletten nur bei den Farbtiefen 1-, 4- und 8-Bit benutzt werden.

16-Bit benutzt eine Bitmaske, in denen die drei Farbkanäle über 2 Byte verteilt werden; aber niemals eine Farbpalette.
Bei 24- und 32-Bit wird jeder Farbkanal einzeln in einem Byte gespeichert; auch keine Farbpalette.
Griffith ist offline   Mit Zitat antworten
Alt 17.04.2010, 10:05  
Erfahrener Benutzer
 
Benutzerbild von lstegelitz
 
Registriert seit: 07.09.2009
Beiträge: 4.005
PHP-Kenntnisse:
Fortgeschritten
lstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nett
Standard

24 Bit und 32 Bit sind im Grunde identisch, der Alphakanal wird bei BMP's nicht genutzt.
PHP-Code:
                case 32:
                    
$color unpack('V'substr($data$p4) . $vide);
                    break; 
Was deinem Code noch fehlt, sind die Kompressionsalgothitmen (RLE4 bzw. RLE8 )

edit: 8 Bit Palette muss nicht zwangsläufig komplett gefüllt sein. 'biClrUsed' bzw 'biClrImportant' sollte darüber Aufschluss geben. 'biClrUsed' ist 32 bei deinem Beispiel.
__________________
Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

Geändert von lstegelitz (17.04.2010 um 10:56 Uhr).
lstegelitz ist offline   Mit Zitat antworten
Alt 17.04.2010, 13:59  
Benutzer
 
Registriert seit: 17.06.2009
Beiträge: 97
PHP-Kenntnisse:
Fortgeschritten
hondatuner befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von Griffith Beitrag anzeigen
Seit wann gibt es Bitmaps mit 16 Bit Farbtiefe UND Palette?
Zum dritten Mal: War eine falsche Schlussfolgerung meinerseits :P

Zitat:
Zitat von lstegelitz Beitrag anzeigen
24 Bit und 32 Bit sind im Grunde identisch, der Alphakanal wird bei BMP's nicht genutzt.
Danke werde den Code testen.

Zitat:
Was deinem Code noch fehlt, sind die Kompressionsalgothitmen (RLE4 bzw. RLE8 )
Gibt es Grafikprogramme mit denen ich solche Grafiken bauen kann bzw. waren das nicht die, die nur intern von Windows verwendet werden. Hatte da was beiläufig gelesen.

Zitat:
edit: 8 Bit Palette muss nicht zwangsläufig komplett gefüllt sein. 'biClrUsed' bzw 'biClrImportant' sollte darüber Aufschluss geben. 'biClrUsed' ist 32 bei deinem Beispiel.
Danke schaue ich gleich mal. Feedback kommt.


EDIT:
Also 32-Bit ist genauso wie 24-Bit. Der Alphakanal störte wohl bei der Berechnung der Farbe. Lässt man ihn hingegen weg stimmt alles:
Code:
				case 32:
				case 24:
					$color = unpack('V', substr($data, $p, 3) . $vide);
					break;
Muss ich den Alphakanal berücksichtigen? Weil bei Wikipedia steht folgendes:
Zitat:
Jeder Farbkanal ist 8 Bit pro Pixel groß; insgesamt ergeben sich 16.777.216 mögliche Farben (8 Bit sind ungenutzt). Einige Programme wie etwa Adobe Photoshop interpretieren die verbleibenden 8 Bits (0xFF000000) als Alphakanal mit 256 möglichen Transparenzstufen. Dies ist jedoch von der Spezifikation nicht vorgesehen.
Kann Photoshop also transparente 32-Bit Bitmaps erstellen?

EDIT2:
Ein paar 24-Bit Bitmaps haben im Header eine filesize gleich offset und die imagesize ist leer. Daher ein Bugfix mit filesize():
Code:
	// obtain imagesize
	if ($meta['imagesize'] < 1) {
		$meta['imagesize'] = $meta['filesize'] - $meta['offset'];
		if ($meta['imagesize'] < 1) {
			$meta['imagesize'] = @filesize($filename) - $meta['offset'];
			if ($meta['imagesize'] < 1) {
				trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING);
				return false;
			}
		}
	}
EDIT3:
Also bei 8-Bit und begrenzter Palette komme ich aktuell nicht weiter. Ich habe die Anzahl der Farben reduziert, sobald biClrUsed gesetzt ist:
Code:
	// calculate colors
	$meta['colors'] = $meta['ncolor'] ? $meta['ncolor'] : pow(2, $meta['bits']);
Auf die Art lese nun die korrekte Palettengröße aus:
Code:
	// read palette
	$palette = array();
	if ($meta['colors'] < 16777216 && $meta['bits'] != 16) {
		$palette = unpack('V' . $meta['colors'], fread($fh, $meta['colors'] * 4));
	}
Das Ergebnis bleibt aber schwarz. Ich habe mir mal hier die Farben ausgeben lassen:
Code:
				case 8:
					$color = unpack('n', $vide . substr($data, $p, 1));
					echo $color[1] . ':';
					$color[1] = $palette[ $color[1] + 1 ];
					echo $color[1] . ', ';
					break;
Ergebnis (Teilauszug):
Code:
26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 2:4278255873, 2:4278255873, 2:4278255873, 2:4278255873, 2:4278255873, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 2:4278255873, 6:4290209603, 17:4288105267, 17:4288105267, 2:4278255873, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 8:4279636996, 20:4282794244, 20:4282794244, 20:4282794244, 20:4282794244, 8:4279636996, 26:0, 26:0, 26:0, 26:0, 26:0, 2:4278255873, 2:4278255873, 2:4278255873, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 2:4278255873, 18:4292051795, 6:4290209603, 17:4288105267, 2:4278255873, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 2:4278255873, 14:4284635918, 9:4291540229, 16:4290160387, 16:4290160387, 16:4290160387, 24:4289305347, 24:4289305347, 14:4284635918, 2:4278255873, 26:0, 26:0, 2:4278255873, 23:4292987432, 9:4291540229, 9:4291540229, 2:4278255873, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 26:0, 2:4278255873, 6:4290209603, 6:4290209603, 19:4289156923, 2:4278255873
Ich vergleiche mal mit einem 8-Bit Bild das funktioniert. Moment...

EDIT4:
Die Palette sieht irgendwie falsch aus, wenn ich davon ausgehe, dass 16.777.215 den höchsten Wert darstellt:
Code:
Array
(
    [1] => 4294967294
    [2] => 4292598747
    [3] => 4278255873
    [4] => 4278190080
    [5] => 4293651435
    [6] => 4294967295
    [7] => 4290209603
    [8] => 4294963219
    [9] => 4279636996
    [10] => 4291540229
    [11] => 4294963014
    [12] => 4294632965
    [13] => 4294896179
    [14] => 4293580548
    [15] => 4284635918
    [16] => 4292199171
    [17] => 4290160387
    [18] => 4288105267
    [19] => 4292051795
    [20] => 4289156923
    [21] => 4282794244
    [22] => 4287727121
    [23] => 4292988421
    [24] => 4292987432
    [25] => 4289305347
    [26] => 4292199703
    [27] => 0
    [28] => 4278190080
    [29] => 4278190080
    [30] => 4278190080
    [31] => 4278190080
    [32] => 4278190080
)
EDIT5:
Ich denke mal hier liegt der Hund begraben:
Code:
    [xres] => 3780
    [yres] => 3780
D.h. biXPelsPerMeter und biYPelsPerMeter. Allerdings habe ich keine Ahnung wie ich die anwenden muss...

Oder gibt es wieder gar keine Palette ^^

EDIT6:
Bei einem 1-Bit Bild genau das gleiche Problem:
Code:
Array
(
    [type] => 19778
    [filesize] => 270254
    [reserved] => 0
    [offset] => 62
    [headersize] => 40
    [width] => 1238
    [height] => 1732
    [planes] => 1
    [bits] => 1
    [compression] => 0
    [imagesize] => 270192
    [xres] => 5905
    [yres] => 5905
    [ncolor] => 2
    [important] => 2
    [colors] => 2
    [bytes] => 0.125
    [decal] => 1.25
)
__________________
meine PHP Scripte

Geändert von hondatuner (17.04.2010 um 16:16 Uhr).
hondatuner ist offline   Mit Zitat antworten
Alt 18.04.2010, 12:15  
Erfahrener Benutzer
 
Benutzerbild von lstegelitz
 
Registriert seit: 07.09.2009
Beiträge: 4.005
PHP-Kenntnisse:
Fortgeschritten
lstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nettlstegelitz ist einfach richtig nett
Standard

Zitat:
EDIT5:
Ich denke mal hier liegt der Hund begraben:
Code:
    [xres] => 3780
    [yres] => 3780
D.h. biXPelsPerMeter und biYPelsPerMeter. Allerdings habe ich keine Ahnung wie ich die anwenden muss...
Die Angaben sind in "Pixel pro Meter". Für die handeslübliche Auflösung "Pixel pro Zoll" (DPI, dots per inch) rechnest du einfach um, z.B.:
3780 / 100 * 2.54 = ~96
5905 / 100 * 2.54 = ~150
(Ein inch sind ungefähr 2.54 cm)

Ich glaube eher, dein Hund liegt hier begraben:
Zitat:
PHP-Code:
    $meta['bytes'] = $meta['bits'] / 8;
    
$meta['decal'] = - (* (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4)));
    if (
$meta['decal'] == 4) {
        
$meta['decal'] = 0;
    } 
Ein Farbwert (egal ob per Index oder per RGB Wert angegeben) kann nicht kleiner als eine Byte sein, daher ist auch die Folgenberechnung des Paddings verkehrt.

"byte" ist 1 für 1,2,4,8 Bit Farbtiefe
"byte" ist 2 für 16 Bit Farbtiefe
"byte" ist 3 für 24 Bit Farbtiefe
"byte" ist 4 für 32 Bit Farbtiefe

"decal" ist 4 - ((width * "byte") % 4)


Die Datei sieht auch etwas seltsam aus:
Zitat:
Array
(
[type] => 19778
[filesize] => 270254
[reserved] => 0
[offset] => 62
[headersize] => 40
[width] => 1238
[height] => 1732
[planes] => 1
[bits] => 1
[compression] => 0
[imagesize] => 270192
[xres] => 5905
[yres] => 5905
[ncolor] => 2
[important] => 2
[colors] => 2
[bytes] => 0.125
[decal] => 1.25
)
Da compression == BI_RGB(0) ist, berechnet sich die Größe der Bilddaten.
padding: 2 byte (width % 4)
1240 * 1732 * 1 / 8 ( (width + padding) * height * bits / 8 ) = 268460

Da ensteht genau eine Spalte Differenz: 270192 - 268460 = 1732

Wie groß ist die Datei denn wirklich (physisch)? Bzw. was sagt ein anderes Bildbearbeitungsprogramm bezüglich Größe?
__________________
Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.
lstegelitz ist offline   Mit Zitat antworten
Alt 19.04.2010, 14:43  
Benutzer
 
Registriert seit: 17.06.2009
Beiträge: 97
PHP-Kenntnisse:
Fortgeschritten
hondatuner befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von lstegelitz Beitrag anzeigen
Ein Farbwert (egal ob per Index oder per RGB Wert angegeben) kann nicht kleiner als eine Byte sein, daher ist auch die Folgenberechnung des Paddings verkehrt.

"byte" ist 1 für 1,2,4,8 Bit Farbtiefe
"byte" ist 2 für 16 Bit Farbtiefe
"byte" ist 3 für 24 Bit Farbtiefe
"byte" ist 4 für 32 Bit Farbtiefe

"decal" ist 4 - ((width * "byte") % 4)
Ich habs so getestet:
PHP-Code:
    // set bytes
    
switch ($meta['bits']) {
        case 
32:
            
$meta['bytes'] = 4;
            break;
        case 
24:
            
$meta['bytes'] = 3;
            break;
        case 
16:
            
$meta['bytes'] = 2;
            
// read additional 16bit header
            
$meta += unpack('VrMask/VgMask/VbMask'fread($fh12));
            break;
        default:
            
$meta['bytes'] = 1;
    }
    
// set padding
    
$meta['decal'] = - (($meta['width'] * $meta['bytes']) % 4); 
Dann geht aber gar kein Bild mehr

Scheinbar muss es manchmal "leere" Rückgaben geben. Leer schein mir dann die Standardfarbe aus der Palette zu sein, die sich durch unpack('n', chr(0)) ergibt. Das gilt übrigens für 8, 4 und 1 Bit. Ich hatte nämlich erst versucht einen Error zu triggern, wenn $part leer ist:
PHP-Code:
                case 8:
                    if (!(
$part substr($data$p1))) {
                        
trigger_error($errorE_USER_WARNING);
                        return 
$im;
                    }
                    
$color unpack('n'$vide $part);
                    
$color[1] = $palette$color[1] + ];
                    break; 
Dabei lief er schon nach kurzer Zeit in den Fehler und lieferte nur noch wenige Zeilen von dem Bild aus.

Zitat:
Zitat von lstegelitz Beitrag anzeigen
Die Datei sieht auch etwas seltsam aus:

Da compression == BI_RGB(0) ist, berechnet sich die Größe der Bilddaten.
padding: 2 byte (width % 4)
1240 * 1732 * 1 / 8 ( (width + padding) * height * bits / 8 ) = 268460

Da ensteht genau eine Spalte Differenz: 270192 - 268460 = 1732

Wie groß ist die Datei denn wirklich (physisch)? Bzw. was sagt ein anderes Bildbearbeitungsprogramm bezüglich Größe?
Die physische Größe stimmt laut filesize() mit $meta['filesize'] überein. Laut Paint/Windows/Photoshop hat das Bild die folgenden Angaben:
1238x1732 Pixel, 270.254 Bytes, 150x150 Punkte pro Zoll

Hier der Link zu dem besagten Bild:
http://www.maxrev.de/files/2006/10/p...and_bild_1.bmp

Ein anderes 1-Bit Bild mit diesen Angaben geht übrigens problemlos:
PHP-Code:
Array
(
    [
type] => 19778
    
[filesize] => 139838
    
[reserved] => 0
    
[offset] => 62
    
[headersize] => 40
    
[width] => 1218
    
[height] => 896
    
[planes] => 1
    
[bits] => 1
    
[compression] => 0
    
[imagesize] => 139776
    
[xres] => 0
    
[yres] => 0
    
[ncolor] => 0
    
[important] => 0
    
[bytes] => 0.125
    
[decal] => 3.75
    
[colors] => 2

Daher glaube ich, dass es irgendwas mit der Palette zu tun haben muss.

EDIT:
Diese Formel habe ich gefunden (von hier: http://en.wikipedia.org/wiki/Windows...#Pixel_storage ):
Zitat:
Using info from the article, here's a good formula for bmp filesize in bytes (when bits-per-pixel < 16):
54 + 4*(num_colors) + 4*ceil(width * bits_per_pixel / 32.0)*height
Das habe ich getestet und es resultiert das richtige Ergebnis:
PHP-Code:
    $meta['calculated_filesize'] = 54 $meta['colors'] + ceil($meta['width'] * $meta['bits'] / 32) * $meta['height']; 
__________________
meine PHP Scripte

Geändert von hondatuner (19.04.2010 um 14:53 Uhr).
hondatuner ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Transparenz bei Bitmaps md5hash Off-Topic Diskussionen 1 25.06.2006 00:17

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
imagecreatefrombmp, php imagecreatefrombmp, php bitmap, \php\ 4-bit image, imagecreatefrombmp 16 bit, 16 bit bmp, php create image bmp, 16 bit farbpalette, php bitmap erstellen, imagecreatefrombmp php, 16bit bmp erstellen, imagecreatefrombmp in php, 16-bit image, php bild 16 bit, bmp 16 bit, 16bit farbpaletten adobe, 16bit bitmap, php bmp erzeugen, 16 bit bmp erzeugen, php imagecreatefrombmp 16bit

Alle Zeitangaben in WEZ +2. Es ist jetzt 22:28 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum