PDA

Ver la Versión Completa : Proyecto: Imágenes de Flickr


angelillo182
23-04-2006, 20:45:52
Planteamiento:
Tenemos un proyecto escolar en Delphi que utiliza las fotografías de Flickr para regresarme resultados. En sí, es un buscador de fotografías en Internet pero específicamente en Flickr (http://www.flickr.com). No puedo poner un título exacto acerca de mi problema, prefiero abrir un hilo y ahí siempre manejar el mismo proyecto. Gracias a Dec que ya nos estuvo ayudando anteriormente, y nos recomendó la herramienta dFlickr.
Hemos avanzado, encontramos que el método de respuesta que utiliza Flickr es através de XML. Hemos podido interpretar ese código XML para adecuarlo y obtener una URL estática para desplegar la imagen en un WebBrowser.
Hasta ahí todo bien.

Problema actual:
Ahora queremos saber cómo desplegar varias imágenes en el programa sin tener que llenar de WebBrowsers la pantalla; sería algo como las vistas en miniatura de Windows. Una imagen sugerida del programa sería ésta: http://img396.imageshack.us/img396/5631/flickr2fy.jpg (http://img396.imageshack.us/my.php?image=flickr2fy.jpg)
Si no me expliqué bien pueden preguntar. Gracias!

dec
23-04-2006, 21:09:18
Hola,

A ver. Creo que ya trataron de responderte en el anterior Hilo en que planteaste la cuestión: por eso es mejor continuar los Hilos hasta su término, es decir, según con la cuestión de marras en un Hilo, porque, de lo contrario, los Hilos acaban "separados" y un tanto sin sentido. Lo dice la guía de estilo (http://www.clubdelphi.com/foros/guiaestilo.php#nadie)de los Foros, no me estoy inventando nada.

A mí lo primero que se me ocurre sobre lo que dices es lo siguiente. Tú obtienes una seride "URLs" de determinadas imágenes. Pretendes mostrar dichas imágenes en un componete "TWebBrowser" y no me parece mal, a bote pronto, puesto que ese componente trabaja con el "lenguaje de etiquetas o marcas" HTML, el cual puede echarte una mano por sí mismo, y si lo unes a "CSS" (Cascading Style Sheet) pueden ser sorprendentes los resultados.

Entonces, ¿cuál es el problema? Que según parece tú ves necesario contar con un "TWebBrowser" por cada una de las imágenes que quieras mostrar, pero, esto no tiene mucha lógica, como comprenderás enseguida. Primeramente, el componente "TWebBrowser" no está pensado para mostrar imágenes por sí solas sino, como he dicho, su misión es la de mostrar al usuario el resultado de interpretar código HTML, CSS, JavaScript, y otros.

Entonces y, antes de que se me ocurra que puede resultar mejor de otro modo, ¿qué tal si creas en tiempo de ejecución un archivo HTML que contenga el código necesario (las etiquetas IMG de HTML que te sean menester) que muestre cada una de las imágenes que obtengáis de una determinada búsqueda, precisamente, a partir de las URLs de dichas imágenes? Ese archivo puedes luego cargarlo en el "TWebBrowser" y punto pelota.

Es decir, supongamos que obtenemos tres imágenes de una determinada búsqueda, con URLs sencillitas para no liarnos demasiado. Ejemplos de URLs que obtenemos como resultado de las búsquedas:


http://www.flickr.com/juan/img/001.jpg
http://www.flickr.com/juan/img/002.jpg
http://www.flickr.com/juan/img/003.jpg


Nada te impide, a partir de esa información, crear un archivo HTML (en realidad es un archivo de texto plano, con extensión ".htm" o ".html" para que el "TWebBrowser" lo "carge sin preguntar"), digo, un archivo como el siguiente, más o menos, claro... (nota que encierro el código entre etiquetas PHP por motivos de legilibilidad, pero no hay código PHP, sólo HTML)


<html>
<body>
<p>
<img src="http://www.flickr.com/juan/img/001.jpg" alt="Juan en la playa" />
</p>
<p>
<img src="http://www.flickr.com/juan/img/002.jpg" alt="Juan en la montaña" />
</p>
<p>
<img src="http://www.flickr.com/juan/img/003.jpg" alt="Juan en su moto" />
</p>
</body>
</html>


Ese archivo puedes guardarlo en el disco duro (aunque sea temporalmente) y mostrarlo (con el método "Navigate" del "TWebBrowser", por ejemplo) y... ya estás mostrando las tres imágenes en un mismo "TWebBrowser"... Ahora es cuestión de que "pongas guapo" al código HTML como mejor te parezca, es decir, que utilizes este lenguaje hasta donde quieras o sepas. Ya he comentado que si le añades un poco de código CSS los resultados pueden sorprender, y, bueno, porqué no, algo de JavaScript que le dé cierto glamour a la cosa... ¿no se dice así?

No sé. Ya dirás qué te parece de todo lo dicho, porque menudo rollo que acabo de soltar. ;)

angelillo182
30-04-2006, 17:57:37
David: ya lo hice y funcionó como esperaba. Nunca se me ocurrió darle formato con HTML, usé CSS y quedó mejor :D Gracias

Ahora mi nueva duda es acerca de XML-RPC. ¿Cómo puedo mandar un Request? En Flickr me dan la opción de mandar de tres maneras diferentes: XML-RPC, SOAP o REST. Leí acerca del tema y al parecer es más simple hacerlo con REST, aunque no sé acerca de esto y me gustaría que me orientaran sobre cual sería el indicado.
Quisiera saber cuales componentes necesito para enviar un Request (Una solicitud como cliente) y a dónde se van los datos de la respuesta que me mandan (Un XML en éste caso).
Los siguientes links van hacia la documentación de Flickr sobre esos formatos. Ya ustedes me orientarán. Muchas gracias!Request Formats
REST (http://www.flickr.com/services/api/request.rest.html)
XML-RPC (http://www.flickr.com/services/api/request.xmlrpc.html)
SOAP (http://www.flickr.com/services/api/request.soap.html)Response Formats
REST (http://www.flickr.com/services/api/response.rest.html)
XML-RPC (http://www.flickr.com/services/api/response.xmlrpc.html)
SOAP (http://www.flickr.com/services/api/response.soap.html)

Actualización al 22 de Mayo: Ya hago Request, ya me responden. Ahora quisiera alguna recomendación sobre lo siguiente.
En el programa aparecen las fotos en el WebBrowser ¿Cómo puedo hacer para bloquear y/o calificar las que escoja? Algo como Click derecho - Bloquear
Eso lo he visto hecho en nuevas tecnologías de Web como AJAX, pero no se si usando algún componente de Delphi pueda funcionar mejor. También leí que con JavaScript se puede, tendría que aprenderlo también.
Al bloquear alguna imagen sus datos se guardarán en una base de datos, al igual que al calificarlas. ¿Puedo de alguna manera mandar como parámetros esos datos hacia una variable o componente de Delphi desde el WebBrowser?

Ojalá y capten la idea :confused:

angelillo182
28-05-2006, 09:13:07
Bueno... sin mucho preámbulo. El profe nos cambió la jugada. Ya no quiere que despleguemos las imágenes en un WebBrowser, las quiere en un ListView.
Hay que abrir las imágenes y poder modificarlas en una interfaz casi clon de Explorer. Abrir, borrar, y que las imágenes se vayan guardando en una base de datos como caché.
Y todo eso con fecha límite de miércoles 31 de mayo.
Sí... 4 dias.
Ya estoy leyendo pero es demasiada información la que leo y poco lo que de verdad me sirve. Por favor ayúdenme.

Dudas mayores:
- ¿De que tipo de dato se hace el campo de una base de datos que guarda imágenes?
- Cómo puedo abrir varias imagenes desde URL's con ImageList y ListView?
osea.. con el XML logro hacer URL de imágenes... como las despliego en el TreeView?
- El manejador de base de datos de Delphi 7 (Database Desktop) me sirve también para guardar las imágenes o tengo que usar uno distinto?
- Las imágenes que me regresa Flickr son siempre JPG. Al parecer ImageList solo abre imágenes .bmp y .ico; ¿cómo puedo arreglar eso?

Estaré muy pendiente del tema, de antemano gracias.

seoane
28-05-2006, 12:30:47
Bueno, yo puedo quitarte algo de trabajo:



uses WinInet, JPEG;

function DownloadToStream(Url: string; Stream: TStream): Boolean;
var
hNet: HINTERNET;
hUrl: HINTERNET;
Buffer: array[0..10240] of Char;
BytesRead: DWORD;
begin
Result := FALSE;
hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if (hNet <> nil) then
begin
hUrl := InternetOpenUrl(hNet, PChar(Url), nil, 0,
INTERNET_FLAG_RELOAD, 0);
if (hUrl <> nil) then
begin
while (InternetReadFile(hUrl, @Buffer, sizeof(Buffer), BytesRead)) do
begin
if (BytesRead = 0) then
begin
Result := TRUE;
break;
end;
Stream.WriteBuffer(Buffer,BytesRead);
end;
InternetCloseHandle(hUrl);
end;
InternetCloseHandle(hNet);
end;
end;

function DownloadToBmp(Url: string; Bitmap: TBitmap): Boolean;
var
Stream: TMemoryStream;
Jpg: TJPEGImage;
begin
Result:= FALSE;
Stream:= TMemoryStream.Create;
try
try
if DownloadToStream(Url, Stream) then
begin
Jpg:= TJPEGImage.Create;
try
Stream.Seek(0,soFromBeginning);
Jpg.LoadFromStream(Stream);
Bitmap.Assign(Jpg);
Result:= TRUE;
finally
Jpg.Free;
end;
end;
finally
Stream.Free;
end;
except end;
end;


La funcion DownloadToBmp se encarga de descargar una imagen jpeg de internet y la convierte automaticamente a Bmp. Una vez que tienes el bmp ya sabras tu lo que tienes que hacer con el.

Ejemplo de como usar la funcion:

var
Bitmap: TBitmap;
begin
Bitmap:= TBitmap.Create;
try
if DownloadToBmp('http://www.clubdelphi.com/images/clubdelphi.jpg', Bitmap) then
begin
// Aqui usa el bitmap para lo que quieras, yo por ejemplo lo guardo
Bitmap.SaveToFile('c:\prueba.bmp');
end;
finally
Bitmap.Free;
end;
end;

seoane
28-05-2006, 14:47:05
Bien ahora que tenemos las imagenes en un bmp, solo nos falta ajustar su tamaño y agregarlo al TListView. Para ajustar las imagenes tenemos 3 "sabores" diferentes :)


// Estira la imagen hasta ajustarla a los valores de Ancho y Alto
procedure Estirar(Imagen: TGraphic; Ancho, Alto: Integer);
var
Bitmap: TBitmap;
begin
Bitmap:= TBitmap.Create;
try
Bitmap.Width:= Ancho;
Bitmap.Height:= Alto;
Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect,Imagen);
Imagen.Assign(Bitmap);
finally
Bitmap.Free;
end;
end;

// Ajusta la imagen, manteniendo la proporcion entre ancho y alto,
// para que uno de los lados se ajuste al valor dado y recorta lo
// que sobra (Este es mi preferido)
procedure Recortar(Imagen: TGraphic; Ancho, Alto: Integer);
var
Bitmap: TBitmap;
begin
Bitmap:= TBitmap.Create;
try
if (Ancho/Imagen.Width) > (Alto/Imagen.Height) then
Alto:= Trunc((Ancho*Imagen.Height)/Imagen.Width)
else
Ancho:= Trunc((Imagen.Width*Alto)/Imagen.Height);
Bitmap.Width:= Ancho;
Bitmap.Height:= Alto;
Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect,Imagen);
Imagen.Assign(Bitmap);
finally
Bitmap.Free;
end;
end;

// Ajusta la imagen, manteniendo la proporcion entre ancho y alto,
// para que uno de los lados se ajuste al valor dado y rellena lo que
// falta con el color dado
procedure Rellenar(Imagen: TGraphic; Ancho, Alto: Integer; Color: TColor);
var
Bitmap: TBitmap;
R: TRect;
begin
Bitmap:= TBitmap.Create;
try
R:= Rect(0, 0, Ancho, Alto);
if (Ancho/Imagen.Width) < (Alto/Imagen.Height) then
R.Bottom:= Trunc((Ancho*Imagen.Height)/Imagen.Width)
else
R.Right:= Trunc((Imagen.Width*Alto)/Imagen.Height);
Bitmap.Canvas.Brush.Color:= Color;
Bitmap.Width:= Ancho;
Bitmap.Height:= Alto;
Bitmap.Canvas.StretchDraw(R,Imagen);
Imagen.Assign(Bitmap);
finally
Bitmap.Free;
end;
end;


Ahora que tenemos la imagen con el tamaño adecuado, solo falta añadirlo al TListview. Podemos usar una funcion como esta:

procedure Agregar(Url: string; Caption: string; ListView: TListView);
var
Bitmap: TBitmap;
ImageList: TImageList;
ListItem: TListItem;
begin
with ListView do
begin
ImageList:= TImageList(LargeImages);
if ImageList <> nil then
begin
Bitmap:= TBitmap.Create;
try
if DownloadToBmp(Url, Bitmap) then
begin
ListItem:= Items.Add;
ListItem.Caption := Caption;
// Aqui usar cualquiera de los metodos anteriores, el que mas te guste
Recortar(Bitmap, ImageList.Width, ImageList.Height);
ListItem.ImageIndex:= ImageList.Add(Bitmap,nil);
end;
finally
Bitmap.Free;
end;
end;
end;
end;



Por ultimo te dejo un ejemplito de todo trabajando.

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
ListView: TListView;
ImageList: TImageList;
begin
ListView := TListView.Create(Self);
ImageList:= TImageList.Create(Self);
ImageList.Height:= 100;
ImageList.Width:= 100;
ImageList.Masked:= FALSE;
with ListView do
begin
Parent := Self;
Align := alClient;
LargeImages:= ImageList;
for i:= 0 to 8 do
Agregar('http://www.clubdelphi.com/images/clubdelphi.jpg', 'Foto ' + IntToStr(i), ListView);
end;
end;

angelillo182
28-05-2006, 22:10:54
Gracias Seoane!
Ya estoy trabajando de nuevo desde cero, porque hasta la interfaz cambió. Estoy en proceso de implementar eso, voy a estar actualizando los avances.

Una duda: ¿Cómo puedo editar el texto que aparece cuando pones el cursor sobre un botón?

Algo así (http://img273.imageshack.us/img273/2135/algoasi6ez.jpg) es lo que sale pero no recuerdo el nombre... ese cuadrito ke da información de lo que hace el botón. (Eso es para hacer una interfaz más limpia en mi proyecto)

turminator
02-06-2006, 00:41:37
Si te refieres al tipico globo de información, debes modificar la propiedad Hint de tu objeto.

zurech
14-06-2006, 18:17:01
seoane tio eres dios :D me has salvado con ese codigo.
Gracias