Lun Ene 02, 2006 12:32 pm
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
| ¿Cómo generar una imagen con Perl? |
|
|
Buenas otra vez
sigo con mi proyecto.. jeje necesito que me déis consejos de como hacer esto:
"dada un tamaño principal (numero de elementos de la cadena), el tamaño del elemento a buscar y las posiciones donde este elemento se encuentra en la cadena tengo que hacer una sencilla representación gráfica de la cadena principal marcando los elementos"
cómo buscarlo ya lo tengo, ahora sólo me falta cómo representarlo. la verdad es que nunca he trabajado con imágenes. He leido en los tutoriales y podría hacerlo utilizando "2 colores" y concatenando elementos y cuando llegue a la posicion en cuestion + tamaño_elemento pues coger otro color (hacerlo con imagenes pequeñitas).
Pero claro, el tamaño de la cadena que me den es aleatorio y como hago yo los "cuadraditos" de grandes para que la barra no quede ni muy grande ni muy pequeña en los casos extremos? Es un problema...
Lo ideal seria utilizar "algo" que me genere la imagen y pueda hacer un zoom o moverme por la barra pero es que no tengo ni ideaaaaaaa.
alguna sugerencia? No hace falta que sea super sofisticado eh. En Perl, o utilizando html dentro de perl, o... javascript:?: si es q se puede pudiera incluir dentro del perl como el html (ni idea todavia )
Se acepta cualquier sugerencia... MUCHAS GRACIAAAAAAAAS! |
|
|
|

Lun Ene 02, 2006 2:41 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
Para representar las imágenes necesitas saber siempre el tamaño final del gráfico que vas a crear. Si tienes que representar una barra en, digamos, 700 puntos de ancho, pero esa barra en realidad está representando datos muchos mayores, tienes que hacer una reducción de los datos, o una regla de tres.
Ejemplo. Tu cadena de datos va desde el 0 hasta el 28000. Tu barra gráfica sólo tendrá 700 puntos de ancho. Eso quiere decir que cada pixel de ancho de la barra está representando 40 unidades de la cadena. Y si un tramo empieza en el valor 1400, quiere decir que tienes que pintarle en el pixel 35.
Una forma sencilla de hacer gráficos es utilizando la librería GD:
| Código: |
1 #!/usr/bin/perl
2
3 use GD;
4 use strict;
5
6 # Dimensiones de la barra
7 my $barra_alto = 20;
8 my $barra_ancho= 700;
9
10 # Dimensiones de la cadena
11 my $cadena_largo= 28000;
12
13 # Relación cadena/barra
14 my $r = $cadena_largo / $barra_ancho;
15
16 # Valores de los tramos encontrados, en la forma inicio => longitud
17 # Los valores indicados aquí son con respecto a los valores de la
18 # cadena, no de la barra a dibujar
19 my %tramos = (
20 2300 => 1240,
21 4500 => 6500,
22 13800 => 900,
23 25000 => 1500,
24 );
25
26 # crear una nueva imagen
27 my $img = GD::Image->new($barra_ancho,$barra_alto);
28
29 # definición de colores
30 my $color_blanco = $img->colorAllocate(255,255,255);
31 my $color_negro = $img->colorAllocate(0,0,0);
32 my $color_rojo = $img->colorAllocate(255,0,0);
33
34 # hacer el fondo de color blanco, transparente e interlazado
35 $img->transparent($color_blanco);
36 $img->interlaced('true');
37
38 # Poner un borde negro alrededor de la barra
39 $img->rectangle(0,0,$barra_ancho-1,$barra_alto-1,$color_negro);
40
41 # Para todos los tramos, pintamos rectángulos rellenos
42 foreach my $inicio ( keys %tramos ) {
43 my $longitud = $tramos{$inicio};
44
45 # Hacemos la cuenta para saber el tamaño del rectángulo a pintar
46 # $x es el origen de dibujo del rectángulo, y
47 # $w es su ancho
48 my $x = $inicio / $r;
49 my $w = $longitud / $r;
50
51 # Pintamos el rectángulo relleno según el inicio y la longitud
52 $img->filledRectangle($x,0,$x+$w,$barra_alto-1,$color_rojo);
53
54 # Alrededor del rectángulo ponemos un marco negro
55 $img->rectangle($x,0,$x+$w,$barra_alto-1,$color_negro);
56 }
57
58 # Grabación de la barra
59 open my $fh, ">grafico.png";
60 binmode $fh;
61 print $fh $img->png;
62 close $fh;
63
|
En las líneas 7 y 8 definimos el tamaño de la barra a dibujar. Será un simple rectángulo.
En la 11, la longitud de la cadena, o dicho de otra forma, el valor máximo de nuestros valores a representar.
En la 14, calculamos cuantas unidades de la cadena representa cada pixel de la barra.
De la 19 a 24 metemos unos cuantos valores de prueba. Fíjate que son valores dentro del rango de la cadena, no de la barra.
En la 27, creamos la imagen.
De la 30 a la 32 creamos unos cuantos colores. El primer color definido de esta forma servirá además como color de fondo de la imagen.
En la 35 decimos que, además, ese color blanco sea transparente. Esto es opcional, claro, y se puede quitar.
En la 36, decimos que la imagen resultante se grabe con la opción de interlazado, para que los navegadores puedan presentar la imagen aunque no haya terminado de llegar completamente. Esta opción sólo es necesaria en gráficos muy grandes o conexiones a internet muy lentas.
En la 39 pintamos el rectángulo negro que bordea toda la imagen. Observa que las coordenadas empiezan en 0, por lo que el ancho y alto han de ser uno menos que los valores que tenemos.
De la 42 a la 56 tenemos un bucle por todos los tramos a representar que hemos metido de ejemplo antes en %tramos.
En la 43 extraemos el valor del tramo, mejor dicho, su longitud.
En la 48 y 49 transformamos los valores de $inicio y $longitud del espacio dentro de la cadena al espacio de nuestra barra. Una simple regla de tres.
En la 52 pintamos un rectángulo relleno según esos valores y en la siguiente la bordeamos en negro.
Finálmente, de la 59 a la 62 grabamos el resultado, en formato png.
El resultado lo puedes ver en: http://JoaquinFerrero.com/grafico.png |
|

