Para seleccionar un archivo desde una aplicación Java e imprimirlo, una opción práctica consiste en abrir un selector mediante `JFileChooser` y enviar el archivo seleccionado a la aplicación predeterminada del sistema operativo con `Desktop.getDesktop().print(file)`. Esta alternativa permite imprimir documentos existentes, como archivos de Microsoft Word o PDF, utilizando el programa asociado al formato.
Si se necesita controlar directamente el contenido impreso, el formato de página o el proceso de impresión, Java proporciona `PrinterJob`, `Printable` y `PageFormat`. En cambio, si el archivo ya existe y debe conservarse tal como fue creado por Microsoft Word, Excel o un lector de PDF, normalmente es más adecuado delegar la interpretación del documento en la aplicación instalada en el sistema.
Seleccionar un archivo con JFileChooser e imprimirlo
La clase `JFileChooser` permite mostrar una ventana para que el usuario seleccione un archivo. Una vez seleccionado, el objeto `File` se puede enviar al método `print` de la clase `Desktop`.
Dentro del paquete AWT de Java (herramienta de Java para hacer aplicaciones de escritorio), desde Java 6, existe una clase que nos permite acceder a diferentes funcionalidades del sistema operativo en el que se está ejecutando el programa, aunque no permite ningún tipo de configuración.
Lo que hace este código es invocar a la aplicación por defecto que haya instalada en el sistema (Microsoft Word para .docx por ejemplo) y llamar directamente al comando imprimir. Es la reponsabilidad del sistema operativo elegir el programa con el que lo va a abrir y elegir la impresora y los settings seleccionados por defecto.
El siguiente ejemplo combina la selección del archivo y la impresión:
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
public class SeleccionarEImprimir {
public static void main(String[] args) {
JFileChooser selector = new JFileChooser();
int resultado = selector.showOpenDialog(null);
if (resultado == JFileChooser.APPROVE_OPTION) {
File archivo = selector.getSelectedFile();
try {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.PRINT)) {
Desktop.getDesktop().print(archivo);
} else {
JOptionPane.showMessageDialog(null, "La impresión no está disponible.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
El código para imprimir un fichero de Microsoft Word ubicado en c:\Documentos\fichero.docx podría ser el siguiente:
package printjava;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
public class PrintJava {
public static void main(String[] args) throws IOException {
File fileToPrint = new File("c:\\Documentos\\fichero.docx");
Desktop.getDesktop().print(fileToPrint);
}
}
Qué ocurre cuando se utiliza Desktop.print
Al llamar a `Desktop.getDesktop().print(archivo)`, Java no interpreta por sí misma el contenido del documento. El sistema operativo identifica la aplicación asociada con la extensión del archivo y ejecuta su acción de impresión.
Por ejemplo, un archivo `.docx` puede abrirse con Microsoft Word y un archivo PDF puede abrirse con el lector de PDF configurado como predeterminado. La aplicación asociada se encarga de interpretar el documento y enviarlo a la impresora.
El problema radica en que no se puede indicar a qué impresora queremos imprimir el documento, y tampoco algunos settings que podríamos utilizar. Parece una opción demasiado básica. Además tampoco hay mucho control sobre la cola de impresión.
Ventajas y limitaciones de la impresión con Desktop
- Permite seleccionar un archivo mediante una interfaz gráfica.
- Utiliza la aplicación predeterminada del sistema operativo.
- Es apropiado para documentos existentes que deben conservar su formato.
- No permite elegir programáticamente la impresora de destino.
- No proporciona un control detallado sobre la cola de impresión.
- La aplicación asociada al tipo de archivo debe estar instalada y configurada.
La solución es especialmente útil cuando el objetivo es imprimir un documento existente sin reconstruirlo desde Java. Si el documento contiene elementos complejos, la aplicación que lo creó puede interpretarlo con mayor fidelidad que una biblioteca genérica.
Filtros de archivos en JFileChooser
El selector puede limitarse a determinados formatos para evitar que el usuario elija archivos que no puedan imprimirse con las aplicaciones instaladas.
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
JFileChooser selector = new JFileChooser();
FileNameExtensionFilter filtro = new FileNameExtensionFilter(
"Documentos Office y PDF",
"doc", "docx", "xls", "xlsx", "pdf"
);
selector.setFileFilter(filtro);
El código permite presentar al usuario una lista de extensiones relacionadas con documentos de Office y PDF. La impresión final seguirá dependiendo de la aplicación asociada a cada extensión.
Imprimir un documento con PrinterJob y Printable
Cuando el contenido que se va a imprimir se genera desde Java, la API `PrinterJob` ofrece un modelo más flexible. Para usar el objeto PrinterJob deberemos tener un objeto Printable que será el que contendrá lo que queremos imprimir.
Este objeto debe contener la función print donde indicaremos la información que nos interesa imprimir. Esta información será dibujada sobre un objeto Graphics (que luego pasaremos a Graphics2D) o Graphics2D (la impresión en Java, al menos versones anteriores es un trabajo gráfico, de ahí su lentitud).
Después crearemos el objeto PrinterJob, mediantesetPrintable(objeto_a_imprimir) haremos que se dibuje la página a mandar a la impresora. Llamaremos o no, a la ventana de configuración de impresión, y por último imprimiremos.
El esquema básico es el siguiente:
import java.awt.Graphics;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
class ObjetoAImprimir implements Printable {
public int print(Graphics g, PageFormat f, int pageIndex) {
if (pageIndex == 0) {
g.drawString("Contenido para imprimir", 100, 100);
return PAGE_EXISTS;
}
return NO_SUCH_PAGE;
}
}
public class Imprime {
public static void main(String[] args) {
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(new ObjetoAImprimir());
if (job.printDialog()) {
try {
job.print();
} catch (PrinterException e) {
System.out.println("Error de impresión: " + e);
}
}
}
}
Para pasar una instancia de la clase que implementa la interfaz Printable, hacia el PrintJob se usa el siguiente metodo:
job.setPrintable(new PrintObject());
Funcionamiento de Printable
El rol de un objeto que implementa esta interfaz es el de formatear una página en blanco que ha recibido de un PrintJob, simplemente lo hace y retorna un código de estado indicando si tuvo éxito.
El PrintJob llamará a este objeto una o más veces para cada página que se deba imprimir. Así el PrintJob nunca sabe cuantas páginas imprimirá en total.
class PrintObject implements Printable {
public int print(Graphics g, PageFormat f, int pageIndex) {
if (pageIndex == 0) {
g.drawString("1", 100, 100);
return PAGE_EXISTS;
} else return NO_SUCH_PAGE;
}
}
Este objeto no hace en realidad ningún tipo de impresión, sólo llena la página para que el PrintJob lo imprima. Chequea el índice de página que se le entrega que empieza con 0 y retorna PAGE_EXISTS indicandole al PrintJob que puede imprimirla y retorna NO_SUCH_PAGE para indicarle que deje de imprimir.
Ejemplo de impresión de dos páginas
El siguiente ejemplo imprime un rectángulo en la primera página y una circunferencia en la segunda:
import java.awt.*;
import java.awt.print.*;
import java.awt.geom.*;
class PrintObject implements Printable {
public int print(Graphics g, PageFormat f, int pageIndex) {
Graphics2D g2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(
f.getImageableX(),
f.getImageableY(),
f.getImageableWidth(),
f.getImageableHeight()
);
Ellipse2D circle = new Ellipse2D.Double(100, 100, 100, 100);
switch (pageIndex) {
case 0:
g2.setColor(Color.black);
g2.draw(rect);
return PAGE_EXISTS;
case 1:
g2.setColor(Color.red);
g2.draw(circle);
return PAGE_EXISTS;
default:
return NO_SUCH_PAGE;
}
}
}
public class Sample1 {
public static void main(String[] args) {
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(new PrintObject());
if (job.printDialog()) {
try {
job.print();
} catch (PrinterException exception) {
System.out.println(exception);
}
}
}
}
Seleccionar un archivo y controlar la impresión con PrinterJob
El selector de archivos y `PrinterJob` pueden combinarse. En este caso, el archivo seleccionado se lee y su contenido se dibuja sobre la página mediante `Graphics2D`.
La API de printing, entrega una implementacion concreta de la interfaz Pageable con la clase Book, que es apropiada para la mayoria de las aplicaciones, pero la interfaz puede ser directamente implementada para ajustarse a la estructura interna del documento deseado.
Sin embargo, `PrinterJob` no interpreta automáticamente un archivo `.docx`, `.xlsx` o PDF como lo hacen Microsoft Word, Excel o un lector de PDF. Para esos formatos, el contenido debe convertirse o representarse mediante una biblioteca compatible antes de dibujarlo en la página.
La clase Book y la interfaz Pageable
En vez de usar el metodo setPrintable() para imprimir, es mejor usar setPageable() por que es mas puro y poderoso. La interfaz Pageable le permite a la API solicitar a la aplicacion el numero de paginas a imprimir, y a obtener para cada página una tupla con el PageFormat y el Printable.
Esto le da la habilidad a la API de imprimir las paginas en cualquier orden, multiples veces, con separadores y otras funcionalidades adicionales.
Una vez que se crea una instancia de Book, se le anexan un par de objetos para representar cada página del documento, describiendo las dimensiones y orientacion de la página y el pintor asociado.
Book book = new Book();
book.append(new PrintBlank(), new PageFormat());
printerJob.setPageable(book);
Imprimir texto con PrinterJob
El siguiente enfoque utiliza `Graphics2D` y `LineBreakMeasurer` para dividir el texto en líneas que caben en el área imprimible de la página:
public int print(Graphics g, PageFormat format, int pageIndex) {
Graphics2D g2d = (Graphics2D) g;
g2d.translate(format.getImageableX(), format.getImageableY());
g2d.setPaint(Color.black);
Point2D.Float pen = new Point2D.Float();
AttributedCharacterIterator charIterator = mStyledText.getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(charIterator, g2d.getFontRenderContext());
float wrappingWidth = (float) format.getImageableWidth();
while (measurer.getPosition() < charIterator.getEndIndex()) {
TextLayout layout = measurer.nextLayout(wrappingWidth);
pen.y += layout.getAscent();
float dx = layout.isLeftToRight() ? 0 : (wrappingWidth - layout.getAdvance());
layout.draw(g2d, pen.x + dx, pen.y);
pen.y += layout.getDescent() + layout.getLeading();
}
return Printable.PAGE_EXISTS;
}
Leer archivos con FileInputStream
Las clases FileInputStream y FileOuputStream permiten leer y escribir archivos mediante streams, trabajando con datos binarios y basándose en objetos de tipo File que representan el archivo de lectura y el archivo de escritura.
El código siguiente muestra la estructura básica de lectura y escritura de un archivo con FileInputStream y FileOutputStream mediante un array de bytes.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class CopiarArchivo {
public FileInputStream input;
public FileOutputStream output;
public byte[] b;
public File fileInput, fileOutput;
public CopiarArchivo() {
fileInput = new File("archivo.txt");
fileOutput = new File("archivo2.txt");
}
public void duplicar() {
input = new FileInputStream(fileInput);
output = new FileOutputStream(fileOutput);
b = new byte[(int) fileInput.length()];
input.read(b);
output.write(b);
input.close();
output.close();
}
}
Este mismo ejemplo se puede realizar mediante un while y un dato de tipo entero.
public void duplicar() {
input = new FileInputStream(fileInput);
output = new FileOutputStream(fileOutput);
int b;
while ((b = input.read()) != -1) {
output.write(b);
}
input.close();
output.close();
}
Para copiar un fichero con Java será necesario crear dos objetos de tipo File, los cuales representarán al fichero origen y al fichero destino:
File origen = new File("origen.txt");
File destino = new File("destino.txt");
La idea principal para copiar un fichero con Java será la de abrir un stream de lectura, es decir, un InputStream, sobre el fichero origen, realizar la lectura a la vez que abrimos un stream de escritura sobre el fichero destino, es decir, un OutputStream.
InputStream in = new FileInputStream(origen);
OutputStream out = new FileOutputStream(destino);
Realizamos la lectura y escritura mientras existan datos en el stream de lectura
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
Las lecturas las hacemos mediante el método .read(). Ya solo nos quedará cerrar los stream mediante el método .close() para finalizar el código de nuestro programa.
in.close();
out.close();
Cabe notar que necesitamos controlar la excepción IOException en todo el código. Es por ello, que todo el código lo tendremos en una estructura try-catch.
Control de excepciones al trabajar con archivos
Para poder compilar estos dos códigos anteriores es necesario encerrarlo todo con try-catch obteniendo un archivo duplicado mediante las clases FileInputStream y FileOutputStream.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopiarArchivo {
public FileInputStream input;
public FileOutputStream output;
public byte[] b;
public File fileInput, fileOutput;
public CopiarArchivo() {
fileInput = new File("archivo.txt");
fileOutput = new File("archivo2.txt");
}
public void duplicar() {
try {
input = new FileInputStream(fileInput);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
try {
output = new FileOutputStream(fileOutput);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
b = new byte[(int) fileInput.length()];
try {
input.read(b);
} catch (IOException ex) {
ex.printStackTrace();
}
try {
output.write(b);
} catch (IOException ex) {
ex.printStackTrace();
}
try {
input.close();
} catch (IOException ex) {
ex.printStackTrace();
}
try {
output.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Impresión mediante FileOutputStream
Este objeto es usado habitualmente para crear ficheros. Como el Stream lo podemos redireccionar, en este caso lo enviamos a la impresora, ya sea indicando la ubicación en red, como el puerto en el que está, y a partir de aquí sólo hay que mandar el fujo de datos para que lo reciba la impresora.
Se debe tener en cuenta que en este caso deberemos saber de antemano la ubicación de la impresora y que no será un código portable a otra estación de trabajo ya que puede no tener acceso a la impresora indicada.
El siguiente ejemplo escribe texto en un archivo:
import java.io.FileOutputStream;
import java.io.PrintStream;
public class ImprimeTexto {
public static void main(String[] args) {
try {
FileOutputStream os = new FileOutputStream("nombre_archivo.txt");
PrintStream ps = new PrintStream(os);
ps.println("prueba de impresión realizada");
ps.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Desde windows se puede poner . new FileOutputStream("//Au-4022/hp1100");
Formato UNIX
FileOutputStream os = new FileOutputStream("\\\\Au-4022\\hp1100");
Si tuviesemos la impresora en el puerto paralelo
FileOutputStream os = new FileOutputStream("LPT1:");
Si tuviesemos la impresora en el puerto serie
FileOutputStream os = new FileOutputStream("COM1:");
Impresión mediante PrintService
PrintService es un objeto de la versión 1.4 del JDK. Si se soporta este objeto, es la mejor opción ya que es la más depurada.
Un servicio de impresión puede ser cualquier impresora instalada en la máquina tanto local como en red. Tras crear el objeto de servicio de impresión y asignar una en concreto, crearemos un objeto documento Doc. que contendrá lo que vamos a imprimir.
Este documento puede contener texto, gráficos, etc. simplemente mediante el objeto DocFlavor indicaremos al objeto PrintService que tipo de datos contiene el documento. aunque deberemos comprobar que el servicio de impresión accepte ese tipo de datos (el DocFlavor).
Una vez creado el documento, definido el tipo de datos y rellenados estos datos, se mandará a imprimir.
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
DocPrintJob pj = service.createPrintJob();
String ss = new String("Aquí lo que vamos a imprimir.");
byte[] bytes = ss.getBytes();
Doc doc = new SimpleDoc(bytes, flavor, null);
try {
pj.print(doc, null);
} catch (PrintException e) {
System.out.println("Error al imprimir: " + e.getMessage());
}
Imprimir un objeto Printable mediante PrintService
Usaremos la clase ObjetoAImprimir como en el ejemplo con PrinterObject. ObjetoAImprimir puede ser cualquier objeto que implemente Printable (Applets, Panels,Objetos propios,?)
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
DocPrintJob pj = service.createPrintJob();
Doc doc = new SimpleDoc(new ObjetoAImprimir(), flavor, null);
try {
pj.print(doc, null);
} catch (PrintException e) {
System.out.println("Error al imprimir: " + e.getMessage());
}
Consultar las impresoras disponibles
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
System.out.println("Nombre impresora por defecto: " + service.getName());
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
Tendremos un array con todas las impresoras instaladas y con length podemos saber el nº de impresoras.
System.out.println("Número de impresoras configuradas en el sistema: " + services.length);
if (services.length > 0) {
for (int i = 0; i < services.length; i++) {
System.out.println(services[i].getName());
}
}
Comparación de las alternativas
| Alternativa | Uso principal | Control de impresión |
|---|---|---|
| JFileChooser y Desktop.print | Seleccionar e imprimir documentos existentes | Limitado |
| PrinterJob y Printable | Imprimir gráficos o texto generado por Java | Alto sobre el contenido generado |
| PrintService | Enviar documentos compatibles a una impresora | Permite seleccionar servicios y formatos compatibles |
| FileOutputStream | Enviar datos a un destino conocido | Depende de la ubicación y del formato admitido |
Impresión de documentos Office y PDF en Windows
Imaginemos un caso en el queun cliente nos hace una petición bastante lógica sobre un desarrollo existente. Su intención era que se añadiese, dado un programa de gestión para su empresa realizado en Spring MVC sobre un servidor Tomcat 7, un usuario pudiese imprimir documentos Office y PDF ya existentes en un directorio en la red Windows de la oficina por la impresora que quisera de las configuradas en su red (también Windows).
Todo ello sin intervención desde el ordenador del cliente puesto que tenía que ser una operación automática y no se podían permitir la pérdida de tiempo que supone descargar los documentos e imprimirlos en local.
La orden de impresión debe ser ejecutada desde el servidor, que es un Tomcat 7. Afortunadamente el sistema operativo del servidor es Windows Server.
Los ficheros a imprimir deberían salir con total calidad. Esto es, un Word debe salir tal cual fue escrito con Microsoft Word; lo mismo para Excel o los ficheros PDF.
Por tanto, usar una librería de un tercero para interpretar los ficheros es inviable (Ojo: queremos imprimir ficheros existentes, no generarlos!).
Las impresoras no disponen de un protocolo que podamos emplear fuera de Windows: no disponen de un FTP interno en el que volcar los ficheros y ser ellas las que interpreten los .docx o los .xlsx.
Básicamente debería hacer lo siguiente:
- Localizar el fichero o los ficheros a imprimir.
- Abrir y leer el fichero.
- Imprimir por la impresora indicada por parámetro.
Abrir y leer el fichero. Esto es muy complicado o imposible hacerlo tan bien como Microsoft Word. Podemos usar Apache POI u otra librería, pero seguro que hay algunos casos en los que no va a abrir el fichero correctamente.
Imprimir por la impresora indicada por parámetro. Todas ellas conectadas a una red Windows.
Limitaciones de javax.print para documentos complejos
Si buscamos algo más sin salirnos de Java, podemos encontrar la API de Java Print Service de Java 2D. Concretamente javax.print:
Esta librería nos permite indicar la impresora sobre la que queremos hacer la impresión y algunas de sus características, como tamaño de páginas, páginas a imprimir o buscar las impresoras de la red, así como el tipo de documento (DocFlavor).
La parte negativa para nuestros intereses es que se comunica directamente con la impresora, sin pasar por un programa que interprete el fichero, y sólo soporta algunos tipos comunes de datos como por ejemplo imágenes (JPEG, GIF, PNG…) o documentos en un formato abierto para impresoras como PCL, PDF o PS.
Por tanto al final se trata de un envío de datos directamente a la impresora desde nuestro programa Java, utilizando protocolos de comunicación con la impresora (como PostScript).
Esto es algo demasiado primitivo paa lo que necesitamos, además de no permitirnos interpretar los documentos que no estén en estos formatos estándard y que eran requisito indispensable.
Uso de bibliotecas para interpretar documentos
También pueden utilizarse librerías similares para abrir documentos de Office como la API de Open Office o archivos PDF con la librería PDFBox sin salirnos de Apache.
Como se ha venido diciendo a lo largo de estes tutorial, no es la solución adecuada porque al tratarse los ficheros de Microsoft Office de tecnología propietaria, solamente con sus productos podremos interpretar de forma adecuada el contenido de los ficheros.
Por tanto, descartamos esta opción en nuestro caso ya que los documentos no son generados por la aplicación, sino que son existentes, y además no podemos realizar conjeturas sobre su complejidad para ser tratados por bibliotecas alternativas a Office.
Invocar comandos del sistema operativo desde Java
Otra de las alternativas es desistir de usar librerías de Java para imprimir, y emplear el esfuerzo en aprender a hacer llamadas a los programas específicos que manejan cada tipo de archivos a base de comandos del sistema operativo (en este caso Windows).
Hay diferentes formas para hacer esto. Básicamente habría que, usando la shell de windows (cmd.exe), ser capaz de obtener los comandos necesarios para imprimir por cada tipo de archivo, configurando como mínimo la impresora de destino entre las instaladas en el ordenador en el que se ejecutará el comando (el servidor en este caso).
Hacer una llamada al sistema operativo desde Java no es algo complicado, aunque puede haber problemas de concurrencia, con el número de instancias de Word o simplemente puede que no se cierre el programa abierto (Word):
Runtime.getRuntime().exec("cmd /c start impresionWord.bat");
Esta solución transforma la problemática de imprimir los documentos de Office y PDF en Java en un entorno Windows, a una simple invocación a un comando del RunTime tal y commo podríamos hacer con un fichero .bat.
Por tanto ya tenemos otra alternativa factible.
Impresión con java.awt.Desktop en una red Windows
El código para imprimir un fichero de Microsoft Word ubicado en c:\Documentos\fichero.docx podría ser el siguiente:
File fileToPrint = new File("c:\\Documentos\\fichero.docx");
Desktop.getDesktop().print(fileToPrint);
Lo que hace este código es invocar a la aplicación por defecto que haya instalada en el sistema y llamar directamente al comando imprimir.
El problema radica en que no se puede indicar a qué impresora queremos imprimir el documento, y tampoco algunos settings que podríamos utilizar.
Elección de la técnica adecuada
Para seleccionar un archivo e imprimirlo con una interfaz sencilla, la combinación de `JFileChooser` y `Desktop.print` es la opción más directa.
Para dibujar texto, gráficos o páginas generadas por la aplicación, `PrinterJob` con `Printable` permite controlar el contenido que se entrega a la impresora.
Para consultar impresoras locales o de red y enviar datos en un formato compatible, `PrintService` proporciona una interfaz específica de impresión.
Para documentos Office y PDF ya existentes cuyo diseño debe conservarse, la aplicación asociada al archivo o un comando nativo del sistema operativo puede ser más adecuado que una biblioteca que intente reconstruir el documento.
La API de printing hace llamadas a la aplicación para rasterizar cada banda.
La aplicación interactua con el sistema de impresion por dos razones: para elegir un impresora y generar las páginas impresas.
Elegir la impresora se conoce como Printer Discovery que le permite a la aplicación conseguir un a lista de impresoras diponibles y sus capacidades y elegir una para las siguientes operaciones.
Printer Imaging consiste en el formateo y dibujo de cada página y la conversión de las operaciones de impresion a un formato soportado por la impresoar elegida es el trabajo del Driver de la impresora.
