jueves, 10 de noviembre de 2011

Optimizar imágenes PNG en Linux

Hola.

Resulta que necesitaba utilizar una gran cantidad imágenes PNG en una aplicación por el rollo de las transparencias y tan solo 10 de estas imágenes pesaban 37MiB, después de la compresión: 8.5MiB.

Buscando un poco te encuentras con bastantes aplicaciones que se dedican a ¿comprimir?/cuantizar/optimizar imágenes en formato PNG, pero la única aplicación que reducía el tamaño en disco así de bien y sin que se notaran grandes cambios (37MiB->8.5MiB) fue pngnq.

Primero vamos a instalarlo, si te encuentras en Debian o derivados:
$ sudo apt-get install pngnq
En la página recomiendan utilizarlo junto a pngcrush de esta forma:
pngnq -n 256 image.png && pngcrush image-nq8.png smallimage.png
he intentado utilizar la línea de arriba, pero obtengo los mismos resultados sin pngcrush, entonces yo lo utilizo así:
$ pngnq image.png -d directorioSalida
lo que genera un nueva imagen llamada image-nq8.png en el directorio especificado.

Pero si como yo necesitan realizar el mismo proceso sobre muchas imágenes y además quieren mantener los nombres de las imágenes sin el -nq8 este script medio cutre, es el primero que hago en python les podría ayudar:

#!/usr/bin/python

import sys
import os
import glob

from subprocess import Popen, PIPE

def check_execs(*progs):
    """Check if the programs are installed, if not exit and report."""
    for prog in progs:
        try:
            Popen([prog, '--help'], stdout=PIPE, stderr=PIPE)
        except OSError:
            msg = 'The {0} program is necessary to run this script'.format(prog)
            sys.exit(msg)
    return


def listDirectory(directory, fileExt):                                       

 directorioOriginal = os.getcwd()
 directorio = os.path.join(os.pardir, directory)

 if os.path.isdir(directorio):
  os.chdir(directorio)
  lista = glob.glob("*."+fileExt)
  os.chdir(directorioOriginal)
  return lista

def renameImagePngnq(image, directory):

 currentDir = os.getcwd();
 os.chdir(os.path.join(os.pardir, directory))
 (name, extension) = os.path.splitext(image)

 if extension == ".png":
  newName = name[:-4] + extension
  os.rename(image, newName)

 os.chdir(currentDir)

 
check_execs("pngnq")

# Obteniendo directorio
path = os.getcwd()
if len(sys.argv) == 2:
 path = sys.argv[1]

# Obteniendo lista de archivos
lista = listDirectory(path, "png")

# creando directorio de salida
out = path + "/optimizadas"
if not os.path.exists(out):
  os.mkdir(out)

os.chdir(path)

for imagen in lista:
 os.system("pngnq " + imagen + " -v -d " + out)
 print "\n\n"

print "Renombrando ficheros..." 
os.chdir(out)
for img_nq8 in listDirectory(out, "png"):
 renameImagePngnq(img_nq8, out)
 
print "Bye..." 
lo guardamos con un nombre creativo como optimiza_png.py, le damos permisos de ejecución y lo ejecutamos de la siguiente forma:
$ chmod +x optimiza_png.py
$ ./optimiza.png /directorio/con/imagenes/png
si omitimos el segundo parámetro el directorio que tomará por defecto para buscar imágenes png será el directorio donde estamos ejecutando el script. El script creará una carpeta llamada optimizadas con las imágenes procesadas por pngnq.

viernes, 4 de noviembre de 2011

Instalar JEE con Glassfish en Debian

Hola.

Vamos a instalar JEE (Java Enterprise Edition) con Glassfish para comenzar a ver de que van los JSP, Servficios Web...

Primero descargamos el paquete que nos convenga de la página oficial, por ejemplo elegimos Java EE 6 Development Kit Bundles without JDK/Java EE 6 SDK Update 3 ya que viene con GlassFish Open Source Edition 3.x.x y después seleccionamos java_ee_sdk-6u3-unix-ml.sh (multilenguaje).

Damos permisos de ejecución e instalamos:
$ chmod +x java_ee_sdk-6u3-unix-ml.sh
$ sh java_ee_sdk-6u3-unix-ml.sh
en el asistente elegimos Instalación típica (en Instalación personalizda podemos configurar una instalación existente) y el directorio de instalación sugerido es en la carpeta personal (por ejemplo /home/oscar/glassfish3). Si todo va bien al terminar la instalación tendremos configurado Glassfish, en el puerto 4848 para administración y el 8080 para exponer aplicaciones web (si ya tienes alguno de estos puertos ocupados, entonces elige la opción de Instalación personalizada para asignar puertos).
Para parar e iniciar Glassfish debemos ejecutar los siguientes comandos:
$ /home/TU_USUARIO/glassfish3/bin/asadmin stop-domain
$ /home/TU_USUARIO/glassfish3/bin/asadmin start-domain
pero como eso no nos gusta mejor creamos un script en /etc/init.d/, entonces hacemos lo siguiente:
# nano /etc/init.d/glassfish
del siguiente script modificamos la línea asadmin="/home/oscar/glassfish3/bin/asadmin" según nuestra instalación.
#!/bin/bash

asadmin="/home/oscar/glassfish3/bin/asadmin"

case $1 in
start)
sh $asadmin start-domain
;;
stop)
sh $asadmin stop-domain
;;
restart)
sh $asadmin restart-domain
;;
*)
#Default case: restart de daemon
sh $asadmin restart-domain
;;
esac
exit 0
guardamos, damos permisos de ejecución y probamos:
# chmod +x /etc/init.d/glassfish
# service glassfish stop
# service glassfish start
# service glassfish restart
y listo.

martes, 1 de noviembre de 2011

Habilitar/deshabilitar componentes de un Panel en Java

Hola.

En ocasiones sucede que necesitamos deshabilitar todos los componentes de un JPanel o un JFrame por alguna razón. Además tenemos botones, etiquetas, sliders, cajas de texto... y tenemos que hacer por cada componente setEnable(true/false), pero como buenos programadores esa opción no nos agrada, así que buscamos y el buen Google nos da la solución rápidamente:

@Override
public void setEnabled(boolean en) {
    super.setEnabled(en);
    setComponentsEnabled(this, en);
}
private void setComponentsEnabled(java.awt.Container c, boolean en) {
    Component[] components = c.getComponents();
    for (Component comp: components) {
        if (comp instanceof java.awt.Container)
            setComponentsEnabled((java.awt.Container) comp, en);
        comp.setEnabled(en);
    }
}

esto lo que hace es sobreescribir el método setEnabled() del componente de tal forma que cuando se llame al método primero se activará/desactivará el propio componente y posteriormente habilita/deshabilita todos los componentes en él con la llamada a setComponentsEnabled.

Pero esto de pegar el par de métodos en cada componente como que no parece lo mejor, porque no mejor hacer lo siguiente:

public static void setEnableContainer(Container c, boolean band) {
        
 Component[] components = c.getComponents();
 c.setEnabled(band);
 for(int i = 0; i < components.length; i++){            
  components[i].setEnabled(band);
  
  if(components[i] instanceof Container){
   setEnableContainer((Container)components[i], band);
  }
  
 }        
} 
 así podemos dejar el método digamos en una clase SwingUtils y cuando necesitemos habilitar/deshabilitar un componente y todos sus hijos únicamente haríamos una llamada así:

SwingUtils.setEnableContainer(miComponente, true);
SwingUtils.setEnableContainer(miComponente, false); 

y listo.

SwingUtils.java