. */ require_once('SWF.php'); $s = new SWFextractImages(); $s->doExtractImages(file_get_contents($argv[1])); class SWFextractImages { private $swf; // SWF file parser private $jpegTables; public function doExtractImages($b) { $this->swf = new SWF($b); // Parse .swf file $this->jpegTables = ''; // Collect and process DefineBits, JPEGTables, DefineBitsJPEG... and DefineBitsLossless... tags foreach ($this->swf->tags as $tag) { switch ($tag['type']) { case 6: // DefineBits $this->defineBits($tag); break; case 8: // JPEGTables $this->jpegTables($tag); break; case 20: // DefineBitsLossless $this->defineBitsLossless($tag); break; case 21: // DefineBitsJPEG2 $this->defineBitsJPEG23($tag); break; case 36: // DefineBitsLossless2 $this->defineBitsLossless2($tag); break; case 35: // DefineBitsJPEG3 $this->defineBitsJPEG23($tag); break; case 90: // DefineBitsJPEG4 $this->defineBitsJPEG4($tag); break; } } } private function jpegTables($tag) { // Save 'JPEGData' $ret = $this->swf->parseTag($tag); $this->jpegTables = $ret['JPEGData']; } private function defineBits($tag) { $ret = $this->swf->parseTag($tag); $imageData = $ret['imageData']; if (strlen($this->jpegTables) > 0) { // Concatenate JPEGData and imageData $imageData = substr($this->jpegTables, 0, -2) . substr($imageData, 2); } file_put_contents(sprintf('images/img_%d.jpg', $ret['characterId']), $imageData); } private function defineBitsJPEG23($tag) { $ret = $this->swf->parseTag($tag); $imageData = $ret['imageData']; if (($extension = $this->guessExtension($imageData)) == null) { error_log(sprintf('DefineBitsJPEG2: Cannot determine image type, skipping...')); echo sprintf("[%s]\n", substr($imageData, 0, 8)); return; } file_put_contents(sprintf('images/img_%d.%s', $ret['characterId'], $extension), $imageData); } private function defineBitsJPEG4($tag) { // TODO } private function defineBitsLossless($tag) { $ret = $this->swf->parseTag($tag); $bitmapFormat = $ret['bitmapFormat']; $bitmapWidth = $ret['bitmapWidth']; $bitmapHeight = $ret['bitmapHeight']; $pixelData = $ret['pixelData']; $img = imageCreateTrueColor($bitmapWidth, $bitmapHeight); if ($bitmapFormat == 3) { $colorTable = $ret['colorTable']; // Construct the colormap $colors = array(); $i = 0; $len = strlen($colorTable); while ($i < $len) { $red = ord($colorTable[$i++]); $green = ord($colorTable[$i++]); $blue = ord($colorTable[$i++]); $colors[] = imageColorAllocate($img, $red, $green, $blue); } $bytesPerRow = $this->alignTo4bytes($bitmapWidth * 1); // 1 byte per sample // Construct the image for ($row = 0; $row < $bitmapHeight; $row++) { $off = $bytesPerRow * $row; for ($col = 0; $col < $bitmapWidth; $col++) { $idx = ord($pixelData[$off++]); imageSetPixel($img, $col, $row, $colors[$idx]); } } } else if ($bitmapFormat == 4) { $bytesPerRow = $this->alignTo4bytes($bitmapWidth * 2); // 2 bytes per sample // Construct the image for ($row = 0; $row < $bitmapHeight; $row++) { $off = $bytesPerRow * $row; for ($col = 0; $col < $bitmapWidth; $col++) { $lo = ord($pixelData[$off++]); $hi = ord($pixelData[$off++]); $rgb = $lo + $hi * 256; $red = ($rgb >> 10) & 0x1f; // 5 bits $green = ($rgb >> 5) & 0x1f; // 5 bits $blue = ($rgb) & 0x1f; // 5 bits $color = imageColorAllocate($img, $red, $green, $blue); imageSetPixel($img, $col, $row, $color); } } } else if ($bitmapFormat == 5) { $bytesPerRow = $this->alignTo4bytes($bitmapWidth * 4); // 4 bytes per sample // Construct the image for ($row = 0; $row < $bitmapHeight; $row++) { $off = $bytesPerRow * $row; for ($col = 0; $col < $bitmapWidth; $col++) { $off++; // Reserved $red = ord($pixelData[$off++]); $green = ord($pixelData[$off++]); $blue = ord($pixelData[$off++]); $color = imageColorAllocate($img, $red, $green, $blue); imageSetPixel($img, $col, $row, $color); } } } imagePNG($img, sprintf('images/img_%d.png', $ret['characterId'])); imageDestroy($img); } private function defineBitsLossless2($tag) { $ret = $this->swf->parseTag($tag); $bitmapFormat = $ret['bitmapFormat']; $bitmapWidth = $ret['bitmapWidth']; $bitmapHeight = $ret['bitmapHeight']; $pixelData = $ret['pixelData']; $img = imageCreateTrueColor($bitmapWidth, $bitmapHeight); imageAlphaBlending($img, false); imageSaveAlpha($img, true); if ($bitmapFormat == 3) { $colorTable = $ret['colorTable']; // Construct the colormap $colors = array(); $i = 0; $len = strlen($colorTable); while ($i < $len) { $red = ord($colorTable[$i++]); $green = ord($colorTable[$i++]); $blue = ord($colorTable[$i++]); $alpha = ord($colorTable[$i++]); $alpha = 127 - floor($alpha / 2); // Alpha correction to PHP values $colors[] = imageColorAllocateAlpha($img, $red, $green, $blue, $alpha); } $bytesPerRow = $this->alignTo4bytes($bitmapWidth * 1); // 1 byte per sample // Construct the image for ($row = 0; $row < $bitmapHeight; $row++) { $off = $bytesPerRow * $row; for ($col = 0; $col < $bitmapWidth; $col++) { $idx = ord($pixelData[$off++]); imageSetPixel($img, $col, $row, $colors[$idx]); } } } else if ($bitmapFormat == 5) { $bytesPerRow = $this->alignTo4bytes($bitmapWidth * 4); // 4 byte per sample // Construct the image for ($row = 0; $row < $bitmapHeight; $row++) { $off = $bytesPerRow * $row; for ($col = 0; $col < $bitmapWidth; $col++) { $alpha = ord($pixelData[$off++]); $red = ord($pixelData[$off++]); $green = ord($pixelData[$off++]); $blue = ord($pixelData[$off++]); $alpha = 127 - floor($alpha / 2); // Alpha correction to PHP values $color = imageColorAllocateAlpha($img, $red, $green, $blue, $alpha); imageSetPixel($img, $col, $row, $color); } } } imagePNG($img, sprintf('images/img_%d.png', $ret['characterId'])); imageDestroy($img); } private function alignTo4Bytes($num) { while (($num % 4) != 0) { $num++; } return $num; } private function guessExtension($imageData) { if (strlen($imageData) > 2 && strcmp(substr($imageData, 0, 2), "\xff\xd8") == 0) { return 'jpg'; } else if (strlen($imageData) > 2 && strcmp(substr($imageData, 0, 2), "\xff\xd9") == 0) { // Erroneous older header return 'jpg'; } else if (strlen($imageData) > 8 && strcmp(substr($imageData, 0, 8), "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") == 0) { return 'png'; } else if (strlen($imageData) > 6 && strcmp(substr($imageData, 0, 6), "\x47\x49\x46\x38\x39\x61") == 0) { return 'gif'; } else { return null; } } } ?>