sábado, setiembre 24, 2016

Condensation (Particle Filters) - OpenCV

Después de muchas semanas analizando el algoritmo de "Condensation" de OpenCv, y tratando de portar el mismo a Python, sin resultados satisfactorios, debido a que no había convergencia de las partículas y los resultados eran insatisfactorios vine a dar con esta entrada en el foro de OpenCV Aquí donde recomendaban la lectura de este artículo link que resulto siendo bastante explicativo, con eso en mente, volví a buscar el fuente de OpenCV para intentar portar nuevamente a Python el código y encontré está versión en el repositorio de Android aquí.
En ese fuente la forma de obtener las nuevas partículas cambia, es mucho más simple que la versión legacy de OpenCv y con eso finalmente lo pude portar a Python con resultados satisfactorios.


El código de Python está disponible en GitHub, requiere Python >=2.7 con Numpy >=1.10.1 y OpenCV >= 2.4.11

sábado, noviembre 17, 2012

Applet para la impresión silenciosa en el Web Browser del cliente

Necesitaba hacer un programa que haga la impresión silenciosa (sin interacción del usuario) de un reporte en la PC del cliente desde una aplicación Web. El reporte fue generado con JasperReports y exportado a PDF, sin embargo, después de semanas de buscar en Google no encontré una solución que cumpla con lo que necesitaba. Así que reuniendo información y ejemplos de diferentes lugares pude desarrollar esta aplicación que la dejo aquí por si alguien más la necesita, así se pueden ahorrar las semanas de tiempo que invertí.

Por motivos de seguridad java no permite que una aplicación Web tenga acceso a los recursos locales (impresión, archivos, etc.) para esto se requiere de un plugin, o como en nuestro caso de un applet.

Para comenzar, nuestro reporte fue generado usando JasperReports 4.5.1 y exportado a PDF a una carpeta local de nuestro servidor. Nuestra aplicación Web, usa Tomcat y hemos creado un servlet que va a permitir hacer la descarga del PDF, por ultimo un HTML ejecuta el applet y permite hacer la impresión sin la intervención del usuario.

Este es nuestro Servlet que va a enviar el PDF al cliente.

package pe.com.example.servlet;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class PrintReportServlet extends HttpServlet {

private static final long serialVersionUID = 1L;
public PrintReportServlet(){
super();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGetAndDoPost(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGetAndDoPost(request, response);
}

private void doGetAndDoPost(HttpServletRequest request, HttpServletResponse response){

File file = null;

try{
file = new File("C:\temp\archivo.pdf");

if(!file.exists())
return;

ServletContext context = getServletConfig().getServletContext();
String mimetype = context.getMimeType("C:\temp\archivo.pdf");
response.setContentType( (mimetype != null) ? mimetype : "application/octet-stream" );
response.setContentLength( (int)file.length() );
//response.setHeader( "Content-Disposition", "attachment; filename=\"" + output + "\"" );

OutputStream op = response.getOutputStream();

int length = 0;
byte[] bbuf = new byte[1024];
DataInputStream in = new DataInputStream(new FileInputStream(file));

while ((in != null) && ((length = in.read(bbuf)) != -1)){
op.write(bbuf,0,length);
}

in.close();
op.flush();
op.close();

}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}finally{
if(file != null && file.exists())
file.delete();
file = null;
}
}

}


Ahora lo que necesitamos es el código del Applet que se va a encargar de llamar al servlet y de lanzar la impresión.

Lo primero que hacemos es la lectura del archivo para esto usamos DataInputStream y ByteArrayOutputStream para hacer la lectura del archivo y guardarla en memoria. Una vez con el archivo, buscamos las impresoras que tenemos disponibles usando PrintService y PrintServiceLookup, en mi caso busco la impresora de nombre "HP Deskjet 2050 J510 series" que es donde voy a dirigir la impresión.

Una vez obtenida la impresora necesitamos un PrinterJob, que se encarga de hacer la impresión de componentes AWT. En mi caso configuro también la página en tamaño A4. Para un mayor detalle de las clases de impresión, pueden consultar aquí.

Nuestro Applet implementa la interface Printable, y se debe definir el método public int print (Graphics g, PageFormat format, int index) throws PrinterException que se encarga de hacer la impresión de los componentes AWT del applet.