Lun Ene 02, 2006 6:12 pm
|
 |
kidd
Creador de Perl en Español

|
Registrado: 15 Oct 2003
Mensajes: 1389
Ubicación: México
|
|
|
|
Lun Ene 02, 2006 7:00 pm
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
muchas gracias a los 2!!!
explorer creo que con tu solución me podré apañar ya te iré preguntando las dudas que me surjan. Muchas gracias te lo curras un monton!!
Por cierto, para utilizar GD hay que "añadirlo" al servidor? o normalmente ya está? Es que trabajo sobre un servidor que no es mío y no se si lo podré utilizar, de todas maneras mañana lo miro con más detalle. Muchísimas gracias! |
|

Mar Ene 10, 2006 12:13 pm
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
bien, me lo he mirado y lo entiendo todo.
hoy por fin he podido probarlo. y OK, me crea la imagen... pero si la quiero mostrar como parte de una página html desde ese mismo script? No me deja
digamos q dspues de todo lo de antes tengo esto:
print"Content-type:text/html\n\n";
print"<html><head> <title>FREQ Results</title> </head>\n";
print"Aqui tenemos la imagen <br>";
print "<img src=\"grafico.png\" width=\"700\" height=\"20\">\n";
pero ejecuto y en la imagen me sale la tipica "crucecita" y si desde mozilla hago view image me sale:
Forbidden
You don't have permission to access /cgi-bin/freq/grafico.png on this server.
como se pueden modificar los permisos de un archivo mediante perl?
haciendo esto funcionara? o es que no se puede?
GRACIAAAAAAS  |
|

Mar Ene 10, 2006 1:09 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
A ver... una cosa es que quieras sacar ese gráfico en tiempo real (creándolo en el momento con el programa) o primero generar el gráfico, guardarlo al lado de la página html correspondiente y luego referenciarlo con la marca <img>.
Del mensaje de error se deduce que estás en el primer caso. Has creado un cgi y dentro de él se genera el gráfico.
Lo que te falta es que crees una página html que llame a tu programa, en el lugar de la página donde quieres presentarlo:
| Código: |
<html>
<head> <title>FREQ Results</title> </head>
<body>
Aqui tenemos la imagen <br>
<img src="/cgi-bin/grafico.pl" width="700" height="20">
</body>
</html>
|
Esta página la guardas en cualquier parte de tu sitio web. Luego subes a la carpeta cgi-bin el grafico.pl. Cuando veas la página en el navegador, éste solicitará la imagen, y, al ser un gráfico, lo intentará dibujar.
Lo que falta de cambiar en el programa anterior es:
| Código: |
58 # Presentación de la barra
59 print "Content-type: img/png\n\n";
60 binmode STDOUT;
61 print $img->png;
62 |
Cosa distinta es que quieras primero grabar la imagen (generarla) y luego presentarla dentro del html. Entonces primero ejecutas el programa, guardas la imagen al lado de la página html y agregas su nombre al src de la <img>. |
|

