schweigenderFlugel / portfolio

Link to my portfolio website
https://facu-castro.netlify.app/
0 stars 0 forks source link

PDF for resume #1

Open schweigenderFlugel opened 1 month ago

schweigenderFlugel commented 1 month ago

Must integrate a library in order to generate a pdf file containing the resume data and download it from the client side.

You can take the following blocks of code extracted from chatGPT as a reference. Nevertheless you can implement another library.

npm install pdf-lib
import { PDFDocument, rgb } from 'pdf-lib';

export async function generatePdf() {
  // Crear un nuevo documento PDF
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([600, 400]);
  const { width, height } = page.getSize();
  const fontSize = 30;

  // Agregar texto al PDF
  page.drawText('Hello, world!', {
    x: 50,
    y: height - 4 * fontSize,
    size: fontSize,
    color: rgb(0, 0.53, 0.71),
  });

  // Serializar el PDF a bytes
  const pdfBytes = await pdfDoc.save();

  // Crear un blob y una URL de descarga
  const blob = new Blob([pdfBytes], { type: 'application/pdf' });
  const url = URL.createObjectURL(blob);

  return url;
}
---
import { generatePdf } from '../generatePdf.js';

const handleDownload = async () => {
  const pdfUrl = await generatePdf();
  const link = document.createElement('a');
  link.href = pdfUrl;
  link.download = 'example.pdf';
  link.click();
};
---

<html>
<head>
  <title>Generar PDF</title>
</head>
<body>
  <h1>Generar y Descargar PDF</h1>
  <button onClick={handleDownload}>Descargar PDF</button>
</body>
</html>
schweigenderFlugel commented 1 month ago

Instead of using only an asynchronous function, we could use a promise or make the function returns a promise to handle the errors. By the way, I've figured out that pdfkit doesn't work on an astro application.

schweigenderFlugel commented 1 month ago

This is a reference to start building the label with the data in the resume.

import { PDFDocument, rgb, StandardFonts } from '@pdf-lib/pdf-lib';

export async function createPdf() {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage();

  const { width, height } = page.getSize();
  const fontSize = 12;
  const margin = 50;

  const timesBoldFont = await pdfDoc.embedFont(StandardFonts.TimesRomanBold);
  const timesNormalFont = await pdfDoc.embedFont(StandardFonts.TimesRoman);

  const label = 'Nombre:';
  const name = ' Juanito de Tales';

  // Dibuja la etiqueta (parte normal del texto)
  page.drawText(label, {
    x: margin,
    y: height - margin,
    size: fontSize,
    font: timesNormalFont,
    color: rgb(0, 0, 0),
  });

  // Obtiene la anchura de la etiqueta para calcular la posición del nombre
  const anchoLabel = timesNormalFont.widthOfTextAtSize(label, fontSize);

  // Dibuja el nombre (parte en negrita del texto)
  page.drawText(name, {
    x: margin + anchoLabel, // Ajusta la posición basándose en el ancho de la etiqueta
    y: height - margin,
    size: fontSize,
    font: timesBoldFont,
    color: rgb(0, 0, 0),
  });

  const pdfBytes = await pdfDoc.save();
  return pdfBytes;
}
const { PDFDocument, rgb, StandardFonts } = require('@pdf-lib/pdf-lib');
const fs = require('fs');

(async () => {
  // Crear un nuevo documento PDF
  const pdfDoc = await PDFDocument.create();

  // Agregar una página al documento
  const page = pdfDoc.addPage([600, 400]);

  // Cargar una fuente estándar
  const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman);

  // Configuración de la página y el texto
  const fontSize = 12;
  const text = `Este es un ejemplo de texto justificado. La justificación del texto se logra ajustando los espacios entre palabras de modo que cada línea tenga la misma longitud, salvo la última línea.`;
  const textWidth = 500;
  const xStart = 50;
  const yStart = 350;

  // Función para dividir el texto en líneas y justificarlo
  const justifyText = (text, font, fontSize, maxWidth) => {
    const words = text.split(' ');
    let lines = [];
    let currentLine = '';

    words.forEach(word => {
      const width = font.widthOfTextAtSize(currentLine + word + ' ', fontSize);
      if (width > maxWidth) {
        lines.push(currentLine.trim());
        currentLine = word + ' ';
      } else {
        currentLine += word + ' ';
      }
    });

    lines.push(currentLine.trim());

    return lines.map(line => {
      const wordsInLine = line.split(' ');
      if (wordsInLine.length === 1) {
        return line;
      }
      const lineWidth = font.widthOfTextAtSize(line, fontSize);
      const totalSpaces = wordsInLine.length - 1;
      const spaceWidth = (maxWidth - lineWidth) / totalSpaces;
      let justifiedLine = '';

      wordsInLine.forEach((word, index) => {
        justifiedLine += word;
        if (index < totalSpaces) {
          justifiedLine += ' '.repeat(Math.ceil(spaceWidth / font.widthOfTextAtSize(' ', fontSize)));
        }
      });

      return justifiedLine;
    });
  };

  // Obtener las líneas justificadas
  const justifiedLines = justifyText(text, timesRomanFont, fontSize, textWidth);

  // Dibujar las líneas justificadas en el PDF
  let yOffset = yStart;
  justifiedLines.forEach(line => {
    page.drawText(line, {
      x: xStart,
      y: yOffset,
      size: fontSize,
      font: timesRomanFont,
      color: rgb(0, 0, 0),
    });
    yOffset -= fontSize + 2; // Ajustar el interlineado
  });

  // Guardar el documento PDF en un archivo
  const pdfBytes = await pdfDoc.save();
  fs.writeFileSync('output.pdf', pdfBytes);

  console.log('PDF creado con éxito');
})();