Aquí es donde entra en juego las librerías de PDFRenderer-0.9.1.jar que está disponible aquí. Sucede que algunas impresoras permiten que se les envíe un documento PDF para impresión, en ese caso no necesitamos usar la clase PrinterJob ni definir el método print, bastaría con crear un objeto de tipo DocPrintJob y hacer la carga del PDF y enviarlo a impresión, como ese no es nuestro caso (la impresora no acepta PDF) debemos de cargar el PDF dentro del applet y dibujarlo dentro de los componentes del applet, eso es lo que hace PDFRenderer, se encarga de dibujar el PDF en los componentes AWT, una vez que se ha cargado y dibujado el PDF, enviamos a imprimir el componente en el cual se dibujo el PDF, en resumen, es eso lo que hacemos.

Este es el código del Applet:



package pe.com.example.applet;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import com.sun.pdfview.PDFRenderer;

/**
* Applet para la impresion de archivos en formato PDF en modo silencionso en
* la PC del cliente
* Requiere de las librerias de PDFRenderer-0.9.1.jar que puede encontrarse en
* http://java.net/projects/pdf-renderer/downloads
*
* Los archivos fueron generados con JasperReports y exportados a PDF. Imprimir
* desde el HTML generaba algunos errores de formato o posición de los elementos
* sobre todo al imprimir sobre formatos pre-impresos (facturas, recibos, etc.)
* por esa razón se eligió exportarlos a PDF e imprimirlos desde ahí.
*
* Se requiere de un servlet que envié el archivo PDF al cliente, este lo recibe
* como un array de Bytes y lo envía a Imprimir en la impresora definida.
*
* Basado en los siguientes ejemplos
* http://www.javaworld.com/javaworld/jw-06-2008/jw-06-opensourcejava-pdf-renderer.html?page=1
* http://publicajava.blogspot.com/
*
* Información de la impresion en Java
* http://docs.oracle.com/javase/6/docs/technotes/guides/jps/spec/JPSTOC.fm.html
*
* @author corosco
*
*/
public class PrintApplet extends javax.swing.JApplet implements Printable {

private static final long serialVersionUID = 3325035839231751544L;

PDFFile pdfFile;

/** Initializes the applet AppletPrint */
public void init() {
try {
//URL del servlet que debe llamar para recibir el archivo PDF
this.urlService = getParameter("urlService");

java.awt.EventQueue.invokeAndWait(new Runnable() {
public void run() {
initComponents();
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}


private void initComponents() {

jPanel1 = new javax.swing.JPanel();
jBtnImprimir = new javax.swing.JButton();

setLayout(new java.awt.BorderLayout());

//Opcional, puede mostrarse una ventana con un botón para imprimir
jBtnImprimir.setText("Imprimir");
jBtnImprimir.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jBtnImprimirActionPerformed(evt);
}
});

//jPanel1.add(jBtnImprimir);

add(jPanel1, java.awt.BorderLayout.CENTER);

}

private void jBtnImprimirActionPerformed(java.awt.event.ActionEvent evt) {
comunicacionServer();//para recibir los datos del server
}


// Variables declaration - do not modify
private javax.swing.JButton jBtnImprimir;
private javax.swing.JPanel jPanel1;
// End of variables declaration

//Guardara la url del servlet al que se comunicara para imprimir
private String urlService;

private void comunicacionServer(){

//long tamFile=0;

/* Primero creamos la URL para la conexión. Tiene sentido construir la
dirección de esta forma tan "complicada" puesto que el applet solo puede
establecer conexiones con su servidor, y así, al construir la dirección
dinámicamente, no tenemos que retocar el código al irnos a otro servidor.
En todo caso, lo siguiente sería válido:
URL direccion = new URL ("http://www.javahispano.com/servlet/MiServlet");
*/
URL pagina = this.getCodeBase();
String protocolo = pagina.getProtocol();
String servidor = pagina.getHost();
int puerto = pagina.getPort();
String servlet = "";

if ( this.urlService != null && !this.urlService.equals(""))
servlet = this.urlService;
else
servlet = "/example/printReport";

URL direccion = null;
URLConnection conexion = null;
try {
direccion = new URL(protocolo, servidor, puerto, servlet);
conexion = direccion.openConnection();
System.out.println(" Url del Servlet: " + direccion.toString());
} catch (IOException ex) {
ex.printStackTrace();
}

/*Lo siguiente es decirle al navegador que no use su
cache para esta conexión, porque si lo hace vamos a
tener un página estatica, y para eso no nos metemos
en estos líos ;-). */
conexion.setUseCaches(false);

/* Ahora añadimos todas las cabeceras de HTTP que necesitemos, Cookies, contenido,
autorizacion, etc. con el método:
conexion.setRequestProperty ("cabecera", "valor");
Consultar la especificación de HTTP para más detalles. Por ejemplo, para decir
que preferentemente hablamos español: */
conexion.setRequestProperty("Accept-Language", "es");

try {


/* Procesamos la información de la forma adecuada, según se
trate de datos ASCII o binarios.
Obtenemos el stream de entrada para leer la informacion que nos envie el
server*/
System.out.println("Obteniendo DataInputStream");
DataInputStream dataIn = new DataInputStream(conexion.getInputStream());

// Recibo el numero de archivos que enviara el servidor
//int numArchivosRecibir = dataIn.readInt();
//Recibo un unico archivo
int numArchivosRecibir = 1;
System.out.println(" Numero de archivos para imprimir " + numArchivosRecibir);

// Recibe los archivos
/*String nameFiles[] = new String[numArchivosRecibir];
File f = null;
File files[] = new File[numArchivosRecibir];
FileOutputStream outputStream = null;*/
ByteArrayOutputStream outputStream = null;

System.out.println("lectura del archivo");
for(int k = 0; k < numArchivosRecibir; k++){

outputStream = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
int len;

while ((dataIn != null) && ((len = dataIn.read(buf)) != -1)){
outputStream.write(buf,0,len);
}

/*
* Si tenemos varias impresoras configuradas se hace una busqueda
* de las impresoras
*/
DocFlavor psInFormat = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
PrintService[] services = PrintServiceLookup.lookupPrintServices(psInFormat, aset);

// this step is necessary because I have several printers configured
PrintService myPrinter = null;
for (int i = 0; i < services.length; i++){

String svcName = services[i].toString();
System.out.println("service found: " + svcName);
//Cambiar el nombre de la impresora
if (svcName.contains("HP Deskjet 2050 J510 series")){
myPrinter = services[i];
System.out.println("my printer found: "+svcName);
break;
}
}

ByteBuffer buff = ByteBuffer.wrap(outputStream.toByteArray());

pdfFile = new PDFFile(buff);

if (myPrinter != null) {
PrinterJob job = PrinterJob.getPrinterJob ();

//Se le asigna la impresora configurada
job.setPrintService(myPrinter);
try {

PageFormat pf = job.defaultPage();
Paper paper = new Paper();
paper.setSize(595, 842); //A4
paper.setImageableArea(72, 72, 523, 770);
pf.setPaper(paper);
job.setPrintable(this, pf);
job.print();

} catch (Exception pe) {
pe.printStackTrace();
}
} else {
System.out.println("no printer services found");
}

outputStream.close();

}

/* Y finalmente cerramos la conexión. */

dataIn.close();
dataIn = null;
outputStream = null;

} catch (PrinterException e) {
e.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}

/**
* Método que será ejecutado desde JavaScript para lanzar la impresion
*
* @param urlConParametros ruta del servlet que envía el PDF
*/
@SuppressWarnings("unchecked")
public void ejecutaConJavascript (final String urlConParametros){

AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
comunicacionServer(urlConParametros);
} catch(Exception e) {
e.printStackTrace();
return false;
}
return null;
}
});
}

