2009-10-18 12 views
5

J'ai essayé de trouver un moyen de convertir des fichiers bitmap en JPEG en utilisant la bibliothèque GD en PHP.Convertir des fichiers bitmap en JPEG en utilisant la bibliothèque GD en PHP

J'ai essayé de nombreuses implémentations mais rien ne semble fonctionner. J'ai essayé de dire à mon client qu'il ne devrait pas utiliser les fichiers Bitmap mais il insiste et ne comprend pas assez les ordinateurs pour les convertir en JPG.

Je ne peux pas utiliser ImageMagick sur ce serveur et j'ai besoin d'une solution GD pure. Merci d'avance pour toute aide.

EDIT:

Les images bitmap qui sont utilisés sont de 16 bits et qui est l'endroit où le problème se produit.

J'ai cette fonction que je travaille .... un peu:

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'image résultante est la suivante:

Uploaded Image

Si vous regardez l'image sur la main gauche côté, vous pouvez voir que l'image résultante n'est pas correctement alignée. Le petit ruban appartient sur le côté droit. Où est le code qui va mal? Le problème se produit dans le 16-bit else-if.

Merci encore pour toute l'aide.

+0

J'ai regardé votre code, semble correct. Êtes-vous sûr que le format BMP est comme prévu (54 octets, pas de données de palette, suivi de données d'image)? Comme il s'agit d'une variante BMP exotique, il se peut qu'il y ait des données supplémentaires/inférieures dans l'en-tête qui conduisent à cette erreur de "décalage". – schnaader

+0

Je dois être honnête, je ne suis pas vraiment sûr de ce qui se passe avec l'image. S'il y avait un moyen de vous envoyer une des images par e-mail pour que vous puissiez y jeter un coup d'œil ... Je m'intéresse plus que jamais à ce qui se passe avec ces fichiers image. Un email que je peux être contacté est dphoebus à g mail dot com et je vais répondre avec l'une des images. –

Répondre

10

Utilisez cette fonction:

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

Il prend en charge plusieurs bitrates comme 16- et 32 ​​bits. De plus, il contient des corrections de bogues concernant la taille de fichier manquante, les palettes de couleurs négatives, les sorties d'erreur, l'en-tête de masque supplémentaire de 16 bits (problème principal sur 16 bits) et la palette de couleurs réduite (biClrUsed).

espère que vous aimez;)

Mise à jour en 2015: Cette fonction fait maintenant partie de DOMPDF et a été portée à la perfection. Maintenant, il couvre les 4 et 8 bits compressés, ignore les en-têtes sans importance et supporte aussi le masque spécial 565 16 bits.

+0

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

0

Qu'en est-il de la fonction imagejpeg?

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

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

Pour vous aider à supporter le format BMP dans GD, un coup d'oeil here, par exemple.

EDIT: Cela ne prend pas en charge les images 16 bits, ce qui est correct car la spécification de bitmap d'origine ne le prend pas en charge. Dans votre cas, déterminez quel modèle de bit est utilisé pour coder la valeur de couleur. Je suppose qu'il est 5 bits pour R et B, 6 bits pour G et l'ordre est BGR dans cette solution (s'il vous plaît insérer dans le code I lien ci-dessus):

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"; 
} 

Notez que je n'ai pas testé ce code (spécifiquement, je ne suis pas sûr de cette mise à l'échelle à 0..255) et cela ne fonctionnera que si un motif de 5-6-5 bits a été utilisé (eh bien, cela fonctionnera aussi avec d'autres, mais les couleurs seront fausses).

+0

Merci pour une réponse rapide mais je continue à courir dans le même problème. Les fichiers bitmap que mon client utilise sont des fichiers bitmap 16 bits. TOUTES les implémentations que j'ai trouvées (y compris celle que vous avez montrée) prennent en compte les bitmaps 24 bits, 8 bits, 4 bits et 1 bit. –

+0

Merci encore. J'ai essayé cette solution. Le fichier résultant qui a été retourné était une image noire pleine avec des lignes vertes horizontales espacées également sur toute la longueur de l'image. –

0

Alors que GD ne prend pas en charge BMP de manière native, un peu de recherche Google fournit une fewuserlandimplementations d'une fonction imagecreatefrombmp().

Je ne les ai pas essayés, mais je suis sûr qu'au moins l'un d'eux travaillera pour vous.

+0

Merci encore. Je les ai tous essayés. Encore une fois, lorsque je fais des tests, je découvre que les bitmaps qui sont soumis sont des fichiers de 16 bits. Les images 16 bits ne sont prises en compte dans aucune de ces implémentations. –

0

Du haut de ma tête:

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

Ça va prendre toute GD peut traiter comme entrée de format, et la sortie d'un fichier jpeg. Je ne sais pas quelle version de GD vous utilisez, mais la mienne gère parfaitement .bmp, tout comme la version que nous avons utilisée pour la société précédente pour laquelle j'ai travaillé. (sur Mac OS X 10.6 et CentOS 5 respectivement)

éditer: oublié imagedestroy! Aie!

+0

Espérons que cela fonctionne pour les fichiers BMP 16 bits, aussi ... serait la solution la plus rapide et la plus élégante. – schnaader

+0

Merci pour votre aide. J'ai essayé et j'ai eu cette erreur: imagecreatefromstring() [fonction.imagecreatefromstring]: Les données ne sont pas dans un format reconnu. Ceci est probablement dû aux images bitmap 16 bits que mon client utilise. –

+0

Je ne pense pas avoir jamais rencontré une image en 16 bits, mais cela semble fonctionner correctement pour les images 24 bits, et même RLE. – Kris