miércoles, 8 de noviembre de 2023





El mundo del desarrollo de software está en constante evolución, y la elección de la herramienta adecuada es esencial para optimizar la productividad y crear aplicaciones excepcionales. En este sentido, Visual Studio Code (VS Code) se ha convertido en una de las opciones más populares y versátiles para desarrolladores de todo el mundo. En este artículo, te guiaré a través de todo lo que necesitas saber sobre Visual Studio Code, desde qué es hasta cómo obtenerlo y sacar el máximo provecho de esta poderosa herramienta.


¿Qué es Visual Studio Code?


Visual Studio Code es un editor de código fuente desarrollado por Microsoft. A pesar de llevar el nombre de la popular suite de desarrollo "Visual Studio", VS Code es una herramienta liviana, gratuita y de código abierto, diseñada para ser altamente personalizable y adecuada para una amplia gama de lenguajes de programación y tecnologías. Su interfaz intuitiva y su ecosistema de extensiones lo hacen especialmente atractivo para los desarrolladores.


Características Destacadas


1. Editor de Texto Avanzado


VS Code ofrece todas las funciones esenciales de un editor de texto avanzado, como resaltado de sintaxis, autocompletado, plegado de código, búsqueda y reemplazo, y mucho más. Su capacidad para manejar grandes cantidades de código de manera eficiente lo convierte en una elección sólida para proyectos de cualquier tamaño.


2. Extensiones Poderosas


Una de las características más destacadas de Visual Studio Code es su extensibilidad. Puedes personalizarlo según tus necesidades instalando extensiones específicas para lenguajes, frameworks o herramientas. Hay miles de extensiones disponibles en el Marketplace de Visual Studio Code, lo que te permite adaptar tu entorno de desarrollo exactamente como lo desees.


3. Depuración Integrada


VS Code incluye un potente depurador que te permite rastrear y solucionar problemas en tu código de manera efectiva. Admite múltiples lenguajes de programación y proporciona una experiencia de depuración intuitiva con puntos de interrupción, inspección de variables y más.


4. Control de Versiones Integrado


La integración con sistemas de control de versiones, como Git, es sencilla en Visual Studio Code. Puedes realizar un seguimiento de los cambios, confirmarlos y colaborar con otros desarrolladores de manera eficiente sin salir de la aplicación.


¿Cómo Obtener Visual Studio Code?


Obtener Visual Studio Code es fácil y gratuito. Simplemente sigue estos pasos:


1. Visita el sitio web oficial de Visual Studio Code en  https://code.visualstudio.com/.

2. Haz clic en el botón "Descargar" para tu sistema operativo (disponible para Windows, macOS y Linux).

3. Una vez que se descargue el instalador, ejecútalo y sigue las instrucciones en pantalla para completar la instalación.


¡Y eso es todo! En cuestión de minutos, tendrás Visual Studio Code listo para usar en tu entorno de desarrollo.


Conclusión    


Visual Studio Code es una herramienta poderosa y versátil que se ha convertido en la elección de muchos desarrolladores de software en todo el mundo. Con su amplia gama de características, su comunidad activa y su facilidad de personalización, es una opción ideal para proyectos de cualquier envergadura y para una variedad de lenguajes de programación. Si aún no lo has probado, te animamos a descargarlo y comenzar a explorar todo lo que Visual Studio Code tiene para ofrecer. Tu experiencia de desarrollo nunca será la misma una vez que descubras su potencial.


¿Utilizas Visual Studio Code en tu trabajo o proyectos personales? ¡Comparte tus experiencias y extensiones favoritas en los comentarios!

martes, 31 de octubre de 2023


La librería pdf-lib es una de las librerías más personalizables y fáciles de utilizar a la hora de crear documentos PDF, que puedan ser descargados para su posterior visualización. Pero si hay algo que complica el escenario al momento de configurarla, es justamente la parte de cargar y leer una fuente personalizada, porque si bien EXPO está creado para ser más seguro y facilitarnos muchas cosas, a la vez nos complica el acceso a los archivos del dispositivo.

