PDA

Ver la Versión Completa : Manejar Trozos de BMP


Deiv
03-06-2006, 22:19:56
Hola!
Como novato acabo de darme cuenta que en Delphi se puede manejar trozos de un BMP (Números graficados por así decirlo=0123456789 dibujados en un solo BMP [con una determinada altura y ancho]) y que estos se puedan mostrar en un TPanel o TPaintBox, solo cierta parte. Vi este ejemplo en una Aplicación como ejemplo pero ejecutable ¿Como se realiza este proceso?

1.- Me explico: por así decirlo necesito mostrar solo el "4" y el "9" adyacentemente de la "Cadena BMP" = '0123456789' (gráficado) ¿como lo hago?
2.- De mostrarlo, ¿como simular un parpadeo (blinkado) con un trozo de BMP, el "4" (parpadeando) por así decirlo y el "9" nada que ver?
3.- ¿Donde es más adecuado (óptimo) mostrar este trozo de BMP? ¿En un TPanel? ¿En un TPaintBox? ¿En un TIMage? ¿En un TForm directamente? ¿Es indiferente según necesidades?

Saludos

Deiv
08-06-2006, 02:08:46
He encontrado en la página http://www.latiumsoftware.com/es/pascal/0012.php se asemeja a lo que requiero, pero este recorta seleccionando la imagen con el mouse, Lo que intento es realizar un cierto cálculo y como resultado obtenga un número (en integer o en string) pero que de alguna manera lo relacione con el BMP graficado del 0 al 9 y pueda mostrar solo aquel que me interese del BMP
¿Como relaciono ese cálculo para que pueda recortar solo una parte del BMP y mostrar lo que requiero?

Sobre el blinkado, me parece que debo crear un Gif, la pregunta es si tuviera que hacer todos los números (0-9) y todo el abecedario (A-Z) sería un trabajo tedioso. ¿No habrá forma de (relacionado a mi primera pregunta) de capturar sola una parte del BMP y hacerla blinkar realizando otra BMP de números de color diferente?

madriles
10-06-2006, 10:05:08
hola
para lo que tu quieres, yo usaria un TPanel y dentro un TImage, cargado con el bmp con los numeros.
en el ejemplo de codigo he usado unos TSpeedButton con los numeros del 0 al 9. El TPanel tiene que tener el ancho de un numero cualquiera, que sera, logicamente, la decima parte del bmp


//comun a todos los botones de numeros
procedure TForm1.SpeedButton10Click(Sender: TObject);
begin
Image1.Left := -(StrToInt((Sender as TSpeedButton).Caption) * Panel1.Width);
end;


para el tema del parpadeo, puedes hacer mas o menos lo mismo pero con la propiedad Top del TImage, y el bmp hacerlo el doble de alto, la parte de arriba con el numero en verde y la de abajo en rojo, por ejemplo de forma que, usando un TTimer te vaya pasando de rojo a verde segun el intervalo que le pongas.
espero haberte aclarado algo, un saludo

Deiv
11-06-2006, 01:47:58
He encontrado ejemplos como este:
procedure TForm1.Button1Click(Sender: TObject);
var
b:TBitmap;
RDest, RSource: TRect;
begin
b := TBitmap.Create();
b.Width := 100;
b.Height := 100;
// Creamos las zonas de copia origen y destino
RDest := Rect(0,0,100,100);
RSource := Rect(0,0,100, 100);
// Copiar parte del form al bitmap
b.Canvas.CopyRect(RDest, Self.Canvas, RSource);
end;

El ejemplo que encontré entre algunos, siempre se basan midiendo de un TPaintBox, TImage o de un TPanel PEGADOS al Form (es decir en el formulario están como OBLIGADOS uno de estos objetos para calcularlos con el CopyRect). Pero no encuentro un ejemplo que teniendo el BitMap en mi Directorio calcular (un x-ancho) y mostrarlo evidentemente en un TPaintBox, TImage, TPanel o en el Form solo UNA PARTE del BMP después de cierto cálculo.

