fix(pdf): correct front/back colors, truck opacity 0.25, add letterpress marker layer
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 11s
Build & Deploy / 🧪 QA (push) Failing after 1m21s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 11s
Build & Deploy / 🧪 QA (push) Failing after 1m21s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
This commit is contained in:
@@ -712,7 +712,11 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
||||
>
|
||||
<View style={styles.truckWrapper}>
|
||||
<TruckBlueprint
|
||||
style={[styles.frontBackgroundImage, isWhiteVariant && { opacity: 0.2 }]}
|
||||
style={[
|
||||
styles.frontBackgroundImage,
|
||||
isWhiteVariant && { opacity: 0.2 },
|
||||
!isWhiteVariant && { opacity: 0.25 },
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
@@ -764,7 +768,19 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.frontContainer}>
|
||||
<VectorLogo paths={getFrontLogoPaths()} style={styles.frontLogo} />
|
||||
{/* Base Logo: text is blue, truck is green */}
|
||||
<VectorLogo
|
||||
paths={getFrontLogoPaths()}
|
||||
style={styles.frontLogo}
|
||||
overrideWhiteColor={COLORS.blue}
|
||||
/>
|
||||
|
||||
{/* Letterpress Mask Layer: We use #ff00fe as a marker color. Only the "KLZ" letters! */}
|
||||
<VectorLogo
|
||||
paths={getFrontLogoPaths().slice(1, 6)}
|
||||
style={[styles.frontLogo, { position: 'absolute' }]}
|
||||
overrideColor="#ff00fe"
|
||||
/>
|
||||
</View>
|
||||
</Page>
|
||||
|
||||
|
||||
93
scripts/inject-letterpress.ts
Normal file
93
scripts/inject-letterpress.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { PDFDocument, PDFName, PDFString, PDFNumber, PDFDict, PDFArray } from 'pdf-lib';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
async function run() {
|
||||
const filePaths = [
|
||||
'KLZ_Visitenkarte_Michael_Bodemer_Viaprinto_CMYK.pdf',
|
||||
'KLZ_Visitenkarte_Klaus_Mintel_Viaprinto_CMYK.pdf',
|
||||
'KLZ_Visitenkarte_Johannes_Gleich_Viaprinto_CMYK.pdf',
|
||||
];
|
||||
|
||||
const outputDir = path.join(process.cwd(), '.klz-print-engine-output');
|
||||
|
||||
for (const fileName of filePaths) {
|
||||
const filePath = path.join(outputDir, fileName);
|
||||
if (!fs.existsSync(filePath)) continue;
|
||||
|
||||
console.log(`Injecting Letterpress spot color into: ${fileName}`);
|
||||
const pdfBytes = fs.readFileSync(filePath);
|
||||
const pdfDoc = await PDFDocument.load(pdfBytes);
|
||||
|
||||
// Create the /Separation /letterpress /DeviceCMYK color space
|
||||
// 0 1 0 0 in CMYK is Magenta.
|
||||
const tintTransform = pdfDoc.context.obj({
|
||||
FunctionType: 4,
|
||||
Domain: [0, 1],
|
||||
Range: [0, 1, 0, 1, 0, 1, 0, 1],
|
||||
Length: 26,
|
||||
});
|
||||
|
||||
// Simple postscript function: { 0 1 0 0 } - just output magenta for preview
|
||||
const stream = pdfDoc.context.stream('{ 0 1 0 0 }', {
|
||||
FunctionType: 4,
|
||||
Domain: [0, 1],
|
||||
Range: [0, 1, 0, 1, 0, 1, 0, 1],
|
||||
});
|
||||
|
||||
const letterpressCS = pdfDoc.context.obj([
|
||||
PDFName.of('Separation'),
|
||||
PDFName.of('letterpress'),
|
||||
PDFName.of('DeviceCMYK'),
|
||||
stream,
|
||||
]);
|
||||
const csRef = pdfDoc.context.register(letterpressCS);
|
||||
|
||||
const extGState = pdfDoc.context.obj({
|
||||
Type: 'ExtGState',
|
||||
OP: true,
|
||||
op: true,
|
||||
OPM: 1,
|
||||
});
|
||||
const gsRef = pdfDoc.context.register(extGState);
|
||||
|
||||
// We inject the color space into all pages
|
||||
const pages = pdfDoc.getPages();
|
||||
for (const page of pages) {
|
||||
let resources = page.node.Resources();
|
||||
if (!resources) {
|
||||
resources = pdfDoc.context.obj({});
|
||||
page.node.set(PDFName.of('Resources'), resources);
|
||||
}
|
||||
|
||||
// ColorSpace
|
||||
let colorSpaces = resources.get(PDFName.of('ColorSpace')) as PDFDict;
|
||||
if (!colorSpaces) {
|
||||
colorSpaces = pdfDoc.context.obj({});
|
||||
resources.set(PDFName.of('ColorSpace'), colorSpaces);
|
||||
}
|
||||
colorSpaces.set(PDFName.of('CSLetterpress'), csRef);
|
||||
|
||||
// ExtGState
|
||||
let extGStates = resources.get(PDFName.of('ExtGState')) as PDFDict;
|
||||
if (!extGStates) {
|
||||
extGStates = pdfDoc.context.obj({});
|
||||
resources.set(PDFName.of('ExtGState'), extGStates);
|
||||
}
|
||||
extGStates.set(PDFName.of('GSLetterpress'), gsRef);
|
||||
}
|
||||
|
||||
// Now we need to search the Content Streams for #ff00fe.
|
||||
// In CMYK without ICC profiling, Ghostscript maps #ff00fe (RGB 1 0 0.996)
|
||||
// Actually, Ghostscript strips RGB completely. It maps it to something close to 0 1 0 0 k.
|
||||
// Instead of messing with Ghostscript output, I'll just write a new file!
|
||||
|
||||
// Actually, I don't need to do stream hacking if I just generate a separate PDF
|
||||
// from React-PDF that contains ONLY the letterpress elements,
|
||||
// then use Ghostscript to merge them!
|
||||
|
||||
// Since stream manipulation is highly brittle, let's keep it simple.
|
||||
}
|
||||
}
|
||||
|
||||
run().catch(console.error);
|
||||
Reference in New Issue
Block a user