Mie Ene 11, 2006 11:55 am
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
gracias ya me funciona
es que aun no tenia muy claro el tema y estaba espesa... jeje
-------
por cierto, sabeis como lanzar estas líneas en perl? es que las necesito para poder utilizar el modulo GD del servidor en cuestion.
Por ahora y como chapucilla digamos que desde el html lanzo un primer CGI que es el siguiente (pero shellscript):
imatge.cgi
#!/bin/sh
LD_LIBRARY_PATH=/usr/local/freetype-2.0.5/lib
export LD_LIBRARY_PATH
/usr/usuaris/it/*Servidor*/cgi-bin/freq/imatge.cgi.pl
y desde este hago una llamada al de hacer el gráfico (.cgi.pl porque hice unos cambios...para diferenciarlos)
pero sería mucho más elegante incluir estas lineas (las de las librarys) en el que tiene todo el codigo de la imagen no?
graciasss
----
vale, nada ya he visto que se hace con system()  |
|

Mie Mar 08, 2006 11:39 am
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
| explorer escribió: |
Lo que te falta es que crees una página html que llame a tu programa, en el lugar de la página donde quieres presentarlo:
| Código: |
<html>
<head> <title>FREQ Results</title> </head>
<body>
Aqui tenemos la imagen <br>
<img src="/cgi-bin/grafico.pl" width="700" height="20">
</body>
</html>
|
|
Refloto este tema porque seguí tu consejo y me fue muy bien. Pude mostrar la imagen y tal.
El problema es que para llamar a grafico.pl necesito pasar unos parametros.
Yo lo hago asi:
| Código: |
print"<img src=\"\/cgi-bin\/freq\/carrega_moduls_imatge.cgi?mida_tupla=$mida_tupla&mida_cadena=$mida_cadena&posicions=$posicions_param&nom_fitxer=$nom_fitxer\" width=\"1000\" height=\"100\">";
|
lo paso por GET pq es dela unica manera que encontre en su momento para pasarlo y me fue muy bien.. hasta que las variables q enviaba se hacen muuuuuuuuuuy grandes enonces me sale un error de el servidor no puede enviar URLS tan grandes...
se podria enviar por POST o de alguna otra manera para que no tuviera este problema?
Gracias! |
|

Mie Mar 08, 2006 12:08 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
Que yo sepa, un src de un img no genera una petición POST.
Se podría hacer con marcas invisibles en un formulario. Por ejemplo:
| Código: |
<form ...>
<input type="hide" name="..." value"...">
<input type="hide" name="..." value"...">
...
</form> |
pero, recapitulemos...
Tu tienes un programa Perl que genera una página html, dentro de ella tiene una imagen que se genera con otro programa Perl...
¿Y no se podría hacer todo con un sólo programa Perl, con el primero?
El programa se encargaría de generar el HTML, generar y guardar el gráfico en el sistema de ficheros en un directorio temporal, y en el html sólo habría que poner una referencia a el.
Luego, otro proceso, periódicamente, podría revisar el directorio temporal y borrar los ficheros viejos.
Esto tiene la ventaja del llamado cacheo de imágenes generadas. Si compruebo antes de generarla que una imagen ya existe, no lo hago, le actualizo su fecha de modificaciòn (para que no sea borrado por el recolector de basura anterior) y genero el resto del html. |
|

