2009-10-18 14 views
5

Ho cercato di capire un modo per convertire i file bitmap in un JPEG utilizzando la libreria GD in PHP.Converti file bitmap in JPEG utilizzando la libreria GD in PHP

Ho provato numerose implementazioni ma nulla sembra funzionare. Ho cercato di dire al mio cliente che non dovrebbero usare i file Bitmap ma insiste e, francamente, non comprende abbastanza i computer per convertirli in JPG da solo.

Non riesco a utilizzare ImageMagick su questo server e ho bisogno di una soluzione GD pura. Grazie in anticipo per qualsiasi aiuto.

EDIT:

Le immagini bitmap che vengono utilizzati sono 16 bit e che è dove si verifica il problema.

Ho questa funzione che ho a lavorare .... un pò:

function ImageCreateFromBMP($filename) { 
    if (! $f1 = fopen($filename,"rb")) return FALSE; 

    $FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14)); 
    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($f1,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 && $BMP['colors'] != 65536) { 
     $PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4)); 
    } 

    $IMG = fread($f1,$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']) { 
      if ($BMP['bits_per_pixel'] == 24) 
       $COLOR = unpack("V",substr($IMG,$P,3).$VIDE); 
      elseif ($BMP['bits_per_pixel'] == 16) { 
       $COLOR = unpack("v",substr($IMG,$P,2)); 
       $blue = ($COLOR[1] & 0x001f) << 3; 
       $green = ($COLOR[1] & 0x07e0) >> 3; 
       $red = ($COLOR[1] & 0xf800) >> 8; 
       $COLOR[1] = $red * 65536 + $green * 256 + $blue; 
      } 
      elseif ($BMP['bits_per_pixel'] == 8) { 
       $COLOR = unpack("n",$VIDE.substr($IMG,$P,1)); 
       $COLOR[1] = $PALETTE[$COLOR[1]+1]; 
      } 
      elseif ($BMP['bits_per_pixel'] == 4) { 
       $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1)); 
       if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F); 
       $COLOR[1] = $PALETTE[$COLOR[1]+1]; 
      } 
      elseif ($BMP['bits_per_pixel'] == 1) { 
       $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1)); 
       if  (($P*8)%8 == 0) $COLOR[1] = $COLOR[1]  >>7; 
       elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6; 
       elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5; 
       elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4; 
       elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3; 
       elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2; 
       elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1; 
       elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1); 
       $COLOR[1] = $PALETTE[$COLOR[1]+1]; 
      } 
      else 
       return FALSE; 

      imagesetpixel($res,$X,$Y,$COLOR[1]); 

      $X++; 
      $P += $BMP['bytes_per_pixel']; 
     } 
     $Y--; 
     $P+=$BMP['decal']; 
    } 

    fclose($f1); 
    return $res; 
} 

L'immagine risultante è questo:

Uploaded Image

Se guardate l'immagine a sinistra lato si può vedere che l'immagine risultante non è allineata correttamente. Il piccolo frammento si trova sul lato destro. Dove sta andando il codice sbagliato? Il problema si sta verificando nel 16-bit else-if.

Grazie ancora per tutto l'aiuto.

+0

Ha dato un'occhiata al codice, sembra corretto. Sei sicuro che il formato BMP sia come previsto (54 byte, nessun dato sulla tavolozza, i seguenti dati immagine)? Poiché si tratta di una variante BMP esotica, potrebbero esserci ulteriori/meno dati nell'intestazione che portano a questo errore di "spostamento". – schnaader

+0

Devo essere sincero, non sono sicuro di cosa stia succedendo con l'immagine. Se ci fosse un modo per mandare una e-mail a una delle tue foto in modo da poterle dare un'occhiata ... Sono più interessato che mai a quello che sta succedendo con questi file di immagine. Una mail a cui posso essere contattato è dphoebus at g mail dot com e risponderò con una delle immagini. –

risposta

10

Usare questa funzione:

http://www.programmierer-forum.de/function-imagecreatefrombmp-welche-variante-laeuft-t143137.htm

