Files
FarmaFinder/scripts/generate_patent_clean_sections.mjs
Antoni Nuñez Romeu d68463548f
Run Tests on Branches / Detect Changes (push) Successful in 19s
Run Tests on Branches / Backend Tests (push) Successful in 2m46s
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
Run Tests on Branches / Frontend Tests (push) Successful in 2m24s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Has been skipped
Patentes internacionales + Forgot Pwd
2026-08-18 11:01:54 +02:00

151 lines
5.7 KiB
JavaScript

import fs from 'fs';
import os from 'os';
import path from 'path';
import { execFileSync } from 'child_process';
const root = process.cwd();
const sourcePdf = path.join(root, 'Patentes', 'SOLICITUD_PATENTE_OEPM_FARMAFINDER.pdf');
const outDir = path.join(root, 'Patentes');
function ensureExists(file) {
if (!fs.existsSync(file)) {
throw new Error(`Missing file: ${file}`);
}
}
function run(cmd, args) {
execFileSync(cmd, args, { stdio: 'inherit' });
}
function mergePages(output, pages) {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'farmafinder-clean-'));
run('pdfseparate', [sourcePdf, path.join(tmp, 'page-%d.pdf')]);
const inputs = pages.map((n) => path.join(tmp, `page-${n}.pdf`));
run('pdfunite', [...inputs, output]);
}
function esc(s) {
return String(s).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
}
function latin1(s) {
return Buffer.from(s, 'latin1').toString('latin1');
}
function wrapText(text, widthChars) {
const words = String(text).split(/\s+/);
const lines = [];
let line = '';
for (const word of words) {
const candidate = line ? `${line} ${word}` : word;
if (candidate.length > widthChars && line) {
lines.push(line);
line = word;
} else {
line = candidate;
}
}
if (line) lines.push(line);
return lines;
}
function writeDrawingsPdf(output) {
const PAGE_W = 595.28;
const PAGE_H = 841.89;
const MARGIN_L = 56;
const MARGIN_R = 56;
const MARGIN_T = 56;
const MARGIN_B = 54;
const CONTENT_W = PAGE_W - MARGIN_L - MARGIN_R;
const lines = [
{ type: 'title', text: 'Dibujos' },
{ type: 'subtitle', text: 'Bloque limpio para la presentación de la solicitud' },
{ type: 'spacer', lines: 1 },
{ type: 'heading', text: 'Breve descripción de los dibujos' },
{ type: 'paragraph', text: 'Figura 1. Diagrama de bloques general del sistema.' },
{ type: 'paragraph', text: 'Figura 2. Flujo de captura y validación del escaneo de la TSI.' },
{ type: 'paragraph', text: 'Figura 3. Flujo de contraste entre necesidad terapéutica y stock de farmacias.' },
{ type: 'paragraph', text: 'Figura 4. Flujo de acción cuando no existe stock disponible.' },
{ type: 'spacer', lines: 1 },
{ type: 'heading', text: 'Nota' },
{ type: 'paragraph', text: 'El documento fuente contiene referencias esquemáticas a las figuras, pero no incluye láminas técnicas dibujadas de forma separada. Si la Oficina requiere placas gráficas, habrá que añadirlas antes de la presentación definitiva.' },
];
const objects = [''];
const add = (body) => {
objects.push(body);
return objects.length - 1;
};
const fontReg = add('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Roman /Encoding /WinAnsiEncoding >>');
const fontBold = add('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Bold /Encoding /WinAnsiEncoding >>');
const fontIt = add('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Italic /Encoding /WinAnsiEncoding >>');
const pagesTree = add('');
const ops = [];
let y = PAGE_H - MARGIN_T;
const write = (txt, x, size, font = 'F1') => {
ops.push(`BT /${font} ${size} Tf ${x} ${y} Td (${esc(latin1(txt))}) Tj ET`);
y -= size * 1.25;
};
const ensure = (needed) => y - needed > MARGIN_B;
for (const item of lines) {
if (item.type === 'title') {
for (const line of wrapText(item.text, 26)) write(line, MARGIN_L + 175, 18, 'F2');
continue;
}
if (item.type === 'subtitle') {
for (const line of wrapText(item.text, 40)) write(line, MARGIN_L + 45, 11.5, 'F3');
y -= 6;
continue;
}
if (item.type === 'spacer') {
y -= (item.lines || 1) * 12;
continue;
}
if (item.type === 'heading') {
if (!ensure(20)) break;
write(item.text, MARGIN_L, 13, 'F2');
y -= 2;
ops.push(`0.3 w ${MARGIN_L} ${y} m ${PAGE_W - MARGIN_R} ${y} l S`);
y -= 8;
continue;
}
if (item.type === 'paragraph') {
const wrapped = wrapText(item.text, 80);
if (!ensure(wrapped.length * 14 + 6)) break;
for (const line of wrapped) write(line, MARGIN_L, 11.5, 'F1');
y -= 2;
}
}
ops.push(`BT /F1 9 Tf ${PAGE_W - 100} ${24} Td (Page 1) Tj ET`);
const content = ops.join('\n');
const contentObj = add(`<< /Length ${Buffer.byteLength(content, 'latin1')} >>\nstream\n${content}\nendstream`);
const pageObj = add(`<< /Type /Page /Parent ${pagesTree} 0 R /MediaBox [0 0 ${PAGE_W} ${PAGE_H}] /Resources << /Font << /F1 ${fontReg} 0 R /F2 ${fontBold} 0 R /F3 ${fontIt} 0 R >> >> /Contents ${contentObj} 0 R >>`);
objects[pagesTree] = `<< /Type /Pages /Kids [${pageObj} 0 R] /Count 1 >>`;
const catalog = add(`<< /Type /Catalog /Pages ${pagesTree} 0 R >>`);
let pdf = '%PDF-1.4\n';
const offsets = [0];
for (let i = 1; i < objects.length; i += 1) {
offsets[i] = Buffer.byteLength(pdf, 'latin1');
pdf += `${i} 0 obj\n${objects[i]}\nendobj\n`;
}
const xref = Buffer.byteLength(pdf, 'latin1');
pdf += `xref\n0 ${objects.length}\n`;
pdf += '0000000000 65535 f \n';
for (let i = 1; i < objects.length; i += 1) {
pdf += `${String(offsets[i]).padStart(10, '0')} 00000 n \n`;
}
pdf += `trailer << /Size ${objects.length} /Root ${catalog} 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
fs.writeFileSync(output, Buffer.from(pdf, 'latin1'));
}
ensureExists(sourcePdf);
mergePages(path.join(outDir, 'SOLICITUD_PATENTE_OEPM_FARMAFINDER_descripcion_limpia.pdf'), [2, 3, 4]);
mergePages(path.join(outDir, 'SOLICITUD_PATENTE_OEPM_FARMAFINDER_reivindicaciones_limpia.pdf'), [5]);
mergePages(path.join(outDir, 'SOLICITUD_PATENTE_OEPM_FARMAFINDER_resumen_limpia.pdf'), [6]);
writeDrawingsPdf(path.join(outDir, 'SOLICITUD_PATENTE_OEPM_FARMAFINDER_dibujos_limpia.pdf'));
console.log('Clean section PDFs generated.');