222 lines
7 KiB
PHP
222 lines
7 KiB
PHP
<?php
|
|
|
|
require_once __DIR__ . "/vendor/autoload.php";
|
|
|
|
function outputFrame($frame, $endFrame, $frameDurationMs) {
|
|
foreach ($frame[2]->commands as $path) {
|
|
/** @var \swf2ass\DrawPath $path */
|
|
$line = new \swf2ass\ass\ASSLine();
|
|
$line->objectId = 0;
|
|
$line->layer = [$frame[0]];
|
|
$line->start = $frame[1];
|
|
$line->end = $endFrame;
|
|
$line->style = "f";
|
|
$line->name = $frame[3];
|
|
$shape = $path->commands;
|
|
|
|
$line->tags = [
|
|
new \swf2ass\ass\borderTag(new \swf2ass\Vector2(0, 0)),
|
|
new \swf2ass\ass\shadowTag(0),
|
|
\swf2ass\ass\fillColorTag::fromStyleRecord($path->style)
|
|
];
|
|
/*if($shape->getRecords()[0] instanceof \swf2ass\MoveRecord){
|
|
$shape = (new \swf2ass\MatrixTransform(null, null, $shape->getRecords()[0]->to->multiply(-1)))->applyToShape($shape);
|
|
}*/
|
|
$line->tags[] = new \swf2ass\ass\positionTag(new \swf2ass\Vector2(0, 0), new \swf2ass\Vector2(0, 0), 1, 1);
|
|
$line->tags[] = new \swf2ass\ass\drawTag($shape, 1);
|
|
echo $line->encode($frameDurationMs) . PHP_EOL;
|
|
}
|
|
}
|
|
|
|
$fps = 30;//30000 / 1001;//30;
|
|
$colorN = 2;
|
|
$pframeColorDistance = 16;
|
|
|
|
if (is_dir($argv[1])) {
|
|
$frames = glob($argv[1] . "/*.png");
|
|
} else {
|
|
$frames = [$argv[1]];
|
|
}
|
|
sort($frames);
|
|
|
|
/** @var \swf2ass\Color[][] $frameBuffer */
|
|
$frameBuffer = null;
|
|
$quantizedFrameBuffer = $frameBuffer;
|
|
|
|
$dynamicPalette = false;
|
|
$palette = [];
|
|
for ($i = 0; $i < $colorN; ++$i) {
|
|
$palette[] = new \swf2ass\Color((int)round($i * (255 / ($colorN - 1))), (int)round($i * (255 / ($colorN - 1))), (int)round($i * (255 / ($colorN - 1))));
|
|
}
|
|
|
|
|
|
$frameNumber = 1;
|
|
$endFrame = 6522;
|
|
$lastFrameNumber = null;
|
|
|
|
$currentFrames = [];
|
|
|
|
/**
|
|
* @param \swf2ass\Color $color
|
|
* @param \swf2ass\Color[] $palette
|
|
*
|
|
* @return \swf2ass\Color
|
|
*/
|
|
function getClosestColor(\swf2ass\Color $color, array $palette) {
|
|
$minColor = null;
|
|
$minDistance = null;
|
|
foreach ($palette as $c2) {
|
|
if (($d = $c2->distance($color)) < $minDistance or $minColor === null) {
|
|
$minColor = $c2;
|
|
$minDistance = $d;
|
|
}
|
|
}
|
|
return $minColor;
|
|
}
|
|
|
|
foreach ($frames as $frame) {
|
|
if (count($frames) === 1 or preg_match("/([0-9]+)\\.png/", $frame, $matches) > 0) {
|
|
if (count($frames) === 1) {
|
|
$frameNumber = 0;
|
|
} else {
|
|
$frameNumber = ((int)ltrim($matches[1], "0"));
|
|
if ($frameNumber > $endFrame) {
|
|
$endFrame = $frameNumber;
|
|
}
|
|
}
|
|
$im = new Imagick();
|
|
$im->readImage($frame);
|
|
$im->transformImageColorspace(Imagick::COLORSPACE_SRGB);
|
|
$resolution = $im->getImageGeometry();
|
|
$resX = $resolution["width"];
|
|
$resY = $resolution["height"];
|
|
|
|
$iframe = [];
|
|
$quantizedIframe = [];
|
|
$pframe = [];
|
|
$quantizedPframe = [];
|
|
|
|
for ($y = 0; $y < $resY; ++$y) {
|
|
$iframe[$y] = [];
|
|
$quantizedIframe[$y] = [];
|
|
$pframe[$y] = [];
|
|
$quantizedPframe[$y] = [];
|
|
for ($x = 0; $x < $resX; ++$x) {
|
|
$pixel = $im->getImagePixelColor($x, $y);
|
|
$c = $pixel->getColor(2);
|
|
$color = new \swf2ass\Color($c["r"], $c["g"], $c["b"], $c["a"] ?? 255);
|
|
|
|
$iframe[$y][$x] = $color;
|
|
if ($frameBuffer !== null and $frameBuffer[$y][$x]->distance($color) > $pframeColorDistance) {
|
|
$pframe[$y][$x] = $color;
|
|
$frameBuffer[$y][$x] = $pframe[$y][$x];
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($dynamicPalette) {
|
|
$im->quantizeImage($colorN, Imagick::COLORSPACE_SRGB, 0, false, true);
|
|
}
|
|
|
|
|
|
foreach ($iframe as $y => $row) {
|
|
foreach ($row as $x => $color) {
|
|
$pixel = $im->getImagePixelColor($x, $y);
|
|
$c = $pixel->getColor(2);
|
|
$color = new \swf2ass\Color($c["r"], $c["g"], $c["b"], $c["a"] ?? 255);
|
|
|
|
|
|
if (!$dynamicPalette) {
|
|
$color = getClosestColor($color, $palette);
|
|
}
|
|
|
|
$quantizedIframe[$y][$x] = $color;
|
|
if (isset($pframe[$y][$x]) and $quantizedFrameBuffer[$y][$x]->distance($color) > $pframeColorDistance) {
|
|
$quantizedPframe[$y][$x] = $color;
|
|
$quantizedFrameBuffer[$y][$x] = $color;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($lastFrameNumber === null) {
|
|
$headerFps = $fps * 2;
|
|
echo <<<ASSHEADER
|
|
[Script Info]
|
|
; Script generated by image2ass from swf2ass
|
|
; https://git.gammaspectra.live/WeebDataHoarder/swf2ass/
|
|
ScriptType: v4.00+
|
|
WrapStyle: 0
|
|
ScaledBorderAndShadow: yes
|
|
YCbCr Matrix: PC.709
|
|
PlayResX: $resX
|
|
PlayResY: $resY
|
|
|
|
[Aegisub Project Garbage]
|
|
Last Style Storage: Default
|
|
Video File: ?dummy:$headerFps:10000:$resX:$resY:160:160:160:c
|
|
|
|
[V4+ Styles]
|
|
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
|
Style: f,Arial,1,&H00FFFFFF,&H000000FF,&H000000FF,&H000000FF,0,0,0,0,100,100,0,0,1,0,0,7,0,0,0,1
|
|
|
|
[Events]
|
|
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
|
|
|
ASSHEADER;
|
|
}
|
|
|
|
fwrite(STDERR, "=== frame $frameNumber\n");
|
|
|
|
$iframeSize = "---";
|
|
|
|
$pframeRender = (new \swf2ass\BitmapConverter($quantizedPframe))->render(false);
|
|
$pframePathCount = array_reduce($pframeRender->commands, function (int $item, \swf2ass\DrawPath $path){
|
|
return $item + count($path->commands->getRecords());
|
|
}, 0);
|
|
|
|
if ($frameBuffer === null or $pframePathCount > 0) {
|
|
$iframeRender = (new \swf2ass\BitmapConverter($quantizedIframe))->render(true);
|
|
$iframePathCount = array_reduce($iframeRender->commands, function (int $item, \swf2ass\DrawPath $path){
|
|
return $item + count($path->commands->getRecords());
|
|
}, 0);
|
|
}
|
|
|
|
if ($frameBuffer === null or ($pframePathCount > 0 and $iframePathCount <= $pframePathCount)) {
|
|
fwrite(STDERR, " | IS IFRAME $frameNumber |$iframePathCount|$pframePathCount\n");
|
|
$frameBuffer = $iframe;
|
|
$quantizedFrameBuffer = $quantizedIframe;
|
|
foreach ($currentFrames as $f) {
|
|
outputFrame($f, $frameNumber, (1 / $fps) * 1000);
|
|
}
|
|
$currentFrames = [];
|
|
|
|
$currentFrames[] = [$frameNumber, $frameNumber, $iframeRender, "i"];
|
|
} else if ($pframePathCount > 0) {
|
|
fwrite(STDERR, " | IS PFRAME $frameNumber |$iframePathCount|$pframePathCount\n");
|
|
$currentFrames[] = [$frameNumber, $frameNumber, $pframeRender, "p"];
|
|
} else {
|
|
|
|
fwrite(STDERR, " | IS DROP $frameNumber |$iframePathCount|$pframePathCount\n");
|
|
}
|
|
|
|
$lastFrameNumber = $frameNumber;
|
|
}
|
|
}
|
|
foreach ($currentFrames as $f) {
|
|
outputFrame($f, $endFrame, (1 / $fps) * 1000);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|