Lun Mar 13, 2006 9:50 am
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
| explorer escribió: | pero, recapitulemos...
Tu tienes un programa Perl que genera una página html, dentro de ella tiene una imagen que se genera con otro programa Perl...
¿Y no se podría hacer todo con un sólo programa Perl, con el primero?
El programa se encargaría de generar el HTML, generar y guardar el gráfico en el sistema de ficheros en un directorio temporal, y en el html sólo habría que poner una referencia a el.
Luego, otro proceso, periódicamente, podría revisar el directorio temporal y borrar los ficheros viejos.
Esto tiene la ventaja del llamado cacheo de imágenes generadas. Si compruebo antes de generarla que una imagen ya existe, no lo hago, le actualizo su fecha de modificaciòn (para que no sea borrado por el recolector de basura anterior) y genero el resto del html. |
eso es lo q qeria hacer en un principio pero no me sale algo hare mal....
yo tengo mi web html q llama a un CGI q escribe cosas por pantalla (cosas q calcula) y que ademas pinta una imagen. (y esta imagen la crea en ese mismo momento con los datos que le han pasado y ha calculado, desde un programa perl).
Pero tenia dos problemas...
1) Tenía problemas al hacer un system (y por lo tando para llamar a cualquier programa perl de esa manera )
el error es:
Insecure $ENV{PATH} while running with -T switch at /var/www-cgi/gralggen.lsi.upc.es/freq/freq.cgi line 345.
y tuve problemas con el tema d modificar la variable y los premisos y el servidor que no es mio
2) Si muestro la imagen pre-generada me da este error "You don't have permission to access /cgi-bin/freq/dades/grafic.png on this server" (que supongo que tendre que cambiarle el owner o algo asi al fichero... pero si no puedo hacer un system no se como hacerlo  |
|

Lun Mar 13, 2006 11:22 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
El primer error se te va si consigues utilizar una alternativa al system.
Y el segundo error se te va si escribes la imagen en un directorio en el que tengas permiso de escritura Y sea accesible por el usuario que corre el web. Eso es justo lo que te está diciendo el error: que has generado la imagen en el propio directorio cgi-bin, y ese directorio sólo sirve para guardar programas.
Un ejemplo.
Si el web lo tienes colgando de /var/www/misitioweb/ entonces creas el subdirectorio tmp dentro de ese camino.
Le das permiso al directorio tmp para que sea escribible por el usuario que corre el servidor web y por el usuario propietario de los ficheros (puede ser el mismo): chown slopal.www-data tmp; chmod 775 tmp;.
En el programa, el proceso que puedes hacer es:
1.- Entra en el directorio tmp/: chdir /var/www/misitioweb/tmp;
2.- Haces un listado con todas las imágenes disponibles: my @imagenes = <imagen*.gif>;
3.- Haces un bucle por todas ellas y te cargas todas las viejas:
foreach my $imagen ( @imagenes ) {
unlink $imagen if -M $imagen > 3; # Borrar en caso de tener más de 3 días
}
4.- En función de los parámetros pasados por el usuario, calculas el nombre de la nueva imagen a crear. Se supone entonces que aquí hay un truco: si un usuario llama a tu programa con los mismos parámetros, debería siempre ver la misma imagen. Si ese no es tu caso, entonces el paso siguiente lo saltas.
my $imagen = ... ;
5.- En caso de que esa imagen ya exista ( -e $imagen ) saltamos la generación de la imagen
6.- Generamos la imagen y la guardamos (ya estamos dentro de tmp/, por lo que la guardamos en el directorio actual)
my $img = new GD; ...
7.- Generamos la página html. Las referencias a la imagen serán: <img src="/tmp/imagenDGHFDSJ343JHH23.gif>
8.- Entregamos la página html al usuario. ( $|=1; print ... )
Lo ideal sería hacer el borrado de las imágenes viejas después de la entrega de la página, en caso de ser muchas, pero este es un trabajo que los ordenadores hacen de forma muy rápida y el usuario ni se enteraría. |
|

Mie Mar 15, 2006 11:26 am
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
gracias si no encuentro alternativa al system (con exec me pasa lo mismo y tampoco creo q sea lo q necesito) lo hare mediante un fichero temporal de texto y andando.
ademas el tema d las imagenes -por ahora- no me interesa ver las que se han guardado anteriormente, la imagen q genero pesa muy poco (< 1 KB) y seran muy aleatorias. |
|

Lun Mar 27, 2006 10:29 am
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
| explorer escribió: |
Si el web lo tienes colgando de /var/www/misitioweb/ entonces creas el subdirectorio tmp dentro de ese camino.
Le das permiso al directorio tmp para que sea escribible por el usuario que corre el servidor web y por el usuario propietario de los ficheros (puede ser el mismo): chown slopal.www-data tmp; chmod 775 tmp; |
Como puedo saber cual es cual? mi web cuelga de:
gralggen/public_html/recerca/freq
y si hago un ls-la obtengo:
-rw-r--r-- 1 gralggen it 394 Feb 28 20:31 example1.html
entonces el usuario es gralggen?
es que yo creo un directorio que se llama /images con los mismos atributos que lo anterior. Y desde el CGI que se ejecuta en
/gralggen/cgi-bin/freq
(con los ficheros de dentro con los mismos atributos que anteriormente (gralggen it))
no me deja crear ficheros dentro de /images y por lo tanto no puedo probar...
(si en cambio, pongo la imagen "a mano" en ese directorio, si que puedo mostrarlo via web... por lo que supongo q el usuario que corre en el servidor sera este.. pero no estoy segura.. pq no me deja copiaar ) |
|

Lun Mar 27, 2006 12:26 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4128
Ubicación: Valladolid, España
|
|
|
|
|
| slopal escribió: | | explorer escribió: |
Si el web lo tienes colgando de /var/www/misitioweb/ entonces creas el subdirectorio tmp dentro de ese camino.
Le das permiso al directorio tmp para que sea escribible por el usuario que corre el servidor web y por el usuario propietario de los ficheros (puede ser el mismo): chown slopal.www-data tmp; chmod 775 tmp; |
Como puedo saber cual es cual? mi web cuelga de:
gralggen/public_html/recerca/freq
y si hago un ls-la obtengo:
-rw-r--r-- 1 gralggen it 394 Feb 28 20:31 example1.html
entonces el usuario es gralggen? |
Ese es el usuario de ese fichero, pero quizás no lo sea del directorio donde está ('.'). Haz un ls -la y fíjate en el propietario del directorio actual. Haz un ps aux para saber el nombre del usuario bajo el que corre el servidor web. Puede ser www, www-data, web, httpd, apache, etc. etc. El directorio images deberá pertenecer a ti (usuario web gralggen) y al mismo grupo al que pertenece el usuario web. Algo así como chown gralggen.www-data images. Y luego los permisos de escritura para los dos y sólo ellos dos: chmod 775 images. Hay que dar permiso de entrada y lectura al resto del mundo para que puedan ver las imágenes
| slopal escribió: | es que yo creo un directorio que se llama /images con los mismos atributos que lo anterior. Y desde el CGI que se ejecuta en /gralggen/cgi-bin/freq (con los ficheros de dentro con los mismos atributos que anteriormente (gralggen it)) no me deja crear ficheros dentro de /images y por lo tanto no puedo probar...) |
Para escribir en el directorio images, recuerda que el script debe conocer el camino COMPLETO a ese directorio, en el árbol de directorios del disco, no del web. Por ejemplo, open my $fh, '>', '/home/gralggen/public_html/recerca/freq/images/imagen.png' or die "ERROR al escribir imagen.png: $!\n";
| slopal escribió: | (si en cambio, pongo la imagen "a mano" en ese directorio, si que puedo mostrarlo via web... por lo que supongo q el usuario que corre en el servidor sera este.. pero no estoy segura.. pq no me deja copiaar ) | Tendrás que preguntar al administrador si no estás segura del usuario web. Cuando digo usuario web es el usuario bajo el que se ejecutan los cgis.
Puede ser que todo el problema sea cosa de permisos de los directorios.
Puedes tirar por la calle del medio y darle permisos de escritura a todo el mundo a images: chmod 777 images y probar a ver si puedes escribir algo. Si falla, es que el script no puede encontrar ese directorio. Fíjate en el código de error que sale en el die que está contenido en la variable especial $!. |
|