public void comunicacionServer(String urlConParametros) {
this.urlService = urlConParametros;
this.comunicacionServer();
}

/**
* Método para realizar la impresión
* Las clases de PDFRenderer se encarga de dibujar el PDF en AWT y
* se lanza para impresión está ventana, se hace de esta forma porque
* no todas las impresoras aceptan directamente un archivo PDF para
* impresión.
*
* @param g
* @param format
* @param index
*/
public int print (Graphics g, PageFormat format, int index) throws PrinterException
{
int pagenum = index+1;
if (pagenum < 1 || pagenum > pdfFile.getNumPages ())
return NO_SUCH_PAGE;

Graphics2D g2d = (Graphics2D) g;
AffineTransform at = g2d.getTransform ();

PDFPage pdfPage = pdfFile.getPage (pagenum);

Dimension dim;
dim = pdfPage.getUnstretchedSize ((int) format.getImageableWidth (),
(int) format.getImageableHeight (),
pdfPage.getBBox ());

Rectangle bounds = new Rectangle ((int) format.getImageableX (),
(int) format.getImageableY (),
dim.width,
dim.height);

PDFRenderer rend = new PDFRenderer (pdfPage, (Graphics2D) g, bounds,
null, null);
try
{
pdfPage.waitForFinish ();
rend.run ();
}
catch (InterruptedException ie)
{
System.out.println(ie.getMessage());
}

g2d.setTransform (at);

return PAGE_EXISTS;
}


}


