Projektowanie stron WWW od podszewki

Artykuły na każdy temat

[PHP] Masowa konwersja windowsowskich plików BMP na inny format

Dodano 03.09.2013r. o 21:39
Czy można nazwać to inaczej niż tak, że skrypt jest wynikiem braku konsekwencji działania i zachowywania procedur? A może jest właśnie odwrotnie gdzie konsekwencja wynika z prostego lenistwa? Właściwie to nieistotne, bo liczy się tylko efekt finalny i zrealizowanie planu, który już od dawna czekał w szufladzie. Pamiętam jak każdy kolejny pulpit zapisywałem/przerzucałem do folderu oznaczonego coraz to większą liczbą. Pomiędzy tymi folderami znalazło się masę screenshotów, które były w formacie bitmap kochanego Microsoftu i ważyły swoje. Niestety GD nie rozkminia tego formatu co mnie szczególnie akurat nie dziwi. Teraz zastanawiam się jak dodać opcje tworzenia nowych plików PNG z menu pod prawym klawiszem myszki. Może ktoś z Was zna prostą metodę jak to zrobić? To ułatwiłoby stanowczo sprawę. Co do skryptu to tłumaczenia wiele nie ma. Najistotniejsze elementy zostały oznaczone. Analogicznych funkcji po sieci jest kilka. Jeżeli kogoś interesuję struktura plików BMP to polecam tą lekturę.
Kod:
<?php
$config['path']['new'] = './new/';

$list['old'] = glob('./old/*.bmp');
$list['new'] = glob($config['path']['new'].'*.png');

if(!empty($list['old']))
{
 header('Content-Type: text/plain; charset=windows-1250');
 $counter = (empty($list['new']) ? 1 : count($list['new']) + 1);

 foreach($list['old'] as $object)
 {
  $handle = convert_bmp2gd($object);

  if($handle)
  {
   $info = stream_get_meta_data($handle);
   $img = imagecreatefromgd($info['uri']);

   if($img)
   {
    fclose($handle);
    echo '[';

    if(imagepng($img, $config['path']['new'].$counter.'.png', 9) && unlink($object))
    {
     ++$counter;
     echo 't';
    }
    else
    {
     echo 'f';
    }

    echo '] '.$object."\n";
   }
  }
 }

 // Or option number two

 foreach($list['old'] as $object)
 {
  $img = convert_bmp2gd_v2($object);

  if($img)
  {
   echo '[';

   if(imagepng($img, $config['path']['new'].$counter.'.png', 9) && unlink($object))
   {
    ++$counter;
    echo 't';
   }
   else
   {
    echo 'f';
   }

   echo '] '.$object."\n";
  }

  break;
 }
}

function convert_bmp2gd($source)
{
 $handle['source'] = fopen($source, 'rb');
 $handle['temporary'] = tmpfile();

 if(!$handle['source'] || !$handle['temporary'])
 {
  return false;
 }

 // Grab necessary information
 $header = unpack('vtype/Vsize/v2reserved/Voffset', fread($handle['source'], 14));
 $info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant', fread($handle['source'], 40));
 extract($info);
 extract($header);

 // Check the file header
 if($type != 0x4D42)
 {
  return false;
 }

 // Set the pallete
 $palette_size = $offset - 54;
 $ncolor = $palette_size / 4;
 // True color or 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);
 }

 $gd_header .= "\xFF\xFF\xFF\xFF";
 fwrite($handle['temporary'], $gd_header);

 if($palette_size)
 {
  $palette = fread($handle['source'], $palette_size);

  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($handle['temporary'], $gd_palette);
 }

 $scan_line_size = ($bits * $width + 7) >> 3;
 $scan_line_align = ($scan_line_size & 0x03 ? 4 - ($scan_line_size & 0x03) : 0);

 for($h = 0, $i = $height - 1; $h < $height; ++$h, --$i)
 {
  fseek($handle['source'], ($scan_line_size + $scan_line_align) * $i + $offset);
  $scan_line = fread($handle['source'], $scan_line_size);

  if($bits == 8)
  {
   $gd_scan_line = $scan_line;
  }
  else
  {
   $gd_scan_line = '';
   $j = 0;

   if($bits == 24)
   {
    while($j < $scan_line_size)
    {
     $b = $scan_line[$j++];
     $g = $scan_line[$j++];
     $r = $scan_line[$j++];
     $gd_scan_line .= "\x00$r$g$b";
    }
   }
   else
   {
    if($bits == 4)
    {
     while($j < $scan_line_size)
     {
      $byte = ord($scan_line[$j++]);
      $p1 = chr($byte >> 4);
      $p2 = chr($byte & 0x0F);
      $gd_scan_line .= "$p1$p2";
     }
    }
    else if($bits == 1)
    {
     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);
   }
  }

  fwrite($handle['temporary'], $gd_scan_line);
 }

 fclose($handle['source']);

 return $handle['temporary'];
}

