PDA

Ver la Versión Completa : Rotación de bitmap caso especial


mrnovice
12-03-2008, 04:32:06
Saludos, necesito ayuda help!, soy un caso perdido :D, miren mi situación, es que busqué sobre como rotar una imagen JPEG

Pero esta requería ser rotado mediante una bitmap, y seguí buscando
Ví en los trucos y efectivamente funcionó, y me ha sido muy útil, sólo que para imágenes muy grandes se tarda(ya que utiliza el método por píxeles), y seguí buscando
Encontré una página efg lab creo, donde te muestra optimizaciones por medio del scanline y senos y thetas,y funcionó mejor y dentro de la página venía una optimización de el mismo a 400 X eso hubiera sido perfecto sí,al rotar no cortara la imagen a 90° y 270° ya que este funciona para cuadros(REF1) ya que al voltearlo me rellena con negro y yo solo quería rotarlo jejeXD
busqué otra opción pero es un poco más complicada y un poco menos efectiva pero funciona, sólo que tuve problemas al adaptarlo a un JPEG y a eventos on clic(REF2)Códigos
REF1

begin
BitmapRotated.Width := BitmapOriginal.Width;
BitmapRotated.Height := BitmapOriginal.Height;
BitmapRotated.PixelFormat := BitmapOriginal.PixelFormat; //Copy PixelFormat
{$IFDEF Paletted}
BitmapRotated.Palette := CopyPalette(BitmapOriginal.Palette); //Copy Palette
{$ENDIF}
StartTime := GetTickCount;
try iRotationAxis := SpinEditI.Value
except iRotationAxis := 0
end;
try jRotationAxis := SpinEditJ.Value
except jRotationAxis := 0
end;
Theta := -(SpinEditThetaDegrees.Value + SpinEditThetaDegreesHundredths.Value/100) * PI / 180;
Edit1.text:=' Theta= '+FloatToStr(Theta)+' spe/100= '+ FloatToStr(SpinEditThetaDegreesHundredths.Value/100);
sinTheta := SIN(Theta);
cosTheta := COS(Theta);
ScanlineBytes := Integer(BitmapOriginal.Scanline[1])- Integer(BitmapOriginal.Scanline[0]);
BW := BitmapOriginal.Width - 1; //Prevent Repeated Calls to TBitMap.Width
BH := BitmapOriginal.Height - 1; //Prevent Repeated Calls to TBitMap.Height
iRot := (2 * iRotationAxis) + 1; //Simplify Calculation within Inner Loop
jRot := (2 * jRotationAxis) + 1; //Simplify Calculation within Outer Loop
RowRotated := BitmapRotated.ScanLine[BH]; //Last BitmapRotated Scanline
POriginalStart := BitmapOriginal.ScanLine[0]; //First BitmapOriginal Scanline
for j := BH downto 0 do
begin
jPrime := (2 * j) - jRot;
jPrimeSinTheta := jPrime * sinTheta;
jPrimeCosTheta := jPrime * cosTheta;
POriginal := POriginalStart;
for i := BW downto 0 do
begin
iPrime := (2 * i) - iRot;
iPrimeRotated := ROUND(iPrime * cosTheta - jPrimeSinTheta);
iOriginal := (iPrimeRotated - 1) div 2 + iRotationAxis;
if (iOriginal >= 0) and (iOriginal <= BW) then
begin
jPrimeRotated := ROUND(iPrime * sinTheta + jPrimeCosTheta);
jOriginal := (jPrimeRotated - 1) div 2 + jRotationAxis;
if (jOriginal >= 0) and (jOriginal <= BH) then begin
RowOriginal := Pointer(Integer(POriginal) + (jOriginal * ScanLineBytes));
RowRotated[i] := RowOriginal[iOriginal];
end else {$IFDEF Paletted}RowRotated[i] := 0;{$ELSE}RowRotated[i] := Black;{$ENDIF}
end else {$IFDEF Paletted} RowRotated[i] := 0; {$ELSE} RowRotated[i] := Black;{$ENDIF}
end;{for i}
Dec(Integer(RowRotated), ScanLineBytes);
end;{for j}


REF2

with BitMapOriginal do
begin
case pixelformat of
pfDevice:begin
nbits := GetDeviceCaps( Canvas.Handle,BITSPIXEL )+1 ;
nbytes := nbits div 8;
if (nbytes>0)and(nbits mod 8 <> 0) then exit;
end;
pf24bit: nBytes:=3;
pfCustom:begin
GetObject( Handle, SizeOf(DIB), @DIB );
nbits := DIB.dsBmih.biSizeImage;
nbytes := nbits div 8;
if (nbytes>0)and(nbits mod 8 <> 0) then exit;
end;
else exit;
end;// case
BitmapRotated.Assign( BitMapOriginal);
sinTheta := SIN( theta ); cosTheta := COS( theta );
NewWidth := ABS( ROUND( Height*sinTheta) ) + ABS( ROUND( Width*cosTheta ) );
NewHeight := ABS( ROUND( Width*sinTheta ) ) + ABS( ROUND( Height*cosTheta) );
if ( ABS(theta)*MAX( width,height ) ) > 1 then
begin
BitmapRotated.Width := NewWidth;
BitmapRotated.Height := NewHeight;
iRotationAxis := width div 2;
jRotationAxis := height div 2;
Rwi := NewWidth - 1;
Rht := NewHeight - 1;
Owi := Width - 1;
Oht := Height - 1;
TransparentT := pRGBtripleArray( Scanline[ Oht ] )[0]; //**
FOR j := Rht DOWNTO 0 DO //1/8/00
BEGIN //for j
RowRotatedT := BitmapRotated.Scanline[ j ] ;
jPrime := 2*j - NewHeight + 1 ;
FOR i := Rwi DOWNTO 0 DO
BEGIN //for i
iPrime := 2*i - NewWidth + 1;
iOriginal := ( ROUND( iPrime*CosTheta - jPrime*sinTheta ) -1 + width ) DIV 2;
jOriginal := ( ROUND( iPrime*sinTheta + jPrime*cosTheta ) -1 + height) DIV 2 ;
IF ( iOriginal >= 0 ) AND ( iOriginal <= Owi ) AND ( jOriginal >= 0 ) AND ( jOriginal <= Oht )THEN
begin RowRotatedT[i] := pRGBtripleArray( Scanline[jOriginal] )[iOriginal];end
ELSE
begin RowRotatedT[i] := TransparentT; end;
END //for i
END;//for j
end;//non-zero rotation
sicoPhi := sicodiPoint( POINT( width div 2, height div 2 ),oldaxis );
with sicoPhi do begin
NewAxis.x := newWidth div 2 + ROUND( di*(CosTheta*co - SinTheta*si) );
NewAxis.y := newHeight div 2- ROUND( di*(SinTheta*co + CosTheta*si) );
end;
end;{with}
end;{Rotate Bitmap}


