. */ require_once('SWF.php'); $s = new SWFextractShapes(); $pdf = $s->doExtractShapes(file_get_contents($argv[1])); file_put_contents('output.pdf', $pdf); class SWFextractShapes { public function doExtractShapes($b) { $swf = new SWF($b); // Parse .swf file $shapes = array(); // Collect and parse DefineShape... tags foreach ($swf->tags as $tag) { $tagType = $tag['type']; if ($tagType == 2 || $tagType == 22 || $tagType == 32 || $tagType == 83) { $shapes[] = $swf->parseTag($tag); } } // Construct and return the PDF buffer return $this->constructPDF($shapes); } private function constructPDF($shapes) { $numPages = count($shapes); // Place one shape per page $objects = array(); // To hold the PDF objects $objectNumber = 1; // Collect object numbers $catalog = $objectNumber++; $info = $objectNumber++; $pages = $objectNumber++; $resources = $objectNumber++; $helveticaObjectNumber = $objectNumber++; $page0 = $objectNumber; $objectNumber += $numPages; $contents0 = $objectNumber; $objectNumber += $numPages; // Catalog object $sb = sprintf("<>", $pages); $objects[] = array('num' => $catalog, 'data' => $sb); // Info object $sb = "<>"; $objects[] = array('num' => $info, 'data' => $sb); // Resources object $sb = sprintf("<>>>", $helveticaObjectNumber); $objects[] = array('num' => $resources, 'data' => $sb); // Helvetica font object $sb = "<>"; $objects[] = array('num' => $helveticaObjectNumber, 'data' => $sb); // Pages object $sb = sprintf("<>", $this->dumpPageReferences($page0, $numPages), $numPages); $objects[] = array('num' => $pages, 'data' => $sb); for ($i = 0; $i < $numPages; $i++) { // Page object (for i-th page) $sb = sprintf("<>", $pages, $resources, $contents0 + $i); $objects[] = array('num' => $page0 + $i, 'data' => $sb); // Contents object (for i-th page) $stream = self::constructContents($i, $shapes[$i]); $sb = sprintf("<>\nstream\n%s\nendstream", strlen($stream), $stream); $objects[] = array('num' => $contents0 + $i, 'data' => $sb); } // Create the PDF $pdf = ''; // Dump the prologue $pdf .= "%PDF-1.7\n"; $pdf .= "%\342\342\342\342\n"; // Some binary data // Dump the objects for ($num = 0; $num < count($objects); $num++) { $objects[$num]['offset'] = strlen($pdf); $pdf .= sprintf("%d 0 obj\n%s\nendobj\n", $objects[$num]['num'], $objects[$num]['data']); } // Dump the xref $startXref = strlen($pdf); $pdf .= "xref\n"; $pdf .= sprintf("%d %d\n", 0, count($objects) + 1); $pdf .= sprintf("0000000000 65535 f \n"); for ($num = 0; $num < count($objects); $num++) { if (($object = $this->locateObject($objects, $num + 1)) !== null) { $pdf .= sprintf("%010d %05d n \n", $object['offset'], 0); } } // Dump the trailer $pdf .= "trailer\n"; $id = md5(sprintf('%s', microtime())); // Something 'random' here $pdf .= sprintf("<]>>\n", count($objects) + 1, $catalog, $info, $id, $id); // Dump the epilogue $pdf .= "startxref\n"; $pdf .= sprintf("%d\n", $startXref); $pdf .= "%%EOF\n"; return $pdf; } private function constructContents($i, $shape) { $sb = ''; $shapeBounds = $shape['shapeBounds']; $xmin = $shapeBounds['xmin']; $xmax = $shapeBounds['xmax']; $ymin = $shapeBounds['ymin']; $ymax = $shapeBounds['ymax']; $shapeWidth = $xmax - $xmin; $shapeHeight = $ymax - $ymin; $PAGE_WIDTH = 595; // A4 width in points $PAGE_HEIGHT = 842; // A4 height in points $MARGIN = 72; // Margin in points (1 inch) // Scale to fix $scaleX = ($PAGE_WIDTH - 2 * $MARGIN) / $shapeWidth; $scaleY = ($PAGE_HEIGHT - 2 * $MARGIN) / $shapeHeight; $scale = $scaleX < $scaleY ? $scaleX : $scaleY; $sb .= "q\n"; // Save state $sb .= sprintf("%.5f %.5f %.5f %.5f %.5f %.5f cm\n", // Establish translation and scaling $scale, 0.0, 0.0, -$scale, ($PAGE_WIDTH - $scale * $shapeWidth) / 2 - $xmin * $scale, $PAGE_HEIGHT - ($PAGE_HEIGHT - $scale * $shapeHeight) / 2 + $ymin * $scale); $x = 0; $y = 0; $shapeRecords = $shape['shapes']['shapeRecords']; foreach ($shapeRecords as $shapeRecord) { $type = $shapeRecord['type']; if ($type == 'EndShapeRecord') { ; // Do nothing } else if ($type == 'StyleChangeRecord') { if ($shapeRecord['stateMoveTo'] != 0) { $deltaX = $shapeRecord['moveDeltaX']; $deltaY = $shapeRecord['moveDeltaY']; $sb .= sprintf("%d %d m\n", $deltaX, $deltaY); $x = $deltaX; $y = $deltaY; } } else if ($type == 'StraightEdgeRecord') { $deltaX = $deltaY = 0; $generalLineFlag = $shapeRecord['generalLineFlag']; if ($generalLineFlag == 0) { $vertLineFlag = $shapeRecord['vertLineFlag']; } if ($generalLineFlag == 1 || $vertLineFlag == 0) { $deltaX = $shapeRecord['deltaX']; } if ($generalLineFlag == 1 || $vertLineFlag == 1) { $deltaY = $shapeRecord['deltaY']; } $sb .= sprintf("%d %d l\n", $x + $deltaX, $y + $deltaY); $x += $deltaX; $y += $deltaY; } else if ($type == 'CurvedEdgeRecord') { $controlDeltaX = $shapeRecord['controlDeltaX']; $controlDeltaY = $shapeRecord['controlDeltaY']; $anchorDeltaX = $shapeRecord['anchorDeltaX']; $anchorDeltaY = $shapeRecord['anchorDeltaY']; // Convert quadratic Bezier to cubic Bezier $x1 = $x + $controlDeltaX * 2 / 3; $y1 = $y + $controlDeltaY * 2 / 3; $x2 = $x + $controlDeltaX + $anchorDeltaX * 1 / 3; $y2 = $y + $controlDeltaY + $anchorDeltaY * 1 / 3; $x3 = $x + $controlDeltaX + $anchorDeltaX; $y3 = $y + $controlDeltaY + $anchorDeltaY; $sb .= sprintf("%.5f %.5f %.5f %.5f %.5f %.5f c\n", $x1, $y1, $x2, $y2, $x3, $y3, $controlDeltaX, $controlDeltaY, $anchorDeltaX, $anchorDeltaY); $x += $controlDeltaX + $anchorDeltaX; $y += $controlDeltaY + $anchorDeltaY; } } $sb .= "s\n"; // Close and stroke the path $sb .= "Q\n"; // Restore state $sb .= "BT\n"; // Begin text object $sb .= sprintf("/F0 12.0 Tf\n"); // Helvetica font at 12pt $sb .= sprintf("72 72 Td\n"); // Move to lower left corner $sb .= sprintf("(ShapeID: %d)Tj\n", $shape['shapeId']); // Display the shape ID $sb .= "ET\n"; // End text object return gzcompress($sb); // Compress and return } private function locateObject($objects, $num) { foreach ($objects as $object) { if ($object['num'] === $num) { return $object; } } throw new Exception(sprintf('Cannot locate object [%d]', $num)); } private function dumpPageReferences($page0, $numPages) { $sb = ''; for ($i = 0; $i < $numPages; $i++) { $sb .= sprintf(' %d 0 R', $page0 + $i); } return substr($sb, 1); // Remove first space } } ?>