Supporta diversi bitrate come a 16 e 32 bit. Inoltre contiene alcune correzioni ai bug relativi a file mancanti, tavolozze dei colori negative, output di errore, intestazione maschera aggiuntiva a 16 bit (questo era il problema principale su 16 bit) e tavolozza dei colori ridotta (biClrUsed).

Spero che vi piaccia;)

Aggiornamento nel 2015: Questa funzione è ora parte di DOMPDF ed è stato portato alla perfezione. Ora copre compressi a 4 e 8 bit, ignora le intestazioni non importanti e supporta anche la speciale maschera 565 a 16 bit.

+0

Nuovo URL: https://github.com/dompdf/dompdf/blob/master/src/Helpers.php#L555 – Tominator

0

E la funzione imagejpeg?

bool imagejpeg (resource $image [, string $filename [, int $quality ]] )

imagejpeg() creates a JPEG file from the given image .

Per contribuire a supportare il formato BMP in GD, uno sguardo here, per esempio.

MODIFICA: non supporta immagini a 16 bit che sono corrette in quanto la specifica bitmap originale non la supporta. Nel tuo caso, ti preghiamo di scoprire quale pattern di bit è usato per codificare il valore del colore. Presumo è 5 bit per R e B, 6 bit per G e l'ordine è BGR in questa soluzione (inserire nel codice ho collegato sopra):

else if ($bits == 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"; 
} 

noti che non ho la prova questo codice (in particolare, non sono sicuro di tale ridimensionamento a 0..255) e funzionerà solo se è stato usato il pattern 5-6-5 bit (beh, funzionerà anche con gli altri, ma i colori saranno errati).

+0

Grazie per una rapida risposta, ma continuo a incontrare lo stesso problema. I file bitmap utilizzati dal mio client sono file bitmap a 16 bit. OGNI implementazione che ho trovato (incluso quella che hai mostrato) rappresenta bitmap a 24 bit, 8 bit, 4 bit e 1 bit. –

+0

Grazie ancora. Ho provato questa soluzione. Il file risultante che è stato restituito era un'immagine nera solida con linee verdi orizzontali distanziate in modo uguale per l'intera lunghezza dell'immagine. –

0

Mentre GD non supporta nativamente BMP, un po 'grande di googling offre invece una fewuserlandimplementations di una funzione imagecreatefrombmp().

Non li ho provati, ma sono sicuro che almeno uno di loro funzionerà per voi.

+0

Grazie ancora. Li ho provati tutti. Di nuovo quando eseguo dei test, scopro che i bitmap che vengono inviati sono file a 16 bit. Le immagini a 16 bit non sono prese in considerazione in nessuna di queste implementazioni. –

0

Fuori della parte superiore della mia testa:

function convert_to_jpeg($input_path, $output_path) 
{ 
    $image = imagecreatefromstring(file_get_contents($input_path)); 
    imagejpeg($image, $output_path); 
    imagedestroy($image); 
} 

Ci vorrà qualsiasi GD formato in grado di gestire in ingresso e in uscita un file JPEG. Non so quale versione di GD state usando, ma il mio handle .bmp perfettamente e così pure la versione che abbiamo usato nella precedente azienda per cui lavoravo. (su Mac OS X 10.6 e CentOS 5 rispettivamente)

modifica: dimenticato imagedestroy! Ahia!

+0

Speriamo che funzioni anche per i file BMP a 16 bit ... sarebbe la soluzione più rapida ed elegante. – schnaader

+0

Grazie per il vostro aiuto. Ho fatto un tentativo e ho ottenuto questo errore: imagecreatefromstring() [function.imagecreatefromstring]: I dati non sono in un formato riconosciuto. Ciò è probabilmente dovuto alle bitmap darn 16 bit utilizzate dal mio client. –

+0

Non credo di essermi mai imbattuto in un'immagine a 16 bit, ma sembra funzionare bene per 24 bit e persino immagini con codifica RLE. – Kris