En esta guía veremos un ejemplo de cómo cargar y embeber una fuente personalizada a un documento PDF de la manera correcta.


Requisitos previos: Instalar las siguientes dependencias:

-   expo-file-system

- pdf-lib

- base-64

- expo-asset




Directorio: Colocar los archivos de fuentes personalizadas en el
directorio assets/fonts



Para este ejemplo utilizaremos la fuente:
AlexBrush-Regular.ttf







En el archivo principal de nuestro proyecto (App.js) procederemos a importar las librerías previamente
instaladas

import * as FileSystem from 'expo-file-system';
import * as Sharing from 'expo-sharing';
import { PDFDocument, StandardFonts } from 'pdf-lib';
import React, { useEffect, useState } from 'react';
import { Button, Text, View } from 'react-native';
import fontkit from '@pdf-lib/fontkit';
import { decode, encode } from 'base-64';
import { Asset } from 'expo-asset';

Procedemos a configurar las funciones globales de codificación y decodificación: btoa y
atob para poder codificar la fuente personalizada



// Comprobar si la función btoa (Base64 encode) no está disponible en el entorno global
if (!global.btoa) {
  // Asignar la función de codificación Base64 (encode) al objeto global (global)
  global.btoa = encode;
}

// Comprobar si la función atob (Base64 decode) no está disponible en el entorno global
if (!global.atob) {
  // Asignar la función de decodificación Base64 (decode) al objeto global (global)
  global.atob = decode;
}


Dentro de la función principal App definiremos un estado para almacenar la ruta
donde se guardará el doc. pdf, veremos también el esquema

export default function App() {

  const [pdfUri, setPdfUri] = useState(null);

// .....

 async function createAndSavePDF() {
//...
}

const downloadPDF = async () => {
//...
}
useEffect (() => {
createAndSavePDF()
}, [])

return (
<></>
)
}


A continuación crearemos una función llamada createAndSavePDF que contendrá toda
la lógica de creación y guardado de un archivo PDF



async function createAndSavePDF() {

    try {

      console.log('Generando el PDF...');

      // Accediendo al archivo de fuente personalizada AlexBrush-Regular.ttf

      // Comprobando si el directorio 'Fonts' en el sistema de archivos
// local existe.
      if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory +
        'Fonts')).exists) {
        // Si no existe, crea el directorio 'Fonts' en el sistema de archivos local.
        await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory +
          'Fonts');
      }
      // Comprobando si el archivo 'AlexBrush-Regular.ttf' en el directorio
// 'Fonts' existe.
      if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory +
        'Fonts/AlexBrush-Regular.ttf')).exists) {
        // Si no existe, descarga el archivo 'AlexBrush-Regular.ttf'
//desde la ubicación
        //de activos ('assets/fonts/CoconutOil.otf')
        await FileSystem.downloadAsync(
          Asset.fromModule(require('./assets/fonts/CoconutOil.otf')).uri,
          FileSystem.documentDirectory + 'Fonts/AlexBrush-Regular.ttf'
        );
      }
      // Accediendo a los datos binarios del archivo 'AlexBrush-Regular.ttf'.
      const ttfBinary = await FileSystem.readAsStringAsync(FileSystem
        .documentDirectory +
        'Fonts/AlexBrush-Regular.ttf', {
        encoding: FileSystem.EncodingType.Base64,
      });

      // Crea un nuevo documento PDF
      const pdfDoc = await PDFDocument.create();

      // Registro de fontkit
      pdfDoc.registerFontkit(fontkit)

      // Agregando una página al documento
      const pageWidth = 8.5 * 72; // 8.5 pulgadas convertidas a puntos
      const pageHeight = 11 * 72; // 11 pulgadas convertidas a puntos

      const page = pdfDoc.addPage([pageWidth, pageHeight]);

      // Registrando la fuente personalizada estandar
      const font = await pdfDoc.embedFont(StandardFonts.Helvetica);

      // Registrando la fuente personalizada externa
      const customFont = await pdfDoc.embedFont(ttfBinary, {
        custom: true,
      });

      // Agregando contenido al PDF
      page.drawText('Hola, Mundo', {
        x: 270,
        y: 600,
        size: 12,
        font: font,
        colorRgb: [0, 0, 0],
      });

      page.drawText('Cómo estás hoy', {
        x: 250,
        y: 560,
        size: 24,
        font: customFont, // Fuente personalizada
        colorRgb: [0, 0, 0],
      });

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

      // Guardar el archivo PDF en el almacenamiento local
      const fileUri = `${FileSystem.documentDirectory}mi_archivo.pdf`;

      // Convertir pdfBytes a una cadena Base64 utilizando btoa
      const pdfBase64 = btoa(String.fromCharCode(...pdfBytes));

      await FileSystem.writeAsStringAsync(fileUri, pdfBase64, {
        encoding: FileSystem.EncodingType.Base64,
        uri: fileUri,
      });

      console.log('El archivo PDF se ha generado y guardado.');
      setPdfUri(fileUri);

    } catch (error) {
      console.error('Error al generar y guardar el PDF:', error);
    }
  };

