Archivo

Entradas Etiquetadas ‘Imagenes’

A la búsqueda de imágenes/iconos

lunes, 28 de febrero de 2011 4 comentarios

Muchas veces nos encontramos en nuestros programas con que necesitamos imágenes o iconos para ilustrar acciones o elementos de nuestros menús o barras de botones. Personalmente utilizo alguno que tengo como «librería habitual»; Pero otras veces necesitamos algo diferente o las características del proyecto obligan a buscar algo nuevo.

Hay muchas librerías profesionales de iconos (de muy alta calidad), pero también hay lugares donde se pueden conseguir infinidad de iconos de forma gratuita.

He aquí un pequeño repaso de los que yo visito con mayor asiduidad.

(29/06/2015) Actualizado; He eliminado algunas webs que ya no están disponibles del listado anterior y he añaduido también algunas nuevas.

____________________________________________________________

EasyIcon EASYICON
(http://www.easyicon.net/)

Un poco lenta a aveces, pero posee gran cantidad de iconos disponibles. Una vez seleccionada una palabra para la búsqueda, posee selectores para afinar los resultados en cuanto a tamño, color (imprtante),…

_____________________________________________________________

IconGenerator

PICOL – Icon generator
(http://www.picol.org/)

Esta web en un poco diferente al resto, puesto que tal y como indica su nombre es una especie de utilidad para generar iconos personalizados (dentro de unos límites). Nos solicita un tamaño, un color, un icono «base» y un pequeño icono «badge» para la zona inderior derecha (como la flecha de un acceso directo). A partir de todo esto, ‘podemos descargar el icono generado.

_____________________________________________________________

FlatIcons

FLATICON
(http://www.flaticon.com/)

Como su nombre indica, es una web enfocada a iconos con estilo «plano» que están utilizandose más últimamente con las inteficies de las nuevas versiones de Windows. Faltan selectores por categorías o tamaños como tienen otras webs, pero es un buen lugar donde buscar si necesiotamos iconos con la característica comentada (flat).

_____________________________________________________________

IconFinderICONFINDER
(http://www.iconfinder.com)

Muy buena interface una vez realizada la búsqueda. La selección de tamaños, la visualización en pantalla,… se puede realizar una vez que se muestran los resultados y es muy ágil. La visualización de los iconos una vez seleccionados en muy buena y mustra diferentes tamaños del mismo icono junto al resultado.

_____________________________________________________________

VeryIcon
VERYICON
(http://www.veryicon.com/)

Muestra menos resultados que los anteriores. La información cuando muestra el icono seleccionado es buena y prioriza mostrar iconos del mismo «icon-set» que el seleccionado.
_____________________________________________________________


ICONS-SEARCH
(http://icons-search.com/)

Personalmente encuentro que devuelve menos resultados que los primeros buscadores que he indicado. No es de los que tiene mejor interface, pero cumple bien su función.

_____________________________________________________________

ICONSPEDIA
(http://www.iconspedia.com/)

Uno de los últimos que he descubierto. Me resulta demasiado recargado el entorno y la búsqueda de iconos. La página está muy «espesa y el número de iconos que devuelve no está entre las páginas con más resultados retorna.
_____________________________________________________________

ICONSEEKER
(http://www.iconseeker.com)

Esta también se encuentra entre las páginas que devuelve más resultados. La página de respuesta es bastante limpia y permite algun filtro (por tamaño) una vez que los resultados ya se han mostrado. No me gusta mucho que los resultados salgan mezclados en cuanto al tamaño de las imágenes, pero como ya he dcho es fácil filtrarlas una vez que estamos en los resultados.
Una vez seleccionado el icono la pantalla es clara y de las más cuidadas. También está entre mis preferidas.
_____________________________________________________________

MrIcons

Mr. ICON
(http://www.mricons.com)

Es de las últimas que he descubierto y me da la sensación de que es de las más nuevas. No es de las que más resultados devuelve y la forma de mostrarlos tampoco es de las que más me agrade. Mezcla los resultados por tamaños y no permite filtrar entre ellos de forma fácil. La página de resultados es liosa, pero en cambio una vez seleccionado el icono la página que se muestra es más clara y hay acceso rápido a iconos relacionados (por tamaño y por «icon-set»).
_____________________________________________________________

ICONARCHIVE
(http://www.iconarchive.com)

Esta se encuentra también entre las últimas que he descubierto. No ses de las que más resultados muestra (de las que menos en realidad), pero posee los mejores filtros una vez que se accede a los resultados; La página está muy cuidada y la información se muestra de una forma muy clara.
_____________________________________________________________

FINDICONS
(http://findicons.com)

También es de los últimos que he encontrado, y aunque no es de los que devuelve más iconos, los filtros a posteriori una vez completada la búsqueda son los mejores junto con los de IconArchive. La página que muestra el icono seleccionado también es muy clara y da mucha información.
_____________________________________________________________

ICONZA
(http://iconza.com/)

Es web es algo diferente al resto, pero la he incluído aquí porque en algun caso también me ha servido. Se trata de una serie de 112 iconos (generales) que se pueden personalizar para obtener muchas combinaciones. A partir de los iconos base se puede seleccionar el tamaño, el color (tonalidad general del icono) y el fondo, de forma que se obtienen muchas combinaciones a partir de los 112 originales.
_____________________________________________________________

 

 

Una vez encontrados los iconos, hay que mostrar especial atención a la licencia de cada uno de ellos, porque hay variantes.

Recomiendo que si usáis las páginas no es quedéis con una (tal vez tampoco con todas), pero realizar una búsqueda en 3 o 4 de ellas y revisar los resultados combinados suele dar muy buenos resultados (al menos eso es lo que hago yo  ;-) ).

Espero que os se a útil.

AÑADO: Cualquier enlace que no se encuentre en la lista y que consideréis interesante será bienvenido.

Un saludo.

Categories: General Tags: , ,

TidHTTP; Descargar imágenes de una Web

jueves, 10 de febrero de 2011 Sin comentarios

Haciendo pruebas con el componente TidHTTP me ha surgido este ejemplo y me parece interesante mostrar el proceso completo que he seguido para descargar contenido desde una web. En este caso he accedido a las imágenes en formato PNG, pero es extensible a cualquier otros contenidos.

En un primer paso se trata de obtener el contenido (source) desde una página web y a partir de ahí, extraer los links (en mi caso correspondientes a imágenes en formato PNG) y descargar los ficheros para almacenarlos en disco. Para ello utilizaremos el control TidHTTP de la Indy.

Para obtener el código fuente de la página podemos utilizar un código como este:

  // URL de la página
  StrURL := ... ;
  // Crear componente para acceder
  IdH := TIdHTTP.Create(nil);
  // proteccion para liberar
  try
    // proteccion por error
    try
      // Obtenemos la pagina
      Resp := IdH.Get(Trim(StrURL));
      // recuperamos la respuesta
      TSContent.Text  := Resp;
    except
      on E:Exception do begin
        MessageDlg('Error al acceder a la página. '+#13+#10+
                         'Mensaje: ' +
                         E.Message, mtError, [mbOK], 0);
      end;
    end;  // try
  finally
    IdH.Free;
  end;

Una vez que obtenemos la respuesta del componente almacenamos el contenido de la página en un TStrings. Si accedemos a la página: http://neftali.clubdelphi.com/temporal/ejemplo1.html

Obtendremos como resultado del Get el siguiente texto, que corresponde al código fuente de la página:

Lo siguiente que vamos a hacer es un simple «parseo» buscando los enlaces que nos interesen. En nuestro ejemplo queremos links a imágenes en formato png. Utilizando funciones de la clase SysUtils podemos obtener sin mayor problemas los links contenidos en el código; Si probáis con la página de ejemplo, deberíais obtener un único link:

http://neftali.clubdelphi.com/images/GLibWMI_paleta_1.8b.png

Por último, nos queda ver el código necesario para descargar la imagen y almacenarla en disco. Para ello podemos utilizar de nuevo el componente TidHTTP. En mi caso, y en previsión de que pueda haber varias imágenes a descargar, he creado una clase derivada de TThread para ello:

  {: Clase para descargar una imagen y almacenarla en disco.}
  TDownImageThread = class(TThread)
  private
    FURLImage: string;
    FPathImage: string;
    FFileNameImage: string;
    // Internas
    ImageName: string;
    PathURL: string;
    // Componente
    idH:TidHTTP;
  public
    // redefinir métodos
    constructor  Create(AURL:string; AOutPathImages:string);
    destructor Destroy; override;
    procedure Execute; override;
    {: URL de la imagen a descargar. }
    property URLImage:string read FURLImage write FURLImage;
    {: Path de disco local donde voy a almacenar la imagen.}
    property PathImage:string read FPathImage;
    {: Nombre completa (path+Nombre) de la imagen almacenada en disco local}
    property FileNameImage:string read FFileNameImage;
  end;

Al crear el Thread (método Create) ya pasamos como parámetros, la URL de la imagen a descargar y el Directorio inicial donde se van a guardar las imágenes encontradas.

El método Execute creamos un componente TidHTTP (igual a como lo hemos hecho antes), pero en este caso utilizamos un TFileStream para recoger el fichero que descargamos y almacenarlo en disco.

Utilizamos el Path de la URL para generar diferentes directorios para las diferentes imágenes:

···················································································································

URL: http://neftali.clubdelphi.com/images/GLibWMI_paleta_1.8b.png

Path: images

FileName: GLibWMI_paleta_1.8b.png

···················································································································

//: recupara la imagen y la guarda en disco
procedure TDownImageThread.Execute();
var
  Stream:TFileStream;
  IdH:TidHTTP;
  path:string;
  dir:string;
begin
  // Directorio de salida
  dir := AnsiReplaceText(PathURL, '/', STR_EMPTY);
  // Nombre vacío
  if (ImageName = STR_EMPTY) then begin
    Exit;
  end;
  // Path de salida
  path := IncludeTrailingBackslash(IncludeTrailingBackslash(PathImage)
          + dir) + ImageName;
  // Crearlo por si no existe
  ForceDirectories(ExtractFilePath(path));
  try
    // Stream para la imagfen
    Stream  := TFileStream.Create(path, fmCreate);
    try
      //recuperar la imagen
      IdH := TidHTTP.Create(nil);
      IdH.AllowCookies := True;
      // proteccion
      try
        IdH.Get(Trim( FURLImage), Stream);
      except
        // Error al descargar la imagen
        //..  Volcarlo al log
      end;
    finally
      // Liberar
      idH.Free;
      Stream.Free;
    end;
    // Path de salida
    FFileNameImage := path;
  except
    // error al crear el fichero
    //...  Log
  end;
end;

El resultado se puede ver en este ejemplo.

Una vez descargadas las imágenes se muestran en un componente en la misma aplicación, y desde ahí podemos acceder a la información de la imagen y realizar algunas acciones sobre ellas.

Para realizar pruebas podéis introducir, por ejemplo direcciones como:

Como siempre podéis descargar los fuentes y los binarios de ejemplos.

<DESCARGAR SOURCES>

<DESCARGAR BINARIO>


ACTUALIZACIÓN (26/02/2015): La página del ejemplo ha cambiado y ahora se accede por https. por lo tanto el enlace es:

https://sites.google.com/site/gmapsdevelopment/Home

Por lo tanto para poder descargar tanto la página inicial (de donde se extraen los enlaces),  como las imágenes en si, hay que modificar ligeramente el programa.

Hay que utilizar el componente TIdSSLIOHandlerSocket para poder utilizar SSL y añadir al proyecto as librerías de acceso a SSL.

No hay muchas modificaciones en el código, pero si queréis verlas, dejaré el código antiguo y el nuevo (compilado en Delphi 7) para que podáis compararlos.

<DESCARGAR SOURCES v2 HTTPS>

<DESCARGAR BINARIO v2 + DLL ssl>

<DESCARGAR DLL’s para acceder SSL>

NOTA: Para generar las imágenes en disco PNG he utilizado el componente “Portable Network Graphics Delphi” de Gustavo Huffenbacher Daud, que podéis encontrar y descargar de forma gratuita de Internet.


 

Un saludo.

Unir varias imágenes (TImage) en una sóla

jueves, 7 de octubre de 2010 Sin comentarios

Hay un ejemplo antiguo en la página en la sección de ejemplos, titulado «Trocear un bitmap en n imágenes a modo de puzle». Hoy ha salido en los foros una pregunta sobre la operación contraria, ¿Cómo unir varios bitmaps (TImage) en una única imagen?

Puede ser algo trivial para los que llevamos un tiempo en esto, pero no tanto para los que empiezan; Reconozco que yo al principio también me liaba con los Canvas, los Rect, los ClientRect y no sabía cual copiar en cada cual.  ;-)

El código para unir cuatro imágenes en una sóla formando un cuadro, es muy sencillo y sería algo así:

var
  ARect:TRect;
  path:string;
begin
 
  // Añadir los 4 canvas a la nueva imagen
  ARect.Left := 0;  ARect.Top := 0; ARect.Right := 48; ARect.Bottom := 48;
  imgDestino.Canvas.CopyRect(ARect, img1.Canvas, img1.ClientRect);
  ARect.Left := 48;  ARect.Top := 0; ARect.Right := 92; ARect.Bottom := 48;
  imgDestino.Canvas.CopyRect(ARect, img2.Canvas, img2.ClientRect);
  ARect.Left := 0;  ARect.Top := 48; ARect.Right := 48; ARect.Bottom := 92;
  imgDestino.Canvas.CopyRect(ARect, img3.Canvas, img3.ClientRect);
  ARect.Left := 48;  ARect.Top := 48; ARect.Right := 92; ARect.Bottom := 92;
  imgDestino.Canvas.CopyRect(ARect, img4.Canvas, img4.ClientRect);
 
  // Path para grabarla a disco
  path := ChangeFileExt(Application.ExeName, '.bmp');
  imgDestino.Picture.SaveToFile(path);
  MessageDlg('Se ha guardado la imagen con el nombre: ' +
             path, mtInformation, [mbOK], 0);

Si en lugar de unirlas formando un cuadro, se quieren unir de otra forma (las 4 en línea, por ejemplo), basta con cambiar las coordenadas de destino.

Si hubiera que cambiar el tamaño final, por ejemplo para reducirlo hasta el de las imágenes originales, se podrían aplicar técnicas de antialiasing al redimensionar.

Descargar ejemplo.

Un saludo.

Categories: Delphi, Ejemplos Tags: ,

Google Maps en Delphi – II

lunes, 29 de junio de 2009 37 comentarios

En la última entrada acerca de la API de Google Maps, vimos cómo mostrar un Mapa utilizando la API en un programa Delphi, cómo centrarlo en una posición predefinida y utilizando un Zoom predeterminado.

Además como seleccionar entre los diferentes controles que podemos añadir al mapa (Zoom, Vista general, tipo de mapa…).

También cómo colocar una marca en una ubicación y cómo generar una ventana con información asociada a esa marca (NOTA1).

NOTA1: De forma similar se pueden colocar otros elementos sobre el mapa, como:

  • Líneas, polilíneas y polígonos.
  • Marcas con iconos personalizados.
  • Rutas

Una vez visto cómo mostrar el mapa, lo que nos queda es ver cómo podemos, desde nuestro programa Delphi, interactuar con él; Es decir, que el usuario pueda modificar determinadas características del mapa que tiene en pantalla, y nosotros podamos recuperar esos cambios, para utilizarlos en nuestro programa.

Vamos a continuar con el ejemplo visto en las entradas anteriores; Mostraremos al usuario un Mapa ubicado en una determinada posición. El usuario debe poder «reubicar» la vista del mapa y modificar el Zoom con que está visualizando el mapa, y esos son los valores que obtendremos para posteriormente almacenarlos y actualizarlos en nuestro programa.

  • Coordenada de Longitud
  • Coordenada de Latitud
  • Zoom actual del mapa

La forma de conseguirlo, es añadir a la página web el código necesario para capturar eventos que se produzcan en el mapa. Incluiremos controles de edición, donde se almacenan la longitud/latuitud y Zoom, que después recuperaremos desde el programa Delphi.

GEvent.addListener(map, "click", function (overlay,point)
GEvent.addListener(map, "zoomend", function (oldLevel, newLevel)
GEvent.addListener(map, "mousemove", function(latlng)

Aunque uno no esté muy familiarizado con el tema (yo mismo no lo estoy mucho  ;-D ), no hacen falta muchas explicaciones para comprender los eventos; «Capturaremos» en OnClick, OnZoomEnd y OnMouseMove sobre el mapa. Aquí se puede acceder a la lista de eventos, métodos y propiedades de la clase Gmap.

En el caso del evento OnClick, por ejemplo, utilizaremos un código como este:

GEvent.addListener(map, "click", function (overlay,point){
if (point){
document.posicion.x.value=point.x
document.posicion.y.value=point.y
document.posicion.z.value=map.getZoom()
TipoMapa = map.getCurrentMapType().getName()
document.posicion.t.value=TipoMapa
}

Obtenemos información del punto actual (utilizando un parámetro) y el Zoom actual y el tipo de Mapa utilizando métodos de la clase GMap. Todos ellos se almacenan (como hemos comentado antes) en componentes de tipo Text, que nos sirven como «paso intermedio» para luego capturar esos valores de la página Web desde nuestro programa.

Como resultado final, os dejo el ejemplo que se adjunta con esta entrada. En él he incluído/integrado la parte de Geocodificación (visto en las entradas I y II), y el código y modificaciones necesarias para recuperar posición, Zoom y tipo de Mapa (este incluído a última hora) que el usuario selecciona en un Mapa.

Información capturada

La información de los lugares puede ser guardada y recuperada de un fichero de texto; La estructura es bastante simple y no hace falta mayor explicación. Se almacena en el mismo directorio de la aplicación y recibe el nombre de «Lugares.txt».

Recuperar y Guardar ubicaciones

La información que podemos capturar del Mapa (utilizando la clase GMap) y de otros elementos que estén incluíds en el mapa (imágenes, líneas, marcas,…) es muy extensa y está detallada en las referencias de la API de Google Maps.

Personalmente, creo que las posibilidades de ampliación son muy grandes y bastantes más sencillas de lo que a priori puede parecer.

Se puede descargar el ejemplo completo desde aquí.
<DESCARGAR EJEMPLO>

Espero que estas entradas hayan sido de utilidad. Como siempre cualquier comentario, corrección, sugerencia,… es bienvenida. ;-D

Un saludo.

ACTUALIZACIÓN (10 Febrero 2012): Dado el cambio de política de Google, ahora es necesario (obligatorio) colocar la key que se proporciona desde Google para poder utilizar la API. Es necesario modificar el fichero _mapa.txt del recurso y  recompilarlo utilizando RC.CMD.

 

Google Maps en Delphi – I

jueves, 14 de mayo de 2009 6 comentarios

Después de las dos entradas sobre Codificacióin Geográfica (*), toca entrar de lleno en la Visualización e Integración de Google Maps en nuestro programa, que por otra parte era el objetivo inicial de esta serie de entradas. La Codificación Geográfica (obtención de Latitud y Loingitud a partir de una dirección postal) era un «escollo» a salvar en nuestro camino, hasta nuestro verdadero objetivo.

(*) Lo normal es tener en nuestros programas/aplicaciones una serie de direcciones postales o direcciones de correo que deseamos mostrar o señalar en un Mapa. Para utilizar esas direccones con la API de Google Maps necesitamos obtener las coordenadas de Latitud y Longitud apropiadas. Para ello ya vimos  aquí (Codificación Geográfica – I) y aquí (Codificación Geográfica – II) cómo Google provee métodos para obtener las coordenadas de posicionamiento a partir de direcciones postales.

La idea para conseguir la integración es sencilla. Utilizar un componente TWebBrowser para mostrar una página HTML. Desde Delphi debemos «modificar» esa página para que muestre lo que nosotros deseemos.

Utilizando una sencilla página HTML con un Script, podemos visualizar el mapa correspondiente a coordenadas de Latitud y Longitud.  Con un componente TWebBrowser podemos visualizar esa página dentro de una aplicación delphi.

La página en sí sólo contiene el Script para Visualizar un Mapa.
Dentro del Script vemos cómo se crea un elemento de tipo «map»:

map = new GMap2(document.getElementById("map"));

Se añaden los controles que queremos visualizar en el mapa; En este caso, la selección para el tipo de mapa y control de zoom y posición grande.

        // Controles del mapa
        map.addControl(new GMapTypeControl());
        map.addControl(new GLargeMapControl());

El tipo de mapa que queremos que inicialmente aparezca (Mapa, visión por satélite o lo que Google llama híbrido).

        // Tipo de mapa
        map.setMapType(G_NORMAL_MAP);

Y por último colocamos la posición (latitud y longitud) donde queremos que el mapa salga centrado.

Pero no acaban aquí (ni mucho menos) las posibilidades de Google Maps. Una de las opciones, que dentro de lo sencillo, es muy interesante, es la inclusión de marcas señalando puntos del mapa o incluso ventanas de información no es mucho más complejo.

Para añadir una nueva marca, basta con conocer el punto exacto donde queremos situarla y utilizar un objeto GMarker para mostrarla en el mapa. En cuanto a la ventana, de información, sólo necesitamos el código HTML necesario para crearla.
En este ejemplo la ventana tiene un código sencillo (texto, imagen y link) que se almacena en una variable.

// VENTANA (HTML)
 var html="<img src="http://neftali.clubdelphi.com/images/imagen_neftali_60x54.jpg" alt="" width="60" height="54" />
" + "by Neftalí -Germán Estévez-  2009 <strong>
<a href="http://neftali.clubdelphi.com"
 target="_blank">http://neftali.clubdelphi.com</a>
</strong>
<a href="http://neftali.clubdelphi.com" target="_blank">
    </a>
";

Para mostrarla basta con que utilicemos en método OpenInfoWindowHtml (cuyo nombre es bastante descriptivo, por cierto ;-D ) de la siguiente forma:

    // Visualización de la mrca
    var point = new GLatLng(41.381655,2.122829);
    var marker = new GMarker(point);
    marker.openInfoWindowHtml(html);

Hay más opciones y basta con echarle una vistazo a la API de Google Maps para conocerlas. Además hay muchos ejemplos de utilización que pueden servir para aclarar los conceptos y para ver más cláramente cómo se utilizan los diferentes elementos.

Todo lo visto hasta aquí, está puesto en práctica en un ejemplo Delphi.

Podéis descargar el código completo (incluye EXE -comprimido UPX-) desde aquí:
<Descargar Ejemplo>

Y aquí acabamos esta entrada, que no será la última. Me dejo para una segunda parte, algunos detalles finales, como interactuar con el mapa y obtener datos de él y fusionar los dos conceptos vistos hasta ahora.

Nos vemos.

Redimensionar una imagen (Antialiasing)

lunes, 9 de marzo de 2009 13 comentarios

Hace unos días nos encontramos con el problema (no muy grande ;-D ) de añadir a una aplicación delphi existente la posibilidad de incluir una imagen seleccionada por el usuario. A priori la imagen era un JPG,  de la cual se debía crear una miniatura (thumbnail) a unas dimensiones determinadas (180 x 115) y ambas debían subir a un directorio determinado. Ningun problema.  Aquí mismo había un par de procedimientos de Domingo Seoane para redimensdionar una imagen.
En concreto modificando un poco el procedimiento Proporcional conseguí lo que necesitaba. Que si la imagen original no era exactamente de las mismas proporciones que la que necesitaba (miniatura) esta rellenara con un color «neutro» (en este caso el blanco) los bordes laterales.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Esta otra mantiene la relacion entre alto y ancho
procedure Proporcional(Imagen: TGraphic; Ancho, Alto: Integer);
var
  Bitmap: TBitmap;
  Rect:TRect;
begin
  Bitmap:= TBitmap.Create;
  try
    Bitmap.Width:= Ancho;
    Bitmap.Height:= Alto;
 
    /// Calculos para que quede proporcional
    if  (Ancho/Imagen.Width) &lt; (Alto/Imagen.Height) then  begin
      Alto:= Trunc((Ancho*Imagen.Height)/Imagen.Width);
    end
    else begin
      Ancho:= Trunc((Imagen.Width*Alto)/Imagen.Height);
    end;
 
    // posición nueva
    // Hay que centarla para que queden márgenes iguales a ambos lados
    Rect.Left := ((Bitmap.Width - Ancho) div 2);
    Rect.Top := ((Bitmap.Height - Alto) div 2);
    Rect.Right:= Rect.Left + Ancho;
    Rect.Bottom := Rect.Top + Alto;
 
    // Color neutro para márgenes
    Bitmap.Canvas.Brush.Color := clRed;
    // copiar
    Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
    Bitmap.Canvas.StretchDraw(Rect,Imagen);
    Imagen.Assign(Bitmap);
  finally
    Bitmap.Free;
  end;
end;

Hice un par de pruebas con imágenes y el resultado no fue exactamente lo que yo esperaba. El procedimiento era correcto, y funcionaba bien, pero las imagenes en minuatura presentaban Aliasing. Y siendo las miniaturas bastante pequeñas el efecto se notaba bastante.

Reducir tamaño de una imagen

Imagen generada

Ampliando un poco la imagen y comparándola con una generada con cualquier programa sencillo de retoque fotográfico se apreciaba bastante la diferencia entre ambas.

Comparación de las imágenes
Esto es lo que se conoce como aliasing. Se pueden encontrar múltiples definiciones y explicaciones de este problema en Internet (wiki), así que no explicaré aquí de que se trata.


APLICAR ANTIALIASING

La teoría dice que esto se soluciona aplicando algoritmos de altializasing, así me he puesto a hacer unas pruebas a ver qué resultado obtenía.Mi idea es modificar el color de cada uno de los pixels de la imagen teniendo en cuenta en color de los pixels que hay a su alrededor.

Qué pixels seleccionemos para ello y cuantos (distancia) determinará que el resultado sea más o menos satisfactorio, pero también afectará al tiempo de cálculo. Por lo que he leído esto es lo que se conoce como Supersampling/Multisampling.
Un ejemplo de diferentes selecciones de pixels se puede ver en la imagen siguiente:

En cada uno de estos casos se variará el color del pixel central teniendo en cuenta los colores de los pixels que hay a su alrededor.

Tipos de selección

A partir de aquí me he propuesto hacer algunas pruebas (sencillas) para comprobar si en los resultados se notaban cambios a simple vista.


PRUEBAS DE ALGORITMOS

Para los ejemplos he realizado una imagen sencilla, con varias líneas inclinadas, donde se aprecian bastantes «dientes de sierra» y algunas circunferencias. La imagen inicial es la que se ve en la figura siguiente con un tamaño inicial de 457 x 273 pixels.

La idea es reducir el tamaño de esa imagen hasta la mitad (más o menos) y a una cuarta parte aplicando antes un algoritmo de antialiasing sencillo escogiendo diferentes puntos para modificar el color de los pixels.

Para la reducción de tamaño, he utilizado un procedimiento estandard para reducir el tamaño de imágenes BPL utilizando (StretchDraw), pero en este caso, antes de hacer la reducción he probado a aplicar los algoritmos de AntiAliasing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Esta cambia el alto y ancho, estirando la imagen si es necesario
procedure Redimensionar(Imagen:TBitmap; Ancho, Alto: Integer);
var
  Bitmap: TBitmap;
begin
 
  Bitmap:= TBitmap.Create;
 
  // Aplicamos antialiasing
  Antialiasing(Imagen, Bitmap);
  Imagen.Assign(Bitmap);
 
  // reducir
  try
    Bitmap.Width:= Ancho;
    Bitmap.Height:= Alto;
    Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect, Imagen);
    Imagen.Assign(Bitmap);
  finally
    Bitmap.Free;
  end;
end;

Para modificar el color lo que he probado es a sumar los colores de los puntos escogidos al del pixel actual y luego hacer la media para obtener un color resultante; Así por ejemplo, para calcular el nuevo color de un pixel teniendo en cuenta el pixel superior y el inferior de la misma columna, utilizo un código como este:

1
2
3
4
5
6
  // R1 es el componente Red del pixel actual y R2 y R3 los del sup. e inferior.
  R1:=Round(R1 + R2 + R3 ) div 3;
  G1:=Round(G1 + G2 + R3 ) div 3;
  B1:=Round(B1 + B2 + b3 ) div 3;
  // color resultante
  Result := RGB(R1,G1,B1);

Lo que he hecho en las pruebas es aplicar a la imagen, esta mismo procedimiento, pero teniendo en cuenta diferentes selecciones de puntos.

  1. Seleccionando 2 puntos; Superior e inferior.
  2. Seleccionando 4 puntos; Superior, inferior, izquierda y derecha.
  3. Seleccionando 8 puntos. Los 8 puntos que hay alrededor del pixels actual.
  4. Seleccionando 8 puntos y aplicando ponderación al actual. Utilizar los 8 pixels que hay alrededor del actual, pero aplicando más peso (más valor) al pixels actual (a su color) que a los del resto. En mi caso el pisel actual tiene un peso de 4, mientras que el resto queda con un pero 1.

En un primer ejemplo he aplicado los dos primeros (2 y 4 pixels), pensando que no habría grandes cambios y la verdad es qe me ha sorprendido, ya que tomando tan sólo 2 puntos ya se notan algunos cambios y tomando 4 las dioferencias ya son bastante apreciables.

Descargar ejemplo 1

El resultado obtenido por este ejemplo es el siguiente:

La imagen superior es el original (redimensionado tal como lo hace delphi), y las dos inferiores son a las que se les ha aplicado el procedimiento de Antialiasing antes de redimensionarlas. En una escogiendo 2 los pixels laterales y en la otra los 4 pixels que rodean al del cálculo. Superior, inferior,  izquierdo y derecho.

Como se puede ver, con dos pixels únicamente, ya hay zonas (1, 3 y 5) donde se aprecian diferencias. Seguramente en estas más que en otras porque la selección de pixels no es homogénea (de ahí que en las líneas horizontales se aprecie más mejora).

Cuando se aplica el algoritmo teniendo en cuenta los 4 pixels de alrededor, se aprecia (2, 3, 4 y 5) ya bastantes diferencias.

En el segundo ejemplo he aplicado los 4 casos comentados antes.

Descargar ejemplo 2

El resultado de este segundo ejemplo es el siguiente:

En este caso entre los dos últimos no se aprecia diferencia visible, pero sí entre escoger 4 puntos y 8 puntos. Ver los puntos marcados como 1 y 3.

Dado que no se aprecian grandes diferencias entre los dos últimos, he integrado en un último ejemplo el redimensionado y el procedimiento de Antialiasing, de forma que este segundo se realice de forma automática.

Descargar el ejemplo 3

CONSIDERACIONES FINALES

Aunque el ejemplo que se ha desarrallo aquí y el procedimiento parece que funcionan de manera aceptable, hay que tener en cuenta otros factores a la hora de realizar un algoritmo más completo.

En nuestro caso la distancia de pixel utilizada (muestreo) es una distancia 1; es decir, hemos seleccionado los pixels que hay más cercanos al que vamos a modificar. Podemos seleccionar pixels de distancias mayores (2 y 3); De esta forma el resultado puede ser más correcto, aunque esto también tiene que ver con el porcentaje de reducción del tamaño.

No es lo mismo reducir una imagen a la mitad de su tamaño, que al 10% del tamaño original.  Segun el caso el resultado puede ser mejor o peor si seleccionamos pixels a distancias 1,2 y 3 del pixels a calcular.

El procedimiento final para BMP’s quedaría así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
type
  TRGBTripleArray = array[0..32767] of TRGBTriple;
  PRGBTripleArray = ^TRGBTripleArray;
...
// Esta cambia el alto y ancho, estirando la imagen si es necesario
procedure Redimensionar(Imagen:TBitmap; Ancho, Alto: Integer);
var
  Bitmap: TBitmap;
  //····························································
  // Procedimiento de Antialiasing con Distancia=1
  procedure Antialiasing(bmp1, bmp2:TBitmap);
  var
    r1,g1,b1:Integer;
    Y, X, j:integer;
    SL1, SL2, SL3: PRGBTripleArray;
  begin
 
    // Tamaño del bitmap destino
    bmp2.Height := bmp1.Height;
    bmp2.Width := bmp1.Width;
    // SCANLINE
    SL1 := bmp1.ScanLine[0];
    SL2 := bmp1.ScanLine[1];
    SL3 := bmp1.ScanLine[2];
 
    // reorrido para todos los pixels
    for Y := 1 to (bmp1.Height - 2) do begin
      for X := 1 to (bmp1.Width - 2) do begin
        R1 := 0;  G1 := 0; B1 := 0;
        // los 9 pixels a tener en cuenta
        for j := -1 to 1 do begin
          // FIla anterior
          R1 := R1 + SL1[X+j].rgbtRed    + SL2[X+j].rgbtRed    + SL3[X+j].rgbtRed;
          G1 := G1 + SL1[X+j].rgbtGreen  + SL2[X+j].rgbtGreen  + SL3[X+j].rgbtGreen;
          B1 := B1 + SL1[X+j].rgbtBlue   + SL2[X+j].rgbtBlue   + SL3[X+j].rgbtBlue;
        end;
        // Nuevo color
        R1:=Round(R1 div 9);
        G1:=Round(G1 div 9);
        B1:=Round(B1 div 9);
        // Asignar el nuevo
        bmp2.Canvas.Pixels[X, Y] := RGB(R1,G1,B1);
      end;
      // Siguientes...
      SL1 := SL2;
      SL2 := SL3;
      SL3 := bmp1.ScanLine[Y+1];
    end;
  end;
  //····························································  
begin
 
  Bitmap:= TBitmap.Create;
 
  // Aplicamos antialiasing
  Antialiasing(Imagen, Bitmap);
  Imagen.Assign(Bitmap);
 
  // reducir
  try
    Bitmap.Width:= Ancho;
    Bitmap.Height:= Alto;
    Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect, Imagen);
    Imagen.Assign(Bitmap);
  finally
    Bitmap.Free;
  end;
end;

Componente TSaveComps

domingo, 1 de marzo de 2009 9 comentarios

(versión 1.4)

Permite guardar la posicion y tamaño de todos los componentes que se encuentran en el formulario. Utilizapara ello un fichero INI.
Basta con colocar el componente en el formulario y activarlo; Cuando la aplicación se cierra graba la posición/tamaño y al volver a ejecutarla los recupera de forma automática.

NOTA: Es indispensable para grabar la posición y tamaño de un componente que tenga definida la propiedad Name (para controles creados en RunTime).

Imagen del ejemplo

Historial:
(version 1.4): Añadido un evento (OnNotExistComponent) que facilita el trabajo con componentes creados en tiempo de ejecución (runtime); Se han revisado los componentes para trabajar con Delphi 2005/2006.

(versión 1.3): El componente permite guardar propiedades de tipo TStrings (Lines, Items,…)

(versión 1.2): Para la versión 1.2 se ha añadido la posibilidad de poder añadir propiedades por parte del usuario que se grabarán (propiedad SavedProperties).

Download Descargar componente

Categories: Componentes Tags: , ,

Trocear un Bitmap a modo de puzzle en n imagenes

domingo, 2 de marzo de 2008 Sin comentarios

Éste ejemplo muestra cómo «trocear» una imagen (un bitmap en éste caso) en n pequeñas imágenes a «modo de cudrícula»; El número de imágenes (de ancho y de alto) se puede configurar y finalmente las n partes de la imagen se guardan en disco.

Imagen del ejemplo

Las imágenes resultantes de la división se guardan en disco.

Download Descargar ejemplo

Categories: Delphi, Ejemplos Tags: ,

Dibujar porcentaje en una celda de un Grid

sábado, 19 de enero de 2008 8 comentarios

En este ejemplo se muestra cómo dibujar manualmente una barra de porcentaje en una celda de un DBGrid. Presuponemos que en la celda en la que vamos a dibujar la barra se está mostrando un valor entre 0 y 100 que pertenece a un porcentaje. Este ejemplo muestra cómo se hace para un componente TDBGrid estándard; No es muy difícil adaptarlo para utilizarlo en un TStringGrid o similar.

Dibujar porcentaje en Grid

Download Descargar ejemplo

(Actualizacion 17/05/2021) He actualizado el ejemplo para mostrar cómo se utiliza el mismo evento para realizar esta acción sobre varias columnas.

Download Descargar ejemplo con 2 columnas

Categories: Ejemplos, VCL Tags: , , ,

Ejemplo de tratamiento de «Planos y figuras»

viernes, 4 de enero de 2008 5 comentarios

Es bantante común encontrarse en programación con aplicaciones que requieren una interface del tipo «plano y figuras». Son aquellos programas cuya entrada de datos se realiza a partir de un formulario que presenta un plano y donde se deben poder «colocar» elementos/objetos que después se utilizarán en el programa.

Planos de ejemplo

En éstos proyectos suele haber dos «modos de trabajo» básicos:

  • Modo Administrador: Se utiliza para configurar el escenario de trabajo. Seleccionar un Mapa, y crear los objetos, con las propiedades que luego utilizará el programa. Un mismo programa puede trabajar con varios escenarios.
  • Modo Explotación: Es el modo en que se trabaja con el programa normalmente; Se basa en una o varias configuraciones que se han creado anteriormente en el «modo administrador».

Como ayuda a éste tipo de Interfaces de cara al usuario, se han creado los componentes TSaveComps y TSelectOnRuntime que puedes encontrar en la sección de componentes de ésta página. Y como muestra para éstos dos componentes se ha creado ésta demo. Muestra cómo sería su utilización en una interface sencilla, que en éste caso simula un restaurante. Muestra el funcionamiento básico de ambos modos de trabajo.

Imagen de la demo

Download Descargar ejemplo