function convert_bmp2gd_v2($source)
{
 $handle['source'] = fopen($source, 'rb');

 if(!$handle['source'])
 {
  return false;
 }

 // Grab necessary information
 $header = unpack('vtype/Vsize/v2reserved/Voffset', fread($handle['source'], 14));
 $info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant', fread($handle['source'], 40));
 extract($info);
 extract($header);

 // Check the file header
 if($type != 19778)
 {
  return false;
 }

 $resource = imagecreatetruecolor($width, $height);

 if(!$resource)
 {
  return false;
 }

 $colors = pow(2, $bits);

 if($imagesize == 0)
 {
  $imagesize = $size - $offset;
 }

 $bytes_per_pixel = $bits / 8;
 $decal = $width * $bytes_per_pixel / 4;
 $decal -= floor($width * $bytes_per_pixel / 4);
 $decal = 4 - ($decal * 4);

 if($decal == 4)
 {
  $decal = 0;
 }

 $palette = array();

 if($colors < 16777216)
 {
  $palette = unpack('V'.$colors, fread($handle['source'], $colors * 4));
 }

 $img = fread($handle['source'], $imagesize);
 $vide = chr(0);
 $p = 0;
 $y = $height - 1;

 while($y >= 0)
 {
  $x = 0;

  while($x < $width)
  {
   switch($bits)
   {
    case 32:
     $color = unpack('V', substr($img, $p, 4));
    break;

    case 24:
     $color = unpack('V', substr($img, $p, 3).$vide);
    break;

    case 16:
     $color = unpack('n', substr($img, $p, 2));
     $color[1] = $palette[$color[1] + 1];
    break;

    case 8:
     $color = unpack('n', $vide.substr($img, $p, 1));
     $color[1] = $palette[$color[1] + 1];
    break;

    case 4:
     $color = unpack('n', $vide.substr($img, floor($p), 1));
     $color[1] = $palette[(($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F) + 1];
    break;

    case 1:
     $color = unpack('n', $vide.substr($img, floor($p), 1));

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

   imagesetpixel($resource, $x, $y, $color[1]);
   $p += $bytes_per_pixel;
   ++$x;
  }

  $p += $decal;
  --$y;
 }

 fclose($handle['source']);

 return $resource;
}
?>
Druga metoda (funkcja) ma to do siebie, że teoretycznie powinna być szybsza, bo pomijany jest krok zapisu do pliku. Przy małych ilościach plików pewnie jest to nieistotne natomiast przy dużej ilości plików pewnie jest bardzo istotne. Kodowanie wysyłane w nagłówku jest umyśle, ze względu na to, że nazwy plików odczytywane były na Windows XP. Nie mam bladego pojęcia jak to wygląda na Windows 7 czy innych wersjach/systemach. Oczywiście można konwertować na inny format niż ukochany PNG. Kwestia zmienienia nazwy funkcji i ustalenia odpowiedniego quality. Dokumentacja Twoim przyjacielem Smile

Komentarze

Brak komentarzy

Dodaj komentarz

Zostaw komentarz jeżeli możesz! Nie bądź przysłowiowym botem! Nie bądź obojętny! Ciebie to nic nie kosztuje, a mi sprawi uśmiech na twarzy.
Zezwolono używać: BBCode
Zabroniono używać:
znaczników HTML

(Wymagany)

(Wymagany, niepublikowany)

(Nie wymagana)

Token:

Obrazek dla bota

(Przepisz tylko cyfry!)

(Wymagana)