Wilson Vargas
Wilson Vargas

Un programador enamorado de su código.

Wilson Vargas
Author

Un chico con una gran experiencia en el arte del desarrollo software. Desarrollador de aplicaciones de móviles, especialista en ASP.Net, Xamarin y tecnologías de computo en la Nube en especial Azure.

Share


Suscribete


Mantente al tanto de mis nuevos artículos

Tags


Featured on Planet Xamarin badge

Twitter


Creando un visor PDF con las nuevas APIs de Windows 8.1

Wilson VargasWilson Vargas

Los archivos PDF (Portable Document Format) son en realidad el estándar para la publicación de documentos en internet, ya que es aceptado por todas las plataformas y es utilizado por la mayoría de la gente. El soporte para los archivos PDF es algo que una plataforma como la de Windows, no puede evitar.
En Windows 8 y ahora en Windows 8.1 hay una aplicación que puede leer este formato. Pero en Windows 8.1 este estándar y su API ganaron un nuevo espacio de nombres (namespace) dedicado al formato PDF, por lo que ahora los desarrolladores podemos leer y trabajar con estos archivos fácilmente.

Windows.Data.Pdf

La nueva API dedicada al formato PDF está en el espacio de nombres Windows.Data.Pdf.
Son muy sencillas y básicas y sólo permite leer documentos, así que por favor, si tu intención es genera un archivo PDF a partir de tu aplicación, es mejor que elijas alguna de las bibliotecas gratuitas o comerciales disponibles.
La primera clase en el espacio de nombres es PdfDocument, que es capaz de leer el contenido, desde un archivo (una instancia de IStorageFile) o directamente desde un stream, este último permite la manipulación de los contenidos en memoria. Aquí un ejemplillo:

StorageFile file = this.GetFile(); this.Document = await PdfDocument.LoadFromFileAsync(file);

Los dos métodos estáticos, LoadFromFileAsync y LoadFromStreamAsync te permiten abrir archivos protegidos por contraseña, pasándole la contraseña como un segundo argumento. Podemos saber que un documento está protegido con una contraseña, porque al intentar abrirlo se lanzará una excepción, así que hay que capturar la excepción lanzada y luego pedir al usuario la contraseña.

Una vez que el documento se ha cargado tenemos muy poca información al respecto. La clase PdfDocument sólo proporcionan la propiedad PageCount y una propiedad booleana que cambia a “true” si el documento está protegido con una contraseña. Yo hubiera preferido algo más, pero eso es todo =(.

Por supuesto, tú puedes obtener cada una de las páginas del archivo, con una instancia de la clase PdfPage utilizando el método GetPage de la clase PdfDocument, que requiere el índice de la página que deseas obtener. La clase PdfPage tiene algo más de información disponible, incluyendo el tamaño de la página, su índice en el documento y otras propiedades como la rotación y dimensiones. Aquí puede ver cómo obtener una página del archivo PDF:

PdfPage page = this.Document.GetPage(1); var width = page.Size.Width; var height = page.Size.Height;

En el mismo fragmento de código, puedes ver cómo obtenemos el tamaño actual de la página con la propiedad Size.
Tener una referencia a una página del archivo, es el punto de partida para poder mostrarla en la pantalla. La API te permite renderizar la página a un Bitmap, de modo que puedes utilizar una imagen para mostrar el contenido al usuario. La representación es así de simple:

await this.CurrentPage.RenderToStreamAsync(stream);

Esta línea es capaz de transformar la página a un stream en el formato PNG.

Empecemos…

Antes de adentrarnos más en las opciones de renderización que son de alguna manera mucho más complejas que el sencillo ejemplo que escribí en el punto anterior de este artículo, vamos a crear un pequeño proyecto que implementará un visor PDF básico, capaz de navegar por el documento, ampliar y reducir sus páginas, etc.
En primer lugar, empezamos creando un proyecto en blanco con la estructura, similar a la siguiente imagen.

La aplicación sólo contiene una página que será la plantilla en la que se visualizará el PDF. En una versión más “pro”, que me imagino que tú harás, debes implementar el contrato compartir y asociarlo con una extensión .pdf, pero para el propósito de este articulo sólo pondremos un botón que permitirá elegir un archivo en formato pdf desde el sistema de archivos de Windows.

Los otros componentes son: el contenedor que representará una imagen, dos botones que se utilizarán para navegar por las páginas y un bloque de texto para mostrar la posición actual en el documento. Para la navegación entre páginas también podemos utilizar el control FlipView, pero eso queda a tu criterio, tú eres el genio. ;)

