Hace 15 años | Por afiestas a rooibo.wordpress.com
Publicado hace 15 años por afiestas a rooibo.wordpress.com

img2xhtml es una utilidad para GNU/Linux que dada una imagen, genera un archivo html+css que pinta exactamente la misma imagen contenida en el archivo original, para ello, crea pequeños elementos xhtml de 1 pixel, y utiliza varias técnicas de optimización para reducir su tamaño.

Comentarios

maeghith

#5 qué va, hombre, será bash con llamadas a ImageMagick

D

#1 no es javascript

editado:
vale, entendí mal el comentario lol

D

En referencia a la PD de #10:

Yo también defendía a C++ sobre Java (y lo sigo defendiendo), pero Java tiene muchos ases debajo de la manga.

Mi jefe me hizo ver como un simple for (int i = 0; i < 9999999999; ++i) es 7 veces más rápido en Java que en C++. No veas la cara que se me quedó (aún así, sigo defendiendo C++, simplemente por que Java me parece más bien un juguete en algunos aspectos, pero eso ya es carne de otro flame).

Y en referencia a #12:

Ambos coincidimos en que es más eficiente C++ que PHP, pero ten en cuenta el contexto: generar un html que a base de tags construya una imagen.

1. Si está en un servidor de imágenes...

Si esta es la función principal, nos interesa mucho la portabilidad y, como bien dices, se consigue con la estandarización. Lamentablemente, tu código actualmente no funciona en plataformas no GNU/Linux (en serio, desconozco si es por las bibliotecas jpg o incluso por el configure, esto son cuestiones de
#3).

¿Qué nos queda entonces? Usar un lenguaje que soporte esto y siga siendo multiplataforma.

Finalmente, añadir que si ponemos una imagen de tamaño medio (la que consume 4 segundos en tu binario), acabariamos con una caida del sistema.

2. Si está en el cliente...

¿Qué más le da esperar 4 segundos o 64 si después va a guardar el html para el resto de su vida? (sí, es un argumento poco convincente, pero en serio, no sé para qué quiere un cliente un html que contenga una imagen :S)

3. De todas formas...

A nadie le hace gracia cargar una imagen así en su navegador.

Pero vamos, como prueba de concepto está genial

D

No #10, vamos a hacer las cosas bien.

Veamos, probemos los dos programas en MI máquina (tu tienes un pedazo de maquinón, que nos conocemos ).

Además, he hecho un php que ejecute tu binario y muestre la salida.

Medidos con wget:
mi programa tarda 0.04s
tu programa tarda 0.02s

Sí, tienes razón, es más eficiente el programa creado en C++ (normal), pero no tanto como decias. Además, parsear una imagen tan grande como la que propones es la muerte para el navegador del cliente.

Pero ¿por qué tantas cosas están hechas en PHP y no en C/C++? no es un capricho, es lo que señala #3 (ojo, que ni he probado si tu código funciona en plataformas diferentes a GNU/Linux, no tengo ninguna a mano).

D

No sé #8, yo acabo de hacer un script cutrecillo en PHP para dibujar JPEG's y es instantáneo (probado con la imagen que has posteado en el blog). Tarda 0,04s (según wget), y no está optimizado para nada:

editado:
posteo el code en pastebin: http://pastebin.com/f16b905fe

0.04 segundos teniendo en cuenta el paso por Apache, lo que tarde wget en enviar y recibir cabeceras... Pero bueno, dejémoslo en 0.04s.

Con java, obviamente, rularía mucho más rápido. Si mañana tengo tiempo en el curro lo pruebo.

D

#5 tu estás generando un archivo html a partir de un jpg para luego (supongo) pegarlo en la web... ¿no ves más viable usar un lenguaje como PHP o Java (en la parte del servidor) para generar esa imagen dinámicamente?

Seguro que el próximo gimp es vía web lol

D

#3 con lenguajes como java, tienes más potencia para hacer este tipo de tratamiento de imágenes (tiene soporte nativo para más formatos), y con librerías externas en algunos lenguajes script (por ejemplo, en PHP tienes las bibliotecas GD), es fácil hacer esto.

D

#4 seguro que el próximo gimp está hecho en php con gd, o en java.

D

#7 claro,es una buena opción, pero algunas mejoras que he pensado y probado en php, tardan minutos, y segundos en C, piensa en las capas de abstracción que tienes en java o en php, y en como crece el tamaño del problema, conforme crece la imagen, sin llegar a tamaños raros.

Por ello, lo mas fácil es ejecutar el binario compilado con optimización etc, y leer su salida desde php, por ejemplo.

Aunque sería interesante hacerlo en PHP, temo que no escalase mucho, por ejemplo, una técnica que estoy probando para reducir mas aún los pixeles, es jugar con áreas muy densas en x color, crear allí un cuadro detras, y no pintar ciertos pixeles.

Solo para crear una estadística de la densidad de áreas, en C tarda 2-3-4 segundos, depende, imaginalo en Java, no lo veo viable, aunque quizá me equivoque.

D

jcarlosn@linux-wnp3:~/img2xhtml> time img2xhtml -f tux.jpg > /dev/null

real 0m0.004s
user 0m0.000s
sys 0m0.002s

jcarlosn@linux-wnp3:~/img2xhtml>

Donde tu has tardado 0.04 (4 centesimas, te parece poco?) el código en C tarda 6 MILESIMAS.

Vale, la diferencia es de: 0.04 frente a 0.006, lo que nos da un total de 6 veces mas, teniendo en cuenta que con operaciones mucho mas complejas, como he comentado de los cuadrados, la diferencia entre el C y el PHP se incrementa muchísimo...

En una imagen grande, donde el C con lo que he comentado tarda 4 segundos, tu tardas 24, eso aun en el mejor de los casos, en el que el PHP no rinde peor que el C en algoritmos complejos (que si lo hace).

Eso nos da que una imagen grande, con operaciones complejas y el algoritmo de los cuadros, tarda en C unos 8 segundos, tu tardas unas 8 veces mas (complejidad añadida, en tu ejemplo solo eres un wrapper de gd, casi casi, y ya multiplicas por 6), lo que nos da la friolera de 64 segundos frente a 8 segundos.

Hay diferencia.

Ya que estamos, aprovecho para lanzar la pregunta al aire: a mi me gusta muchísimo php, perl, python, y demás, y trabajo con ellos, pero nadie se ha preguntado alguna vez, por que tantas cosas están hechas en C/C++? no es un capricho.

P.D. Yo no estoy tan seguro que con Java rulase mas rápido, al revés.

PHP, si miras su código, es una fina capa entre tu y el C, y además ahí en tu ejemplo, tirás de GD, también hecho en C, por lo que gran parte de tu ejecución, es en código compilado de C.

En cambio en java tienes muchísimas capas mas por encima (algo innegable, por mucho que a mi también me guste el java) que retrasarían mucho mas la ejecución.

Esto me plantea una duda bastante interesante:

Existe algún lenguaje, en el que el lenguaje haga el manejo de memoria por ti (a diferencia de C/C++), válido para crear programas que trabajen con cantidades de datos ingentes? Estilo los pixeles de una foto gigante, y encima operar sobre ellos con bucles etc.

Yo soy de los que piensa que todo eso, si quieres que tu aplicación sea extensible, requiere de C/C++, que en un script de 5 lineas en php, llamando a un wrapper de una librería C, te haya funcionado, no dice mucho, la gracia esta en operar sobre todo esto, por que cada operación sobre un pixel, la puedes tener que repetir millones de veces, y si es un bucle sobre cada pixel de una imagen (estadística de área), cientos de millones de veces.

Es ahí, donde estas diferencias de proporciones como 6 veces mas, se traducen en días de procesamiento.

D

#11 0.02s y ni si quiera hemos entrado en operaciones complejas, eso solo refuerza mi teoría, aquí lo que retrasa todo el rato, es el PHP, que quiere decir esto? Lo siguiente:

Tu código ha tardado 0.04s, todo el rato ha vivido en PHP, y eso es lo que ha tardado.

Mi código ha tardado, en tu máquina y teniendo que pasar a través de tu PHP, 0.02s, mientras que en ninguna máquina superior a un pentium 4 tardaría eso, ni de broma, solo en ejecutarse el binario.

Entonces, ahora imaginemos que extendemos el programa de forma compleja, en el cual, tu código vivirá siempre en el PHP, mientras que mi programa, sobre tu PHP, sufrirá la lentitud de PHP, entonces se ejecutará el binario, y volverá a PHP, mostrando la salida.

Sabemos pues que el PHP consume ya de por si 0.02 (mi binario consume milesimas en mi portatil, no en mi sobremesa, y lo deja en 0.02, eso es un incremento sustancial).

Ergo, cualquier implementación tendrá un tiempo de X+0.02.

Ahora tu implementación en PHP continua ejecutandose y ejecutandose en PHP, haciendo todos los cáculos sobre la imágen, mientras que la mía, los hace en el C, ahí no sufre de lentitud por estar en PHP, y solo sufre el retraso de 0.02.

Para explicarlo de otra manera...

Cuando yo empezaba eyeOS, decidí crearme mi propio parser xml en PHP (pure-php), después de que mucha gente ha contribuido con el (eyeXML se llama) y lo han ido perfeccionando y acelerando, expat ya solo es 3000 y pico veces mas rápido que eyeXML

Es por poner un ejemplo real, puedes probarlo cuando quieras comparando eyeXML contra PHP XML DOM, el cual usa expat por debajo, y puedes hacer los benchmarks con microtime().

En la mail list de eyeOS hubo un thread larguísimo sobre esto, y yo también defendía primero al PHP (normal, era mi implementación pure-php) pero con las cifras, me dejaron sin argumentos.

La realidad es muy simple: la abstracción tiene un precio, y se paga por que sale a cuenta, para crear la mayoría de aplicaciones que usamos a diario, pero no sale a cuenta en programas con algoritmos extensos sobre volúmenes importantes de datos.

P.D. la portabilidad real no se cosigue con un capa de abstracción, la cual necesitarás en el sistema al que quieras mudar la aplicación, sino que se consigue con la estandarización (posix, c99).

D

Quiero aprovechar, ya que hemos entrado en el tema para citar algunas páginas sobre esto:

http://dan.corlan.net/bench.html

No voy a pastear el resultado del C optimizado ni del python +psyco, sino las cosas reales:

C, gcc V2.95.4 3.61 3.57
RUBY*** (interpreted) 1074.52
Python** V2.1.2 (interpreted) 505.50
Perl* V5.6.1 (bytecompiled) 515.04

Mira que diferencias, donde C ha necesitado 3.61 segundos, Ruby ha necesitado 1074.52 segundos, te recomiendo que mires:

http://shootout.alioth.debian.org/

Una web muy buena sobre todo esto, con muchos datos y benchmarks.

Por ejemplo:

http://shootout.alioth.debian.org/u32q/benchmark.php?test=all&lang=php&lang2=gcc

php vs C de gcc, como indica, las ~ indican cuantas veces es más rápido C, por ejemplo:

fannkuch ~127 ~7.4 1.3
fasta ~106 ~8.1 1.2

En esos dos tests, en uno C es 127 veces más rápido, en el otro C es 106 veces más rápido.

Evidentemente que todos los lenguajes tienen sus puntos fuertes, pero es que hemos ido a discutir sobre el punto fuerte de C, si estuviésemos discutiendo tiempo de desarollo, seguramente, C ni lo nombraríamos.

D

#14

Mi jefe me hizo ver como un simple for (int i = 0; i < 9999999999; ++i) es 7 veces más rápido en Java que en C++. No veas la cara que se me quedó (aún así, sigo defendiendo C++, simplemente por que Java me parece más bien un juguete en algunos aspectos, pero eso ya es carne de otro flame).

Ahí hubo gato encerrado, mira:

http://shootout.alioth.debian.org/u32q/benchmark.php?test=all&lang=javaxint&lang2=gpp

mandelbrot ~99 ~2.0 1.3

G++ (el de la ~) es 99 veces mas rápido resolviendo mandelbrot.

Lo que pasó con tu jefe, es que un bucle no es una prueba de nada, no es una operación real, solo una parte.
Estos lenguajes como java, están optimizados para hacer mas rápido ese tipo de cosas, y tu jefe lo sabía, nada mas.

Pero en programas reales, ahí tienes las cifras.

Googleando un poco #14, he pensado: no puede ser, por mucho que java tengas esas partes optimizadas, no puede haber tanta diferencia, así que he encontrado un explicación buenísima sobre todo esto:

http://www.w3sys.com/pages.meta/benchmarks.html

Please note that 'user' times are being used,
which is erroneous, since the JVM time apparently is
not included for the java -s invocation.
I would strongly argue that real time should be used.

If the computer isn't tasked doing anything else but
the benchmark (which is only reasonable for a benchmark!) The real question
is how long did it take!

You can't always trust the user number, if the 'program' is just
a proxy client for the JVM!

Now on to the C++ code that was used for the benchmark...

Y despues del analisis que hace el autor:

This code is twice as fast. In the context of the orginal kano test results would yield:
9 seconds for C++
26 seconds for Java -s

Entiendo que tu jefe se deje liar por marketing de sun, pero no entiendo cuando los informáticos cualificados lo hacen.

D

#16 No has entendido la pregunta, estaba en un contexto, en el que la duda no es:

"Puedo usar C/C++ sin encargarme yo de la memoria?"

Sino:

"Se puede usar realmente un lenguaje donde la gestión de memoria la haga un interprete (o una capa intermedia), para problemas complejos sobre volúmenes ingentes de datos?"

Eso te pasa por entrar al flame corriendo y sin leer

D

#18 lo de flame lo decía en broma hombre.

Acerca de lo que dices...no estoy de acuerdo.

Cuando tienes un lenguaje abstraido, tienes una capa entre tu y la memoria, es una capa genérica, y que tiene un coste, sin embargo, tu propones que es mejor, pero argumentas cuestiones relativas a la implementación.

En primer lugar, cualquier técnica que utilice PHP, el cual está hecho en C, la puedes utilizar tu también en tu programa en C, y con una capa de abstracción menos, lo cual siempre se nota (mira las gráficas que puse mas arriba)

En segundo lugar, de que sirve la destrucción de objetos demorada? toda la memoria que pides, la ha de liberar, sea ahora, o dentro de un rato.

Acerca del pool de memoria, no lo veo claro para una imagen, respecto al impacto que tiene en el consumo de memoria total.

Torocatala

La idea me mola pero este código solo funciona en linux, vaya mierda... Estos linuxeros siempre discriminando

maeghith

Joer, que comentarios más majos

Digo yo, que para grandes volúmenes de datos, además de la gestión de memoria que comentáis, paralelizar también ayudaría, ¿no?, tipo erlang (aunque hablo de oídas, también 'he oído' que la complejidad puede hacerse difícil de manejar si no se lleva cuidado).

Martes13

Es curioso ver como para hacer este tipo de chuminadas el javascript te peta el pc y tenemos que pasar a los metodos mas estaticos... los de "toda la vida".

Personalmente me encanto la optimizacion...

e

#10 Existe algún lenguaje, en el que el lenguaje haga el manejo de memoria por ti (a diferencia de C/C++), válido para crear programas que trabajen con cantidades de datos ingentes? Estilo los pixeles de una foto gigante, y encima operar sobre ellos con bucles etc.

Fácil. No hace falta que dejes C o C++, usa un recolector de basura (hay varias librerías). Además, en C++ tienes los punteros inteligentes.

Si quieres usar el programa para imágenes grandes, hay sitios del código donde podrías optimizarlo, como por ejemplo las iteraciones de los bucles (a simple vista) no tienen dependencias entre sí. Pasarlo a un algoritmo del estilo "divide y vencerás" para paralelizarlo sería relativamente trivial.

Por otra parte, ¿la libjpeg no tiene nada como mmap()? Lo digo por lo de tener que escanear línea por línea.

e

#17 Eso te pasa por entrar al flame corriendo y sin leer

¿Qué flame? De verdad, deberías dejar de tomarte las cosas tan a la defensiva, saltas a la primera

En fin, a la reformulación de la pregunta, te puedo asegurar que sí. De hecho es beneficioso, ¿porqué? Pues porque si creas y destruyes la memoria al momento, tu programa irá más lento (malloc/free y new/delete tienen un coste). Cualquier programa que tenga que estar ejecutándose por largos periodos y que trabaje con muchos datos se verá beneficiado de varias técnicas (pool de memoria, destrucción de objetos demorada, mallocs especializados, etc.)

e

#19 Parece que te he malinterpretado, será que la lluvia me hace estar más susceptible, como se cargue la Mercè...

Cuando tienes un lenguaje abstraido, tienes una capa entre tu y la memoria, es una capa genérica, y que tiene un coste, sin embargo, tu propones que es mejor, pero argumentas cuestiones relativas a la implementación.

Hablaba de la manera de gestionar la memoria en C y C++ porque era de los lenguajes de los que estábamos hablando. Aún así, manejar la memoria "a mano" no siempre es eficiente:

http://en.wikipedia.org/wiki/Memory_pool

En primer lugar, cualquier técnica que utilice PHP, el cual está hecho en C, la puedes utilizar tu también en tu programa en C, y con una capa de abstracción menos, lo cual siempre se nota (mira las gráficas que puse mas arriba)

Las gráficas que has enlazado "intentan" (digo intentan, porque hay muchos factores a evaluar) comparar la velocidad de ejecución de diferentes programas y ahí, interviene tanto la gestión de memoria, como la velocidad de cálculo, etc.

De todas formas, nunca he mirado el código del intérprete de PHP, de hecho apenas he programado en ese lenguaje. Sin embargo, aún lejos de considerarme un experto, sí que he tenido que bucear en el código del intérprete de CPython, cuya gestión de memoria se basa en un recolector de basura y un contador de referencias, siendo bastante eficiente. De hecho, esta discusión me recuerda a un problema que tuve hace un tiempo.

Estaba desarrollando un servicio que iba a recibir muchísimas peticiones y que iba a manejar cantidades brutales de datos. Lo habíamos desarrollado en Python, mientras que el algoritmo crítico y que hacía todo el cálculo importante, lo implementamos en una librería en C++ a la que se hacía desde Python. El algoritmo tenía complejidad logarítmica y escalaba linealmente con el número de procesadores (si lo usábamos en una máquina con 16 procesadores, iba 16 veces más rápido), era perfecto... sobre el papel. Como muchas veces pasa, a la hora de pasarlo a la vida real, nos encontramos con problemas. El problema era que se creaban y destruían muchos objetos, provocando problemas de fragmentación, la caché de datos patinaba, etc. y todo porque reservábamos y liberábamos la memoria al vuelo, así que al final implementamos un pool de objetos, optimizado al problema y adaptado al recolector de basura de Python. Es muy rápido y (aún) no hemos tenido ningún problema.

En segundo lugar, de que sirve la destrucción de objetos demorada? toda la memoria que pides, la ha de liberar, sea ahora, o dentro de un rato.

Sí, pero si tienes un servicio, mejor que se haga cuando no esté tan ocupado, puesto que lo que necesitas es devolver un resultado cuanto más rápido mejor. Si llamas a una función y ésta tiene que reservar y liberar la memoria antes de devolver un resultado, estás perdiendo un tiempo valioso. En cambio, si consigues que la gestión de memoria se haga antes y después de la llamada a la función, ganarás algo de tiempo (dependiendo del caso, claro), además de que evitarás otros problemas, como la fragmentación.

Acerca del pool de memoria, no lo veo claro para una imagen, respecto al impacto que tiene en el consumo de memoria total.

Pues depende, si lo escribes en forma de librería, usándola desde PHP y permites que éste sea quien se encargue de la gestión de la memoria, es posible que consigas mejoras (asumiendo que el gestor de memoria de PHP es eficiente). Piénsalo, qué devolverá una respuesta más rápidamente (suponiendo que esto sea código válido):

funcion()

o

funcion()