Con la función anterior hemos logrado crear un nuevo documento, cargar la fuente
personalizada, y embeberla en el documento pdf el cual se guarda en una ubicación
por default dentro de los archivos del dispositivo.

Ahora crearemos la función downloadPDF para poder seleccionar una ruta personalizada
a través de algún explorador de archivos, y guardar ahí el documento PDF, o bien
compartirlo por medio de las redes sociales:
const downloadPDF = async () => {
    if (pdfUri) {

      console.log('Ruta del archivo:', pdfUri);

      const result = await Sharing.shareAsync(pdfUri);
      // const { status } = await Sharing.shareAsync(pdfUri);

      if (result) {
        const { status } = result;
 
        if (status === 'done') {
          console.log('El archivo PDF se descargó exitosamente.', status);
        } else {
          console.error('No se pudo completar la descarga del archivo PDF.', status);
        }
      } else {
        console.error('No se pudo compartir el archivo PDF.');
        console.error('Result: ', result);
      }
    } else {
      console.error('El archivo PDF no existe.');
    }
  };
Con esto podremos asegurarnos de colocar el archivo en el lugar que queramos. Si elegimos guardarlo con
el explorador de archivos, luego podríamos ir manualmente al lugar donde lo guardamos y elegir abrirlo
con algún gestor de archivos PDF

Finalmente configuramos la vista con un simple botón que nos permitirá guardar el archivo:

 return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>
        Ejemplo de generación y descarga de PDF en React Native
      </Text>
      <Button title="Guardar PDF"
      onPress={downloadPDF}
      // onPress={()=> saveToDocumentPicker(pdfUri)}
      />
    </View>
  );