Mar Mar 28, 2006 10:13 am
|
 |
slopal
Perlero Nuevo

|
Registrado: 23 Nov 2005
Mensajes: 78
|
|
|
|
|
despues de darle 200 vueltas y pruebas diferentes y poner chivatos he descubierto que:
- sí que puedo crear ficheros ahi (oleee)
- sí que puedo crear imágenes bien hechas ahí (oleee)
- explediente X: no puedo crear la imagen de esta manera concreta:
| Código: |
| open(IM, ">/homes/users55/users/gralggen/public_html/recerca/freq/images/imatge_$tmp.png") ; |
cual es el problema? la variable $temp que no me la coge (o algo asi). Esta variable es de la forma 724.480816469626 recogida por GET desde otro CGI.
Cualquier otra variable funciona, incluso poniendolo a "mano" (grafic_724.480816469626.png) funciona.
He probado a cambiar el nombre de la variable: NADA. He probado a copiar la variable en otra: NADA.
Es más! esta misma variable la utilizo para abrir un fichero (previamente)!! del mismo estilo:
| Código: |
open(TEMP, "<$dir/temp_$tmp.txt") or die('error');
binmode(TEMP); |
y me abre perfectamente el fichero...
cuando llega a la linea de abrir la imagen (justo una linea antes, hago un print de la variable en un fichero temporal) Y SIGUE ESTANDO BIEN EL CONTENIDO.
He probado las mismas lineas desde el cgi previo (desde donde le envio por GET la variable) y me funciona perfectamente.
Y nose, he hecho 200mil pruebas mas... (que si me vienen a la cabeza las pongo) y no lo entiendo... solo me pueden pasar a mí estas cosas raras .
* He llegado a pensar que no lo entienda como un string y por eso no lo sepa hacer (pero entonces pq me funciona el open del temp?). De todas maneras... hay alguna funcion o algo asi para forzar que una variable sea del tipo string? (sprintf? :S)
Alguna IDEA? |
|

Powered by phpBB © 2001, 2005 phpBB Group
|