Son fragmentos, nose si alguien se le haga parecido al código, el punto es que si me pudieran ayudar a rotar rectangulos que de hecho las imágenes tamaño carta sin escalar y pués me gustaria saber si se pudiera modificar la ref1 para que este funcione con rectangulos u optimizar la ref2 ó no si hayan escuchado del BitBlt es bueno? me la estoy complicando mucho, también aplicar el procedimiento rotatebitmap en eventos onclick es decir tener un Bitmap:bitmap global, es decir que funcione el rotar como el Microsoft Office Picture Manager

cHackAll
12-03-2008, 14:48:13
Revisaste el Truco 455 (http://www.clubdelphi.com/trucos/index.php?id=455)? dudo que tu comentario haya sido de éste porque el mismo no se vale de movimiento de pixeles ni de calculos en punteros ScanLine, sino que mediante la API realiza las rotaciónes.

Solo necesitas convertir el JPEG a BMP y utilizar la función.

Saludos

mrnovice
12-03-2008, 17:00:41
Saludos, Muchas gracias, este no lo había visto, parece más sencillo, luego te comentó cómo me fue,voy a probarlo, una pregunta osea las versiones scanline o pixeles son métodos antiguos, ya no se usan, son como la base para lo que tenemos en la actualidad?.

Muchas gracias:)

cHackAll
12-03-2008, 17:11:26
...una pregunta osea las versiones scanline o pixeles son métodos antiguos, ya no se usan, son como la base para lo que tenemos en la actualidad?.

En ningún momento he sugerido tal cosa, y si fue así me retracto. Acceder a los pixeles es útil para comprender la abstracción de los gráficos... al fin y a cabo un pixel es la mínima unidad utilizada por el mismo monitor. Y usarla no es nada malo en pequeñas medidas.

Usar "ScanLine" es acceder a la matriz de pixeles del gráfico en cuestión, lo que acelera en gran medida la modificación de sus datos pues es la modificación del buffer en memoria que posteriormente será actualizada.

Qué tenemos en la "actualidad"... en realidad si pudiésemos ver el código que realiza la API, estaríamos viendo operaciones en memoria con senos y cosenos. La supuesta ventaja es que una empresa con tantos $$$$, puede pagar a buenos matemáticos que optimicen dicho código (o que por lo menos lo busquen e implementen).

Saludos

mrnovice
12-03-2008, 17:30:18
Muchas gracias, saludos.
Muy clara la explicación, mejor no pudo haber quedado.
Ah! :D no lo sugeriste, lo que pasa es que me quedo la duda, porque según investigaba, encontraba nuevos métodos, me imaginaba que cada vez se optimizaba y creo de ahí me vino la confusión.
Si te fijas he tratado de encontrar la solución a rotar pero uff creo que hay diversidad de métodos,sólo que me perdí y no supe si estoy haciendo pasos innecesario.
Ah!!!!!!!, me llamó la atención, qué es una verdad qué, pues en cierta manera las grandes empresas pagan $$$$ para optimizar y esto ayude al avance de la tecnología.
Gracias y arriba club Delphi!!!!:cool:

mrnovice
12-03-2008, 18:33:45
mmm, si funciona, y me gusta el rendimiento, pero me deja un espacio morado y algunos bmp no me los lee......serà que no lee bmps grandes?
voy a tratr de modificar el código para hacerlo funcionar, saludos

cHackAll
12-03-2008, 18:57:58
...me deja un espacio morado y algunos bmp no me los lee......serà que no lee bmps grandes?

No es morado, es clFuchsia y esta hecho así para realizar las modificaciones en tiempo de ejecución y que el espacio vacío quede como tal en un componente que procese el color de transparencia. Puedes cambiarlo sin problema.

No está probado, pero espero que dicha función procese BMPs de decenas de mega pixeles. Con respecto a los BMPs que no reconoce... si tienes uno pequeño súbelo para corregir el truco (si es que realmente es necesario)

Saludos

mrnovice
13-03-2008, 20:17:12
Pues estuve investigando aunque muy poco los que no me agarraba era bmps de muchos pixeles aprox su tamaño era 24MB, seguirè invesitgando gracias