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']) ? 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 - ($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_line0$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 - ($decal 4);

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

 $palette = array();

 if($colors 16777216)
 {
  $palette unpack('V'.$colorsfread($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$p4));
    break;

    case 24:
     $color unpack('V'substr($img$p3).$vide);
    break;

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

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

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

    case 1:
     $color unpack('n'$vide.substr($imgfloor($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)