mycofi-earth-website/lib/zine.ts

87 lines
2.3 KiB
TypeScript

import sharp from "sharp";
import { getAllPagePaths, readFileAsBuffer, savePrintLayout } from "./storage";
export interface PrintLayoutOptions {
zineId: string;
zineName?: string;
background?: string;
}
// Create print layout directly with Sharp
export async function createZinePrintLayout(
zineId: string,
zineName: string = "mycozine"
): Promise<{ filepath: string; buffer: Buffer }> {
const pagePaths = await getAllPagePaths(zineId);
if (pagePaths.length !== 8) {
throw new Error(`Expected 8 pages, got ${pagePaths.length}`);
}
// Print layout dimensions (300 DPI, 11" x 8.5")
const PRINT_WIDTH = 3300;
const PRINT_HEIGHT = 2550;
const PANEL_WIDTH = 825;
const PANEL_HEIGHT = 1275;
// Page arrangement for proper folding:
// Top row (rotated 180°): P1, P8, P7, P6
// Bottom row (normal): P2, P3, P4, P5
const pageArrangement = [
// Top row
{ page: 1, col: 0, row: 0, rotate: 180 },
{ page: 8, col: 1, row: 0, rotate: 180 },
{ page: 7, col: 2, row: 0, rotate: 180 },
{ page: 6, col: 3, row: 0, rotate: 180 },
// Bottom row
{ page: 2, col: 0, row: 1, rotate: 0 },
{ page: 3, col: 1, row: 1, rotate: 0 },
{ page: 4, col: 2, row: 1, rotate: 0 },
{ page: 5, col: 3, row: 1, rotate: 0 },
];
// Create base canvas
const canvas = sharp({
create: {
width: PRINT_WIDTH,
height: PRINT_HEIGHT,
channels: 4,
background: { r: 255, g: 255, b: 255, alpha: 1 },
},
});
// Prepare composites
const composites: sharp.OverlayOptions[] = [];
for (const { page, col, row, rotate } of pageArrangement) {
const pageBuffer = await readFileAsBuffer(pagePaths[page - 1]);
// Resize page to panel size, maintaining aspect ratio
let processedPage = sharp(pageBuffer).resize(PANEL_WIDTH, PANEL_HEIGHT, {
fit: "cover",
position: "center",
});
// Rotate if needed
if (rotate !== 0) {
processedPage = processedPage.rotate(rotate);
}
const pageData = await processedPage.toBuffer();
composites.push({
input: pageData,
left: col * PANEL_WIDTH,
top: row * PANEL_HEIGHT,
});
}
// Composite all pages
const outputBuffer = await canvas.composite(composites).png().toBuffer();
// Save the print layout
const filepath = await savePrintLayout(zineId, outputBuffer);
return { filepath, buffer: outputBuffer };
}