Skip to content

Commit

Permalink
Merged generate PDF/PNG logic into 1 file
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvilmehta committed Apr 29, 2024
1 parent 3cf284b commit e74b44d
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 222 deletions.
123 changes: 123 additions & 0 deletions src/actions/certificate/generateCertificate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { createCanvas, loadImage } from 'canvas';
import { PDFDocument, rgb } from 'pdf-lib';
import fs from 'fs';

const getTextProperties = (
certificateId: string,
userName: string,
hostname: string,
) => {
return [
{ text: 'CERTIFICATE', fontSize: 80, offsetY: 450 },
{ text: 'OF COMPLETION', fontSize: 35, offsetY: 400 },
{
text: 'This certificate is proudly presented to',
fontSize: 30,
offsetY: 100,
},
{ text: userName, fontSize: 65, offsetY: 0 },
{
text: "For Successfully Completing the '0-1' cohort offered by 100xdevs",
fontSize: 30,
offsetY: -100,
},
{ text: 'HARKIRAT SINGH', fontSize: 30, offsetY: -400 },
{ text: 'Instructor', fontSize: 25, offsetY: -450 },
{ text: `Certificate id: ${certificateId}`, fontSize: 20, offsetY: -500 },
{
text: `Verify at: http://${hostname}/certificate/verify/${certificateId}`,
fontSize: 20,
offsetY: -530,
},
];
};
export const generatePng = async (
certificateId: string,
userName: string,
hostname: string,
) => {
const textProperties = getTextProperties(certificateId, userName, hostname);

const certiTemplate = await loadImage(
'src/app/api/certificate/certitemplate.png',
);
const canvas = createCanvas(certiTemplate.width, certiTemplate.height);
const ctx = canvas.getContext('2d');

ctx.drawImage(certiTemplate, 0, 0, canvas.width, canvas.height);

ctx.fillStyle = 'black';
ctx.textAlign = 'center';

for (const { text, fontSize, offsetY } of textProperties) {
ctx.font = `${fontSize}px "Times New Roman"`;
ctx.fillText(text, canvas.width / 2, canvas.height / 2 - offsetY);
}

const sign = await loadImage('src/app/api/certificate/sign.png');

ctx.drawImage(
sign,
canvas.width / 2 - sign.width / 2,
canvas.height / 2 + 350 - sign.height,
);

const buffer = canvas.toBuffer('image/png');
return buffer;
};

export const generatePdf = async (
certificateId: string,
userName: string,
hostname: string,
) => {
const textProperties = getTextProperties(certificateId, userName, hostname);

const [imageData, signData] = await Promise.all([
fs.promises.readFile('src/app/api/certificate/certitemplate.png'),
fs.promises.readFile('src/app/api/certificate/sign.png'),
]);

const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage([2000, 1545]);

const image = await pdfDoc.embedPng(imageData);
const { width: imgWidth, height: imgHeight } = image.scaleToFit(
page.getWidth(),
page.getHeight(),
);
page.drawImage(image, {
x: page.getWidth() / 2 - imgWidth / 2,
y: page.getHeight() / 2 - imgHeight / 2,
width: imgWidth,
height: imgHeight,
});
const font = await pdfDoc.embedFont('Times-Roman');
for (const { text, fontSize, offsetY } of textProperties) {
const textWidth = font.widthOfTextAtSize(text, fontSize);
const textX = (page.getWidth() - textWidth) / 2;
const textY = page.getHeight() / 2 + offsetY;
page.drawText(text, {
x: textX,
y: textY,
size: fontSize,
color: rgb(0, 0, 0),
font,
});
}

const sign = await pdfDoc.embedPng(signData);
const { width: signWidth, height: signHeight } = sign.scaleToFit(
page.getWidth() * 0.5,
page.getHeight() * 0.1,
);
page.drawImage(sign, {
x: page.getWidth() / 2 - signWidth / 2,
y: page.getHeight() / 2 - 350,
width: signWidth,
height: signHeight,
});

const pdfBytes = await pdfDoc.save();
return pdfBytes;
};
55 changes: 0 additions & 55 deletions src/actions/certificate/generatePdf.ts

This file was deleted.

57 changes: 0 additions & 57 deletions src/actions/certificate/generatePng.ts

This file was deleted.

21 changes: 16 additions & 5 deletions src/app/api/certificate/get/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import db from '@/db';
import { generatePdf } from '@/actions/certificate/generatePdf';
import { generatePng } from '@/actions/certificate/generatePng';
import {
generatePng,
generatePdf,
} from '@/actions/certificate/generateCertificate';
import { headers } from 'next/headers';

export async function GET(req: NextRequest) {
const headersList = headers();
const hostname = headersList.get('x-forwarded-host');
if (!hostname) return new NextResponse('No host found', { status: 400 });

const url = new URL(req.url);
const searchParams = new URLSearchParams(url.search);

Expand All @@ -21,7 +28,11 @@ export async function GET(req: NextRequest) {
});
if (!certificate)
return new NextResponse('Cannot find certificate', { status: 400 });
const data = await generatePng(certId, certificate.user.name || '');
const data = await generatePng(
certId,
certificate.user.name || '',
hostname,
);
return new NextResponse(data, {
headers: {
'Content-Type': 'image/png',
Expand Down Expand Up @@ -68,7 +79,7 @@ export async function GET(req: NextRequest) {

try {
if (type === 'pdf') {
const data = await generatePdf(certificateId, userName);
const data = await generatePdf(certificateId, userName, hostname);
return new NextResponse(data, {
headers: {
'Content-Type': 'application/pdf',
Expand All @@ -78,7 +89,7 @@ export async function GET(req: NextRequest) {
}

if (type === 'png') {
const data = await generatePng(certificateId, userName);
const data = await generatePng(certificateId, userName, hostname);
return new NextResponse(data, {
headers: {
'Content-Type': 'image/png',
Expand Down
104 changes: 0 additions & 104 deletions src/app/api/certificate/share/route.ts

This file was deleted.

Loading

0 comments on commit e74b44d

Please sign in to comment.