Intentaré explicarlo sencillamente, tengo un TButton y un TPanel (con 2 TImage)...... ojo que no se si elegí la forma correcta aquí de los componentes, derepente hubiera sido mejor mostrarlos en un TpaintBox o directamente en el Form en cierta posición, no sé:

Case Num of //Después de un cálculo
0: //Mostrar solo el "Cero" de toda la imagen "BMPFuente" que tiene dibujado=0123456789 de 32 de alto x 320 pixels largo
1: //Mostrar solo el "1" de toda la imagen "BMPFuente" que tiene......... x 320 pixels largo (10 pixels para cada uno)
2: //Mostrar solo el "2" de toda la imagen "BMPFuente".........
....
end;

En el Case para cada caso mostraría un número de miBMP recortado en los TIMage contenidos en el TPanel o en un TPaintBox.

Quizá me digan que más sencillo resultaría crear BMPs para cada uno y mostrarlos.... de acuerdo! pero lo que no quiero es llenar por ejemplo de 10 BMPs como fuente de números en mi Directorio, mucho menos de 23 BMPs del Abecedario. Prefiero crear uno LARGO (uno solo) conteniendo a todos, para luego recortarlos uno a uno y mostrarlos según necesidades y cálculo.

Como dije arriba, de los ejemplos que encontré en la Red, todos se basan en el CopyRect teniendo el gráfico en el Form, y así calculando sus medidas y recortarlo. Lo que yo necesito es ver la forma de hacer ese recorte sin que se vea (sin que se encuentre) en el Form, solo sabiendo las medidas de mi BMP que se encuentra en mi directorio y tomando en el Case un ancho diferente para cada uno.

- Luego será otro lo del blinkado.

seoane
11-06-2006, 03:12:39
Vamos a ir por partes, o mejor por trozos ;)

Primero lo que tu pides:

procedure DibujarTrozo(Filename: string; Count, Index: Integer; Dest: TCanvas);
var
Ancho: Integer;
begin
with TBitmap.Create do
try
LoadFromFile(Filename);
Ancho:= Width div Count;
Dest.CopyRect(Rect(0,0,Ancho,Height), Canvas,
Rect(Ancho*Index,0,Ancho*(Index+1),Height));
finally
Free;
end;
end;


Para utilizar esa funcion, pasale como parametro la ruta del bmp con los diferentes dibujos uno a continuacion del otro en horizontal, pasale tambien el numero de elementos que contine y el indice del que quieres dibujar teniendo en cuenta que el primero sera el 0 y el ultimo Count-1. Por ejemplo, si el bitmap tiene 10 elementos:


// Dibujamos el trozo sobre el propio formulario
DibujarTrozo('d:\1.bmp',10,0,Canvas);
// Dibujamos el Trozo sobre un TPaintBox
DibujarTrozo('d:\1.bmp',10,9,PaintBox1.Canvas);
// Dibujamos el Trozo sobre un TImage
DibujarTrozo('d:\1.bmp',10,5,Image1.Canvas);


Ahora te digo lo que haria yo, utilizaria un TImageList y en el OnCreate del formulario utilizaria esto para cargar las imagenes:


var
Bitmap: TBitmap;
begin
Bitmap:= TBitmap.Create;
try
Bitmap.LoadFromFile('d:\1.bmp');
ImageList1.Width:= Bitmap.Width div 10; // 10 Elementos
ImageList1.Height:= Bitmap.Height;
ImageList1.Masked:= FALSE;
ImageList1.Add(Bitmap,nil);
finally
Bitmap.Free;
end;
end;


Y luego cada vez que lo quisiera dibujar utilizaria esto otro:

// Esto por ejemplo dibuja el trozo numero 6
ImageList1.Draw(Canvas,0,0,5);
// Y esto por dibuja el trozo numero 10 en un TPaintbox
ImageList1.Draw(PaintBox1.Canvas,0,0,9);


