• Publicidad

Cómo insertar imágenes GD con HTTP::Server::Simple

Todo lo relacionado con el desarrollo Web con Perl: desde CGI hasta Mojolicious

Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor _behoimi » 2012-09-13 20:19 @888

Hola, me gustaría saber cómo insertar imágenes desde el disco.

En concreto lo que quiero es que al ingresar a la página con el módulo GD crear la imagen, luego mostrarla en la web. ¿Es posible con el módulo HTTP::Server::Simple? De nos ser así, ¿es posible con otro módulo o método?

Sigo el ejemplo para crear el servidor, mostraré las subrutinas en cuestión solamente, evito también crear una imagen compleja para evitar un exceso de lineas:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub resp_index {
  2.  my $cgi = shift;
  3.  
  4.  print $cgi->header,$cgi->start_html('index');
  5.  print "<FORM method=\"POST\" action=\"http:\/\/localhost:8080/imagen\">";
  6.  print "<h3>ingrese ancho de la im&aacute;gen<\/h3>";
  7.  print "<INPUT type=\"text\" name=\"Ancho\"><br>";
  8.  print "<h3>ingrese alto de la im&aacute;gen<\/h3>";
  9.  print "<INPUT type=\"text\" name=\"Alto\"><br>";
  10.  print "<p><INPUT type=\"submit\" value=\"Enviar\"><\/p>";
  11.  print "<\/FORM>";
  12.  print $cgi->end_html;
  13. }
  14. sub resp_imagen {
  15.  my $cgi = shift;
  16.  
  17.  my $ancho = $cgi->param('Ancho');
  18.  my $alto = $cgi->param('Alto');
  19.  
  20.  use GD;
  21.  my $img = new GD::Image($ancho,$alto);
  22.  my $white = $img->colorAllocate(255,255,255);
  23.  my $red = $img->colorAllocate(255,55,33);
  24.  $img->transparent($white);
  25.  $img->interlaced('true');
  26.  $img->fill(0,0,$red);
  27.  
  28.  print $cgi->header,$cgi->start_html('imagen');
  29.  print "<h3>No s&eacute; llamar la im&aacute;gen<\/h3>";
  30.  print $cgi->end_html;
  31. }
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
_behoimi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-09-13 15:01 @667

Publicidad

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor explorer » 2012-09-14 02:38 @151

Bienvenido a los foros de Perl en Español, _behoimi.

Tienes tres opciones (que se me ocurran ahora).

  • el cgi, además de generar el código HTML de respuesta, genera la imagen como un flujo de caracteres en codificación base64, y lo agrega dentro de la marca <img> correspondiente (más detalles, en inglés)
    .
  • el cgi, antes de terminar de enviar el HTML al usuario, guarda la imagen generada a un archivo, en un directorio que pueda acceder tanto el servidor web como él mismo. Y en el HTML que envía, las marcas <img> hacen referencia a ese archivo, para que sea el navegador web del usuario el que haga la petición expresa de bajarla, como elemento constituyente de la página. Por ejemplo, supongamos que el cgi está en /usr/lib/cgi-bin/, y la raíz del sitio en /srv/www/sitio_web/, y que las imágenes las queremos guardar en /srv/www/sitio_web/img/, entonces es en este último donde nuestro cgi debe escribir la imagen generada. Para poder hacerlo, debe tener permiso de escritura, para el usuario con el que corre el servidor web, así que será algo así:

    chmod 777 /srv/www/sitio_web/img

    o

    chgrp www-data /srv/www/sitio_web/img
    chmod 775 /srv/www/sitio_web/img/

    (siendo www-data el grupo al que pertenece el usuario web).

    El cgi generará la imagen y la guardará ahí. Supongamos que es abc.gif. Luego queda generar el código HTML para que apunte a la imagen: <img src="/img/abc.gif">
    .
  • hacer dos cgi. Uno de ellos devuelve el código HTML. En ese código html, las marcas <img> tienen como direcciones al segundo cgi. Algo así: <img src="/cgi-bin/genera_imagen.pl?arg1=valor1;arg2=valor2">. El código HTML le llega al navegador del usuario, y ve que tiene que hacer una solicitud para bajarse una imagen, que se traduce en el servidor en la llamada al segundo cgi, que se encargará de generar la imagen con GD, que esta vez enviará de forma directa por la salida estándar. Algo así:

    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
    1. #!/usr/bin/env perl
    2. use CGI ':standard';
    3. use GD;
    4.  
    5. my $cgi = CGI->new;
    6.  
    7. # aquí, leer los argumentos y parámetros
    8.  
    9. my $img = GD::Image->new($ancho,$alto);
    10.  
    11. # aquí, generar la imagen
    12.  
    13. print $cgi->header('img/png');                    # cabecera que indica que devolvemos un archivo PNG
    14. binmode STDOUT;                                   # nos aseguramos que la salida es en binario puro
    15. print $img->png;                                  # salida de la imagen en formato PNG
    16.  
    17. __END__
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
    Esta solución es más costosa desde el punto de vista de consumo de recursos (son dos cgi en lugar de uno solo) y además, el segundo cgi necesita acceder a la información necesaria para generar la imagen, por lo que a veces el primero debe dejarle esa información en algún sitio (este es el caso de la ejecución del primer cgi por el envío de un formulario web). Pero tiene la ventaja de que divide el problema en partes