Código completo:

 
import * as FileSystem from 'expo-file-system';                        
  import * as Sharing from 'expo-sharing';
  import { PDFDocument, StandardFonts } from 'pdf-lib';
  import React, { useEffect, useState } from 'react';
  import { Button, Text, View } from 'react-native';
  import fontkit from '@pdf-lib/fontkit';
  import { decode, encode } from 'base-64';
  import { Asset } from 'expo-asset';

  // Comprobar si la función btoa (Base64 encode) no está disponible
  // en el entorno global
  if (!global.btoa) {
    // Asignar la función de codificación Base64 (encode) al objeto
    // global (global)
    global.btoa = encode;
  }

  // Comprobar si la función atob (Base64 decode) no está disponible
  //  en el entorno global
  if (!global.atob) {
    // Asignar la función de decodificación Base64 (decode) al objeto
    // global (global)
    global.atob = decode;
  }


  export default function App() {

    const [pdfUri, setPdfUri] = useState(null);

    async function createAndSavePDF() {

      try {

        console.log('Generando el PDF...');

        // Accediendo al archivo de fuente personalizada AlexBrush-Regular.ttf

        // Comprobando si el directorio 'Fonts' en el sistema de
        // archivos local existe.
        if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory +
          'Fonts')).exists) {
          // Si no existe, crea el directorio 'Fonts' en el
          // sistema de archivos local.
          await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory +
            'Fonts');
        }
        // Comprobando si el archivo 'AlexBrush-Regular.ttf'
        // en el directorio 'Fonts' existe.
        if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory +
          'Fonts/AlexBrush-Regular.ttf')).exists) {
          // Si no existe, descarga el archivo 'AlexBrush-Regular.ttf'
          // desde la ubicación
          //de activos ('assets/fonts/CoconutOil.otf')
          await FileSystem.downloadAsync(
            Asset.fromModule(require('./assets/fonts/CoconutOil.otf')).uri,
            FileSystem.documentDirectory + 'Fonts/AlexBrush-Regular.ttf'
          );
        }
        // Accediendo a los datos binarios del archivo 'AlexBrush-Regular.ttf'.
        const ttfBinary = await FileSystem.readAsStringAsync(FileSystem
          .documentDirectory +
          'Fonts/AlexBrush-Regular.ttf', {
          encoding: FileSystem.EncodingType.Base64,
        });

        // Crea un nuevo documento PDF
        const pdfDoc = await PDFDocument.create();

        // Registro de fontkit
        pdfDoc.registerFontkit(fontkit)

        // Agregando una página al documento
        const pageWidth = 8.5 * 72; // 8.5 pulgadas convertidas a puntos
        const pageHeight = 11 * 72; // 11 pulgadas convertidas a puntos

        const page = pdfDoc.addPage([pageWidth, pageHeight]);

        // Registrando la fuente personalizada estandar
        const font = await pdfDoc.embedFont(StandardFonts.Helvetica);

        // Registrando la fuente personalizada externa
        const customFont = await pdfDoc.embedFont(ttfBinary, {
          custom: true,
        });

        // Agregando contenido al PDF
        page.drawText('Hola, Mundo', {
          x: 270,
          y: 600,
          size: 12,
          font: font,
          colorRgb: [0, 0, 0],
        });

        page.drawText('Cómo estás hoy', {
          x: 250,
          y: 560,
          size: 24,
          font: customFont, // Fuente personalizada
          colorRgb: [0, 0, 0],
        });

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

        // Guardar el archivo PDF en el almacenamiento local
        const fileUri = `${FileSystem.documentDirectory}mi_archivo.pdf`;

        // Convertir pdfBytes a una cadena Base64 utilizando btoa
        const pdfBase64 = btoa(String.fromCharCode(...pdfBytes));

        await FileSystem.writeAsStringAsync(fileUri, pdfBase64, {
          encoding: FileSystem.EncodingType.Base64,
          uri: fileUri,
        });

        console.log('El archivo PDF se ha generado y guardado.');
        setPdfUri(fileUri);

      } catch (error) {
        console.error('Error al generar y guardar el PDF:', error);
      }
    };

    const downloadPDF = async () => {
      if (pdfUri) {

        console.log('Ruta del archivo:', pdfUri);

        const result = await Sharing.shareAsync(pdfUri);

        if (result) {
          const { status } = result;

          if (status === 'done') {
            console.log('El archivo PDF se descargó exitosamente.', status);
          } else {
            console.error('No se pudo completar la descarga del archivo PDF.', status);
          }
        } else {
          console.error('No se pudo compartir el archivo PDF.');
          console.error('Result: ', result);
        }
      } else {
        console.error('El archivo PDF no existe.');
      }
    };


    useEffect(() => {
      createAndSavePDF();
    }, []);

    return (
      <View style={{ flex: 1, justifyContent: 'center',
alignItems: 'center' }}>
        <Text>Ejemplo de generación y descarga de PDF en React Native</Text>
        <Button title="Guardar PDF"
          onPress={downloadPDF}
        />
      </View>
    );
  }


La aplicación se vería así: