soroban-abacus-flashcards/packages/templates/extract-viewbox-broken.js

129 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
// Extract viewBox from crop marks in Typst-generated SVGs
// This demonstrates how to use crop marks for automated SVG processing
const fs = require("fs");
function extractViewBoxFromCropMarks(svgPath) {
console.log(`📐 Analyzing crop marks in ${svgPath}...`);
if (!fs.existsSync(svgPath)) {
throw new Error(`SVG file not found: ${svgPath}`);
}
const svgContent = fs.readFileSync(svgPath, "utf8");
// Use regex to find crop mark links and their positions
const cropMarks = {};
// Pattern to match link elements with crop-mark hrefs and their transforms
const linkPattern =
/<use[^>]*xlink:href="(crop-mark:\/\/[^"]*)"[^>]*\/?>|<g[^>]*>\s*<path[^>]*\/>\s*<\/g>/g;
// Simpler approach: find crop mark red rectangles and their containing transforms
const redRectPattern =
/<g transform="translate\(([^)]+)\)"[^>]*>\s*<path[^>]*fill="#ff4136"[^>]*\/>\s*<\/g>/g;
let match;
let markIndex = 0;
const markTypes = ["left", "right", "top", "bottom"]; // Expected order from our implementation
while ((match = redRectPattern.exec(svgContent)) !== null) {
const coords = match[1].split(/[,\s]+/).map(Number);
const x = coords[0] || 0;
const y = coords[1] || 0;
if (markIndex < markTypes.length) {
const markType = markTypes[markIndex];
cropMarks[markType] = { x, y };
console.log(` ✅ Found ${markType} at (${x}, ${y})`);
markIndex++;
}
}
if (Object.keys(cropMarks).length === 0) {
console.log(" ⚠️ No crop marks found in this SVG");
return null;
}
// Calculate viewBox from crop mark positions
const positions = Object.values(cropMarks);
const minX = Math.min(...positions.map((p) => p.x));
const maxX = Math.max(...positions.map((p) => p.x));
const minY = Math.min(...positions.map((p) => p.y));
const maxY = Math.max(...positions.map((p) => p.y));
const width = maxX - minX;
const height = maxY - minY;
const viewBox = `${minX} ${minY} ${width} ${height}`;
console.log(`📏 Calculated viewBox: "${viewBox}"`);
console.log(` 📊 Dimensions: ${width} × ${height}`);
console.log(` 📍 Origin: (${minX}, ${minY})`);
return {
viewBox,
width,
height,
minX,
minY,
maxX,
maxY,
cropMarks,
};
}
function updateSVGViewBox(inputPath, outputPath = null) {
const result = extractViewBoxFromCropMarks(inputPath);
if (!result) {
console.log("❌ Cannot update viewBox - no crop marks found");
return false;
}
const svgContent = fs.readFileSync(inputPath, "utf8");
// Update the viewBox attribute
const updatedSVG = svgContent.replace(
/viewBox="[^"]*"/,
`viewBox="${result.viewBox}"`,
);
const output = outputPath || inputPath.replace(".svg", "-cropped.svg");
fs.writeFileSync(output, updatedSVG);
console.log(`✅ Updated SVG saved to ${output}`);
return true;
}
// CLI usage
if (require.main === module) {
const args = process.argv.slice(2);
if (args.length === 0) {
console.log("Usage: node extract-viewbox.js <svg-file> [output-file]");
console.log("");
console.log("Examples:");
console.log(" node extract-viewbox.js gallery/debug-crop-marks-89.svg");
console.log(
" node extract-viewbox.js gallery/crop-single-1.svg cropped.svg",
);
process.exit(1);
}
const [inputFile, outputFile] = args;
try {
if (outputFile) {
updateSVGViewBox(inputFile, outputFile);
} else {
extractViewBoxFromCropMarks(inputFile);
}
} catch (error) {
console.error("❌ Error:", error.message);
process.exit(1);
}
}
module.exports = { extractViewBoxFromCropMarks, updateSVGViewBox };