En nuestra aplicación debemos de crear una carpeta bajo el directorio Web, donde debemos de colocar los jar que contienen las clases del applet y de la librería de PDFRenderer, en mi caso he creado WebContent\resources\applet y dentro de esta carpeta he copiado los archivos appletPrintReport.jar y PDFRenderer-0.9.1.jar, el archivo appletPrintReport.jar contiene unicamente la clase pe.com.example.applet.PrintApplet. Los dos applets han sido firmado digitalmente, ya que de lo contrario aparece un mensaje de advertencia de seguridad en el Browser del cliente, para firmar el applet usan el siguiendo comando de java:

C:\> jarsigner appletPrintReport.jar certkey

Donde certkey es la clave que se ha generado usando el keytool de java. Como generar la clave, lo pueden consultar "aquí.

Para el caso del jar PDFRenderer-0.9.1.jar, antes de firmarlo debemos desempaquetarlo, puede ser con el WinRar, extraer el contenido y buscar el archivo MANIFEST.MF que está en la carpeta META-INF, dentro de ese archivo debemos de agregar está linea:

Trusted-Library: true

Sucede que esa librería tiene algunos recursos que no se firman digitalmente, razón por la cual cuando se carga el applet lanza una advertencia de seguridad informando que se está cargando código mixto seguro e inseguro. Ese detalle lo encontré después de Googlear aquí y aquí. Una vez que adicionan la línea vuelven a empaquetar el contenido usando el WinRar, pero en formato ZIP, cuando se ha generado el .ZIP, le cambian la extensión a .JAR y lo firman digitalmente como se indicó arriba.

Por ultimo necesitamos un HTML que cargue el applet, para eso usamos este HTML, que carga una pequeña ventana de 100x100 y después de 5 segundos de finalizada la impresión se cierra.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<script type="text/javascript" language="JavaScript">
function ejecutoApplet() {
//aqui hay que mandarle el nombre que le dimos al applet
var Myapplet = document.applets['nomApplet'];
//alert(Myapplet);
var p = Myapplet.ejecutaConJavascript('/example/printReport');
//alert(p); //si el metodo del applet retorna algo con esto podemos ver el resultado

window.setInterval(function(){window.close()},5000);
}
</script>
<body onload="ejecutoApplet();">
<applet name="nomApplet" CODEBASE="resources/applet/"
code="pe.com.example.applet.PrintApplet"
archive="appletPrintReport.jar,PDFRenderer-0.9.1.jar"
width="10" height="10">
<param value="/example/printReport" name="urlService">
</applet>
</body>
</html>



Listo, eso sería, para poder desarrollar esa aplicación me base en estos dos ejemplos:

http://www.javaworld.com/javaworld/jw-06-2008/jw-06-opensourcejava-pdf-renderer.html?page=1
http://publicajava.blogspot.com/2009/10/imprimir-reporte-de-jasperreports-en-el.html

Subiré los fuentes y el ejemplo junto con algunas imagenes más tarde. Lo dejo ese ejemplo por si a alguien más le sirve.