El flujo se iniciará cuando el usuario haga clic en el botón para abrir el documento. Esto iniciará un FileOpenPicker para permitir que el usuario elija un único archivo PDF para abrirlo. Cuando el usuario haya escogido el archivo, sigue el método OpenFile que carga el archivo PDF e inicializa el entorno de renderizado (OpenFile es un método creado en este ejemplo). Algunas propiedades como ZoomFactor (también creada en este ejemplo) se inicializan pero las vamos a utilizar en el siguiente paso, cuando les muestre cómo implementar una función de zoom.

Después de que hemos abierto el archivo con éxito, el flujo continua llamando al método RenderPage que es el punto central que hace que el PDF se muestre en el control Image.

En primer lugar, la página actual se carga sobre el control Image de la página actual. Esto se va actualizando por los botones de atrás y adelante como te mostraré luego. Entonces tenemos que crear un objeto MemoryStream y hacer un cast a un IRandomAccessStream. Esto te permite escribir el contenido de la página a un stream utilizando el método RenderToStreamAsync(). De esta manera no es necesario crear un archivo temporal en el sistema de archivos para escribir la página antes de cargarla en el control Image, ves que fácil es?
Una vez que el stream se haya escrito, se le asigna al control Image usando un BitmapImage. Esta clase es capaz de cargar el contenido del stream y luego establecer como fuente propia de la imagen.
Cuando el usuario presiona los botones de atrás y adelante, obviamente el usuario avanzará o retrocederá en el documento, la lógica de estos botones es simplemente evaluar la actualización del índice actual y comprobar que se encuentra dentro de los límites de la propiedad PageCount del documento.

Implementando un simple Zoom

La clase PdfPage no sólo permiten convertir las páginas a un Bitmap, sino que también es capaz de hacer zoom y mostrar pequeñas partes de la página y luego presentarlas en un Bitmap sin perder definición. Para implementar el zoom se puede aumentar simplemente el valor de las propiedades DestinationHeight y DestinationWidth en la clase PdfPageRenderOptions. Esta clase se hizo para cambiar el comportamiento predeterminado del proceso de renderización y tienen una serie de propiedades que influye en cómo se produce este proceso. Si modificas las dos propiedades te permite determinar el tamaño del Bitmap de salida por lo que la imagen resultante será mayor.
En el siguiente punto implementaré una "extraña" forma de Zoom eso no es lo mejor para una buena experiencia del usuario, pero me dejará mostrarles que en una sola porción de código se puede hacer trabajar juntos, tanto recorte y zoom. Empecemos agregando unos cuantos botones:

Estos son los botones de zoom-in y zoom-out, junto a otros 4 botones que se utilizan para desplazar el zoom sobre todo el tamaño de la página. El zoom siempre tendrá el tamaño de página completa, sino que funcionará como un visor en una parte de la página. Los botones con flechas te permiten desplazar la vista en la superficie de la imagen:

Después que hemos creado la lógica del botón de desplazamiento, es el momento de implementar el método RenderPage. Esto hará recortar una sola parte de la página sobre la base del zoom actual.

El método RenderPage funciona de forma diferente cuando la propiedad ZoomFactor es diferente a 1,0 (sin zoom). A continuación, crea una instancia de la clase PdfPageRenderOptions y establece las propiedades DestinationWidth y DestinationHeight al tamaño de toda la página. Entonces, usando la propiedad SourceRect establece un rectángulo de un tamaño reducido, y el resultado se representa en la imagen. Esto hace que el zoom se muestre sin perder la calidad.

Pruébalo tú mismo

Puedes descargar este ejemplo aquí.
Ah! El espacio de nombres Windows.Data.Pdf te permite añadir algunas características interesantes a tus aplicaciones, pero por favor no esperes mucho de este espacio de nombre, ya que es un conjunto de herramientas muy limitado, esperemos que lo mejoren en futuras versiones, Microsoft siempre trata bien a sus desarrolladores ;).
Nos leemos pronto.

Un chico con una gran experiencia en el arte del desarrollo software. Desarrollador de aplicaciones de móviles, especialista en ASP.Net, Xamarin y tecnologías de computo en la Nube en especial Azure.

Comentarios