Tu decides ...

madriles
11-06-2006, 11:14:10
Hola Deiv
la verdad es que no entiendo realmente tu problema ¿ estas obligado a cargar la imagen ?, por supuesto, siempre tendras que cargarla en memoria para hacer los calculos, da lo mismo el sistema que uses. ¿Que problema te supone cargar un JPG de 32*320 pixel?, son 5 Kb. Ademas, teniendola en tu ejecutable te evitas que por error borren tu imagen del directorio y te salte una excepcion.
Con la solucion que te propongo solo tienes que tener un TPanel mas en tu formulario (de 32 * 32 pixel) que contiene la imagen completa y luego solo es cuestion de moverla con un calculo sencillo como es, en tu caso


Image1.Left := -(Num * 32);//ya que 32 es tu ancho fijo de dibujo


tienes, por supuesto, muchas otras soluciones, pero mas sencillas y con menos codigo...

bueno, tu tienes la ultima palabra, utiliza la solucion que mas te convenga y haznos saber como te queda
un saludo

Deiv
11-06-2006, 16:38:12
Gracias amigos, en este momento no dispongo de Delphi, llegando a casa probaré las sugerencias y luego les comento.
Saludos

Deiv
12-06-2006, 00:42:16
Gracias Seoane (interesante tu nueva identificación "Registered User") y gracias Madriles por sus orientaciones, me solucionaron el caso, tienen razón existe muchas formas, yo ya la estaba viendo "cuadrado" pensando que no había solución, ahora solo me queda como realizar el BLINKADO con un TTimer para el mismo caso.

madriles
12-06-2006, 20:01:15
hola de nuevo,
para el parpadeo del bmp, siguiendo con mi propuesta, solo tienes que hacer el bmp el doble de alto, en la parte superior el numero normal y en la parte de abajo el numero de parpadeo, nose en color verde por ejemplo asi con este codigo u otro parecido lo consigues


procedure TForm1.Timer1Timer(Sender: TObject);
begin
if Image1.Top = 0 Then
Image1.Top := -32 else
Image1.Top := 0;
end;


un saludo

Deiv
20-06-2006, 19:39:44
No consigo transparentar la parte que recupero del BitMap he colocado el código, en TFormCreate:
TransparentBmp.TransparentColor := clWhite;

TransparentBmp.Transparent := True;

al código de arriba:


procedure DibujarTrozo(Filename: string; Count, Index: Integer; Dest: TCanvas);
var
Ancho: Integer;
begin
with TBitmap.Create do
try
LoadFromFile(Filename);
Ancho:= Width div Count;
Dest.CopyRect(Rect(0,0,Ancho,Height), Canvas,
Rect(Ancho*Index,0,Ancho*(Index+1),Height));
finally
Free;
end;
end;

Mi BitMap tiene fondo blanco, y con el DRAW me dibuja todo pero transparente, en cambio según el código de arriba no logro transparentarlo. Una ayuda please.

Saludos

seoane
22-06-2006, 18:46:20
No consigo transparentar la parte que recupero del BitMap
...

Mi BitMap tiene fondo blanco, y con el DRAW me dibuja todo pero transparente, en cambio según el código de arriba no logro transparentarlo. Una ayuda please.


No es la forma mas elegante de hacerlo pero si muy sencilla de entender, vamos comprobando pixel a pixel y solo copiamos los que no son blancos :p


procedure DibujarTrozo(Filename: string; Count, Index: Integer; Dest: TCanvas);
var
Ancho: Integer;
i,j: Integer;
begin
with TBitmap.Create do
try
LoadFromFile(Filename);
Ancho:= Width div Count;
for i:= 0 to Ancho - 1 do
for j:= 0 to Height -1 do
if Canvas.Pixels[(Ancho*Index)+i,j] <> clWhite then
Dest.Pixels[i,j]:= Canvas.Pixels[(Ancho*Index)+i,j];
finally
Free;
end;
end;