Las dos últimas soluciones se pueden reunir en un cuarta solución para los casos en que las imágenes generadas sean siempre las mismas en caso de que los argumentos para generarlas sean los mismos.

Lo único que tiene que hacer el primer cgi es comprobar que la imagen no haya sido generada antes, y en ese caso, enviar las marcas <img> apuntan al archivo donde está la imagen generada. Y el segundo cgi, además de enviar la imagen generada, guarda una copia en el directorio img/ para que la próxima vez, la encuentre el primer cgi.

Esta es una solución muy buena para los casos de páginas web muy demandadas e imágenes que se repiten.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor _behoimi » 2012-09-14 04:35 @233

Bien, lo he conseguido. He usado la primera opción que has recomendado y resultó perfectamente.

Sólo agregué una pocas lineas al código de la subrutina que crea y muestra la imágen que quedó así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub resp_imagen {
  2.  my $cgi = shift;
  3.  
  4.  my $ancho = $cgi->param('Ancho');
  5.  my $alto = $cgi->param('Alto');
  6.  
  7.  use GD;
  8.  my $img = new GD::Image($ancho,$alto);
  9.  my $white = $img->colorAllocate(255,255,255);
  10.  my $red = $img->colorAllocate(255,55,33);
  11.  $img->transparent($white);
  12.  $img->interlaced('true');
  13.  $img->fill(0,0,$red);
  14.  binmode STDOUT;
  15.  $img = $img->png;
  16.  
  17.  use MIME::Base64;
  18.  $img = encode_base64($img);
  19.  
  20.  print $cgi->header,$cgi->start_html('imagen');
  21.  print "<img src=\"data:img\/png;base64,$img\"><\/img>";
  22.  print $cgi->end_html;
  23. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
_behoimi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-09-13 15:01 @667

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor explorer » 2012-09-14 05:13 @259

Mejor así:

print qq(<img src="data:img/png;base64,$img" />);

o así:

print $cgi->img(-src => "data:img/png;base64,$img");
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor _behoimi » 2012-09-15 11:00 @500

Quiero probar la segunda opción, el problema es que estoy en un entorno Windows.

He intentado colocar una imagen desde el disco de la siguiente forma:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. open IMG, "<imagen.png";
  2. foreach (<IMG>){
  3.  our $img .= $_;
  4. }
  5. use MIME::Base64;
  6. our $img encode_base64($img);
  7. print qq(<img src="data:img/png;base64,$img");
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Esto está mal ya que pierdo un carácter al pasar de <IMG> a $img. No sé cual es el carácter, probé con "\n", "\r" y "\r\n", pero no pude dar con él.

Estoy en un entorno Windows. Strawberry Perl x64 (v5.14.2) es mi versión de Perl.

En este caso, ¿cuál es la carpeta donde se aloja el html creado? o ¿localhost no es una carpeta realmente y el cgi sólo imprime conforme el cliente solicite la web?
_behoimi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-09-13 15:01 @667

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor explorer » 2012-09-15 11:22 @515

Esa no es la segunda solución.

Si ya tienes generada y guardada la imagen, entonces sólo tienes que mandar al usuario, en el HTML, la ruta para que el navegador web la pueda recoger.

Supongamos que imagen.png está en C:/httdocs/img/, siendo C:/httdocs/ la raíz del sitio web.

Ahí, en ese sitio, es donde generaste y guardaste la imagen. Solo queda enviar la marca <img> correcta:

print qq(<img src="/img/imagen.png");
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor _behoimi » 2012-09-15 12:06 @546

Esto no me funciona:

print qq(<img src="/img/imagen.png");

ya que el navegador va a http://localhost/img/imagen.png. Por eso mi pregunta es si HTTP::Server::Simple realmente crea un archivo HTML o imprime directamente al solicitar la página.

Edito:
He solucionado el problema, de la siguiente forma:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub resp_main {
  2.  my $cgi = shift;
  3.  
  4.  print $cgi->header,$cgi->start_html('main');
  5.  print qq(
  6.   <img src="imagen.jpg">
  7.  );
  8.  print $cgi->end_html;
  9.  }
  10.  sub resp_imagen {
  11.  my $cgi = shift;
  12.  
  13.  print $cgi->header('image/jpg');
  14.  open IMG, "<imagen.jpg";
  15.  print <IMG>;
  16.  close (IMG);
  17. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Última edición por _behoimi el 2012-09-15 12:31 @563, editado 1 vez en total
_behoimi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-09-13 15:01 @667

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor explorer » 2012-09-15 16:19 @721

No acabo de entender lo que estás haciendo.

¿En qué momento estás llamando a resp_main() y cuándo a resp_imagen()?

Y el envío de la imagen está mal: te falta activar el modo binario con binmode().

Si la imagen no está en /img, debes cambiarlo para poner la ruta correcta.

Sigo creyendo que no es necesario el envío de la imagen, si ya está guardada en el disco. Hacerlo implica un servicio más lento y que consume más recursos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor _behoimi » 2012-09-15 17:33 @773

Sigo el ejemplo de HTTP::Server::Simple para hacer las llamadas de las subrutinas, pondré el codigo completo.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use warnings;
  3.  
  4. {
  5. package webServer;
  6. use HTTP::Server::Simple;
  7. use base qw(HTTP::Server::Simple::CGI);
  8. my %dispatch = (
  9.  '/' => \&resp_index,
  10.  '/index' => \&resp_index,
  11.  '/banner' => \&resp_banner,
  12.  '/menu' => \&resp_menu,
  13.  '/main' => \&resp_main,
  14.  '/imagen.jpg' => \&resp_imagen_jpg,
  15.  '/imagen.png' => \&resp_imagen_png,
  16.  '/favicon.ico' => \&resp_icon,
  17. );
  18. sub handle_request {
  19.  my $self = shift;
  20.  my $cgi = shift;
  21.  my $path = $cgi->path_info();
  22.  my $handler = $web{$path};
  23.  if (ref($handler) eq "CODE") {
  24.   print "HTTP/1.0 200 OK\r\n";
  25.   $handler->($cgi);
  26.  } else {
  27.   print "HTTP/1.0 404 Not Found\r\n";
  28.   print $cgi->header,
  29.    $cgi->start_html('Not found'),
  30.    $cgi->h1('404 Not found');
  31.   print qq(<hr /><br />404 not found);
  32.   print $cgi->end_html;
  33.  }
  34. }
  35. sub resp_index {
  36.  my $cgi = shift;
  37.  print $cgi->header;
  38.  print qq(
  39.   <!DOCTYPE html>
  40.   <html><head><title>My web page</title>
  41.   <link rel="shortcut icon" href="/favicon.ico" /></head>
  42.   <frameset rows="131,*" frameborder="0">
  43.    <frame name="banner" src="banner" noresize>
  44.   <frameset cols="78,*" frameborder="0">
  45.    <frame name="menu" src="menu" noresize>
  46.    <frame name="main" src="main" noresize>
  47.   </frameset></frameset>
  48.  );
  49. }
  50. sub resp_banner {
  51.  my $cgi = shift;
  52.  print $cgi->header,$cgi->start_html('banner');
  53.  print qq(<img src="imagen.png" />);
  54.  print $cgi->end_html;
  55. }
  56. sub resp_menu {
  57.  my $cgi = shift;
  58.  print $cgi->header,$cgi->start_html('menu');
  59.  print qq(<a href="/main" target="main">Main</a>.<br>);
  60.  print $cgi->end_html;
  61. }
  62. sub resp_main {
  63.  my $cgi = shift;
  64.  print $cgi->header,$cgi->start_html('main');
  65.  print qq(<img src="/imagen.jpg" />);
  66.  print $cgi->end_html;
  67. }
  68. sub resp_imagen_jpg {
  69.  my $cgi = shift;
  70.  print $cgi->header('image/jpg');
  71.  open IMG, "<imagen.jpg";
  72.  binmode IMG;
  73.  print <IMG>;
  74.  close (IMG);
  75. }
  76. sub resp_imagen_png {
  77.  my $cgi = shift;
  78.  print $cgi->header('image/png');
  79.  open IMG, "<imagen.png";
  80.  binmode IMG;
  81.  print <IMG>;
  82.  close (IMG);
  83. }
  84. sub resp_icon {
  85.  my $cgi = shift;
  86.  print $cgi->header('image/x-icon');
  87.  open IMG, "<invader.ico";
  88.  binmode IMG;
  89.  print <IMG>;
  90.  close (IMG);
  91. }
  92.  
  93. }
  94.  
  95. my $pid = webServer->new(8080)->background();
  96. print "Use Control+C to stop server.\n";
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Esto me resulta bien con las imágenes jpg y png, pero no con el icono.

Sólo logro acceder a los archivos del disco usando open(), ya que al darle la dirección de una imagen ejecutará una subrutina.
_behoimi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-09-13 15:01 @667

Re: Cómo insertar imágenes GD con HTTP::Server::Simple

Notapor explorer » 2012-09-15 19:46 @865

Humm...

¿Dónde está definido el hash %web que aparece en la línea 22?

Esto no es nada óptimo... como tengas que definir cada tipo MIME en %dispatch, te puedes eternizar...

¿No es más cómodo instalar/usar un servidor Apache?

El truco está en la misma línea 22... si en esa línea se analiza el tipo de contenido que hay que entregar, se puede simplificar la llamada, para evitar hacer una subrutina por cada tipo: fíjate que las subrutinas resp_imagen_jpg(), resp_imagen_png() y resp_icon() son prácticamente iguales. Eso te da la pista de que se puede simplificar en una sola.

O... de otra manera: hacer que todas las peticiones pasen por una sola subrutina. Y dentro de la subrutina, según el tipo de contenido, ofrecer el archivo, bien desde el disco, o bien de forma generada (HTML), y según su tipo MIME.

En todos los casos que vayas a entregar contenido estático, puedes ahorrarte el open(), leer, imprimir, y close() del archivo, con HTTP::Server::Simple::Static. Este módulo se ocupará de todo (cabecera MIME, leer el contenido, y enviarlo).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Web

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 3 invitados