lainTSX/scripts/extract/extract_lapks.mjs
2021-06-05 20:51:04 +09:30

130 lines
3.7 KiB
JavaScript

import { spawnSync } from "child_process";
import { readFileSync, mkdirSync, writeFileSync } from "fs";
import { join, resolve } from "path";
import KaitaiStream from "kaitai-struct/KaitaiStream.js";
import Lapk from "./Lapk.js";
export function extract_lapks(tempdir, jpsxdec_jar) {
spawnSync(
"java",
[
"-jar",
jpsxdec_jar,
"-x",
join(tempdir, "disc1.idx"),
"-i",
"LAPKS.BIN",
"-dir",
tempdir,
],
{ stdio: "inherit" }
);
const lapk_info = JSON.parse(readFileSync("lapks.json"));
let lapk_data = readFileSync(join(tempdir, "LAPKS.BIN"));
let output_folder = join("..", "..", "src", "static", "sprites", "lain");
mkdirSync(output_folder, { recursive: true });
for (let [index, lapk_entry] of lapk_info.entries()) {
let data = lapk_data.slice(
lapk_entry.offset,
lapk_entry.offset + lapk_entry.size
);
let parsed_lapk = new Lapk(new KaitaiStream(data));
let images = [];
if (index != 37) continue;
for (let [frame_number, cell_data] of parsed_lapk.data.cellData.entries()) {
const cell_header = parsed_lapk.data.cellHeaders[frame_number];
// create bitstream header (from https://github.com/m35/jpsxdec/blob/1de0518583236844b93f5fcc8a4d330a01c222b3/laintools/src/laintools/Lain_LAPKS.java#L319)
let bitstream_header = Buffer.alloc(8);
bitstream_header.writeInt8(cell_data.chrominanceQuantisationScale);
bitstream_header.writeInt8(cell_data.luminanceQuantisationScale, 1);
bitstream_header.writeInt16LE(0x3800, 2);
bitstream_header.writeInt16LE(cell_data.runLengthCodeCount, 4);
bitstream_header.writeInt16LE(0x0000, 6);
let output_bitstream = Buffer.concat(
[bitstream_header, cell_data.imageData],
cell_data.imageDataSize + 8
);
let bitstream_file = join(tempdir, `${index}_${frame_number}.bs`);
let out_frame = join(tempdir, `${index}_${frame_number}.png`);
let out_mask = join(tempdir, `${index}_${frame_number}_mask.gray`);
let out_alpha = join(tempdir, `${index}_${frame_number}_alpha.png`);
writeFileSync(bitstream_file, output_bitstream);
writeFileSync(out_mask, Buffer.from(cell_data.bitMask));
spawnSync(
"java",
[
"-jar",
jpsxdec_jar,
"-f",
resolve(bitstream_file),
"-static",
"bs",
"-dim",
`${cell_data.width}x${cell_data.height}`,
"-up",
"Lanczos3",
],
{ stdio: "inherit", cwd: tempdir }
);
spawnSync(
"convert",
[
"-background",
"none",
"(",
"-extent",
"352x367",
"xc:none",
")",
"(",
out_frame,
"(",
"-depth",
"2",
"-size",
`${cell_data.width}x${cell_data.height}`,
out_mask,
"-alpha",
"off",
")",
"-compose",
"copy-opacity",
"-composite",
")",
"-geometry",
`+${320 / 2 + 4 - cell_header.negativeXPosition}+${
352 - 1 - cell_header.negativeYPosition
}`,
"-compose",
"over",
"-composite",
out_alpha,
],
{ stdio: "inherit" }
);
images.push(out_alpha);
}
if (lapk_entry.tile != "") {
spawnSync(
"montage",
[
"-background",
"none",
"-tile",
lapk_entry.tile,
"-geometry",
"+0+0",
...images,
join(output_folder, lapk_entry.output_name)
],
{ stdio: "inherit" }
);
}
}
}