Actualización: Sigue anexo el link con los archivos del proyecto: link Si están usando Java 7, puede aparecer un mensaje indicando que se está bloqueando la aplicación, de ser asi agregar la ruta de la aplicación (http://localhost:8080/PrintApplet/printApplet.html) a las excepciones de Java en el panel de Control. Pueden encontrar un detalle aquí

jueves, agosto 05, 2010

Humor en el #juevesfilosofico

"Es mejor vestid@ y alborotad@ que desnud@ y olvidad@"

"Cuando una mujer sufre en silencio, es que le cortaron el teléfono"

"La vida sexual del hombre atraviesa tres etapas: sin pagar, pagando y... ni aunque pague"

"La vida sexual de la mujer igual atraviesa tres etapas, Ay que me duele, Ay que rico, hay q pintar el techo"

"La vida es como un moco: intragable, dura y a veces no te deja respirar"...

"Lo único bueno que tiene la muerte: son la viudas"!!!

"Ligar es el arte de hacer caer a una mujer (o a un hombre) en tus brazos, sin caer en sus manos"


Visto en @GomisGomis

martes, agosto 03, 2010

¿Perú, Camino al primer mundo en el 2028?

“¿Camino al primer mundo?” es el título de un artículo que publica hoy el diario gestión, de Javier Portocarrero en el que muestra un alentador panorama. De continuar la racha de crecimiento que mantiene el Perú y crecer a un nivel de 6% en los próximos 18 años, el Perú llegaría a ser un país del primer mundo para el año 2028, por lo menos en cifras.

Esta afirmación se basa en las mediciones de niveles de ingresos del Banco Mundial, que establece como países de ingresos bajos aquellos que tiene un ingreso bruto per cápita  menor a US$ 996. Los de ingreso medio bajo hasta los US$ 3,945, los del grupo medio alto hasta los US$ 12,195 y los de ingresos altos, los que superan esa cifra. El Perú se encuentra actualmente en los de ingreso medio alto, al haber alcanzado ingresos de US$ 3990 en el 2008.

La cifra de crecimiento de 6% parece razonable a raíz de las últimas cifras de crecimiento dadas por el INEI, más aún cuando se espera que para junio se pudiera haber dado un crecimiento que supera los dos dígitos, impulsados por el avance en el sector construcción e hidrocarburos.

Será el 2028 el Perú un país del primer mundo, aún es difícil saberlo, quiero soñar que si.

sábado, julio 24, 2010

INICTEL-UNI ofrece cursos gratuitos a los afectados por la crisis internacional

El día de ayer 23 de julio estuvimos presente en la conferencia de seguridad organizada por INICTEL-UNI durante un breve receso de la misma se anunció que se están ofreciendo cursos gratuitos a aquellos que han resultado afectados con motivo de la crisis internacional, ya sea porque perdieron sus puestos de trabajo o porque su nivel de ingresos se vio reducido, en cualquiera de ambos casos pueden aplicar para estos cursos, que por cierto están muy interesantes.

Entre ellos destacan:

  • Administración de Servidores Linux
  • Software/Hardware para el Desarrollo de Aplicaciones Interactivas para la Televisión Digital Terrestre - Estándar ISDB-T
  • Diseño Gráfico Publicitario
  • Redes Certificadas Cisco - CCNA
La crisis ahora puede ser una buena excusa para estudiar, y al contrario no hay excusa para no hacerlo, es gratis.

Más información en INICTEL-UNI

miércoles, julio 21, 2010

INICTEL-UNI: Seminario de Seguridad de la Información

El viernes 23 de julio INICTEL-UNI orga­ni­za el evento “Sem­i­nario: Seguri­dad de la Infor­ma­ción”



Día: Viernes 23 de julio del 2010
Hora: 6:00 a 10:00 pm
Lugar: Audi­to­rio CECOI – Av. San Luis 1771 San Borja
Ingreso Libre
Inscrip­ción On Line:
http://www.inictel-uni.edu.pe/modulos/EVENTSYS/iu/registro/iu_registro.php

 

miércoles, julio 07, 2010

Delfín y fotógrafo




Impresionante imágen, no se a ustedes pero a mi me da la impresión que el delfín se volvió transparente, y en realidad no sucede tal cosa, es el fotografo el que se ve reflejado en el agua.

Vía Amazing.es