De todas yo consideraria la posibilidad de usar un TImageList como te sugeri un poco mas arriba.

Deiv
23-06-2006, 18:54:29
Gracias Seoane, funciona!

Deiv
27-06-2006, 15:00:23
Probé el consejo de Seoane con el TImageList, y modifiqué un poco el código para transparentarlo de la siguiente forma:
var
Bitmap: TBitmap;
begin
Bitmap:= TBitmap.Create;
try
BitMap.LoadFromFile(FileName);
ImageList1.Width:= BitMap.Width div 10; // 10 Elementos
ImageList1.Height:= BitMap.Height;
ImageList1.BkColor:=clNone;
ImageList1.BlendColor:= clNone;
ImageList1.DrawingStyle:= dsTransparent;
ImageList1.Masked:= True;
ImageList1.AddMasked(Bitmap, Bitmap.Canvas.Pixels[0,0]);
finally
BitMap.Free;
end;
end;
Funciona bien.
He cargado 2 PaintBox capturando en ellos diferentes trozos del BitMap que tengo:

ImageList1.Draw(PaintBox1.Canvas,0,0,0);
ImageList1.Draw(PaintBox2.Canvas,0,0,1);

Todo bien, he intendado MOVERLOS y cruzar a ambos manteniendo su transparencia con TTimer, y ahí tengo un problemita del cual
no me doy cuenta, y requiero de vuestra ayuda:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
PaintBox1.Left:=PaintBox1.Left+2;
PaintBox1.Repaint;
ImageList1.Draw(PaintBox1.Canvas,0,0,0);
PaintBox2.Left:=PaintBox2.Left-2;
PaintBox2.Repaint;
ImageList1.Draw(PaintBox2.Canvas,0,0,1);
end;
Necesitaba sobreponer uno sobre el otro en el momento de cruce transparentes. Arriba lo que hace es uno sobrepone al otro
pero sin transparentarlo (lo tapa, o lo cubre). Es decir necesito en el momento de cruce dibujar uno y encima el otro, pero
mostrando ambos ¿Donde voy mal?
Pd.- Tal vez no me estoy dejando entender si el código de arriba no estuviera en un TTimer, y los ubico en posición de cruce
(left) me muestra bien a ambos (sin TTimer) es lo que requiero en realidad pero que eso se vea así al momento de cruce.
Gracias y saludos

Deiv
03-07-2006, 14:32:54
Finalmente, para el poco conocimiento que tengo logre lo que quería, tuve que darle muchas vueltas al código y finalmente comprendí que el orden de las líneas estaban mal. Este funciona:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
PaintBox1.Left:=PaintBox1.Left+2;
PaintBox1.Repaint;
PaintBox2.Left:=PaintBox2.Left-2;
PaintBox2.Repaint;

ImageList1.Draw(PaintBox1.Canvas,0,0,0);
ImageList1.Draw(PaintBox2.Canvas,0,0,1);
end;
Ahora estoy enredado en otro, estoy intentando blinkar habiendo creado el doble de alto como sugirió madriles, pero el ejemplo de arriba está dado para un TImage con la propiedad Top, y yo estoy trabajando con una TImageList como mencioné en mi último post y este no tiene la propiedad Top????

var
Bitmap: TBitmap;
implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
Bitmap:= TBitmap.Create;
try
BitMap.LoadFromFile(getcurrentdir+'/BigBmp.bmp');
ImageList1.Width:= BitMap.Width div 10; // 10 Elementos
ImageList1.Height:= BitMap.Height div 2; //Muestro solo la parte superior del BitMap de doble alto
ImageList1.BkColor:=clNone;
ImageList1.BlendColor:= clNone;
ImageList1.DrawingStyle:= dsTransparent;
ImageList1.Masked:= True;
ImageList1.AddMasked(Bitmap, Bitmap.Canvas.Pixels[0,0]);
finally
BitMap.Free;
end;
end;
¿Como podría blinkar esa sección del TImageList?