ADD: Viewer - fast rotate and mirror functions for 32 bit images

This commit is contained in:
Alexander Koblov 2026-03-15 14:54:41 +03:00
commit de6219e1e6
2 changed files with 219 additions and 97 deletions

View file

@ -464,8 +464,8 @@ type
function DoZoom( const delta: Double; const inc: Integer ): Boolean;
function DoZoomIn: Boolean;
function DoZoomOut: Boolean;
procedure RotateImage(AGradus:integer);
procedure MirrorImage(AVertically:boolean=False);
procedure RotateImage(ADegree: Integer);
procedure MirrorImage(AVertically: Boolean = False);
published
// Commands for hotkey manager
@ -542,7 +542,7 @@ uses
uConvEncoding, DCBasicTypes, DCOSUtils, uOSUtils, uFindByrMr, uFileViewWithGrid,
fPrintSetup, uFindFiles, uAdministrator, uOfficeXML, uHighlighterProcs, dmHigh,
SynEditTypes, uFile, uFileSystemFileSource, uFileProcs, uOperationsManager,
uFileSourceOperationOptions, uGraphics
LazLogger, uFileSourceOperationOptions, uGraphics
{$if lcl_fullversion >= 4990000}
, SynEditWrappedView
{$endif}
@ -1908,106 +1908,25 @@ begin
Result:= DoZoom( 0.909, -1 );
end;
procedure TfrmViewer.RotateImage(AGradus: integer);
// AGradus now supported only 90,180,270 values
procedure TfrmViewer.RotateImage(ADegree: integer);
// ADegree now supported only 90,180,270 values
var
x, y: Integer;
xWidth,
yHeight: Integer;
SourceImg: TLazIntfImage;
TargetImg: TLazIntfImage;
Q: QWord;
begin
TargetImg:= TLazIntfImage.Create(0, 0);
SourceImg := TLazIntfImage.Create(TRasterImage(Image.Picture.Graphic).RawImage, False);
TargetImg.DataDescription:= SourceImg.DataDescription; // use the same image format
xWidth:= SourceImg.Width - 1;
yHeight:= SourceImg.Height - 1;
if AGradus = 90 then
begin
TargetImg.SetSize(yHeight + 1, xWidth + 1);
for y:= 0 to xWidth do
begin
for x:= 0 to yHeight do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[y, yHeight - x];
end;
end;
x:= Image.Width;
Image.Width:= Image.Height;
Image.Height:= x;
end;
if AGradus = 180 then
begin
TargetImg.SetSize(xWidth + 1, yHeight + 1);
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - x, yHeight - y];
end;
end;
end;
if AGradus = 270 then
begin
TargetImg.SetSize(yHeight + 1, xWidth + 1);
for y:= 0 to xWidth do
begin
for x:= 0 to yHeight do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - y, x];
end;
end;
x:= Image.Width;
Image.Width:= Image.Height;
Image.Height:= x;
end;
BitmapAssign(TRasterImage(Image.Picture.Graphic), TargetImg);
FreeAndNil(SourceImg);
FreeAndNil(TargetImg);
Q:= SysUtils.GetTickCount64;
BitmapRotate(TRasterImage(Image.Picture.Graphic), ADegree);
DebugLn('Rotate: ', IntToStr(SysUtils.GetTickCount64 - Q));
AdjustImageSize;
CreateTmp;
end;
procedure TfrmViewer.MirrorImage(AVertically:boolean);
procedure TfrmViewer.MirrorImage(AVertically: Boolean);
var
x, y: Integer;
xWidth,
yHeight: Integer;
SourceImg: TLazIntfImage;
TargetImg: TLazIntfImage;
Q: QWord;
begin
TargetImg:= TLazIntfImage.Create(0, 0);
SourceImg := TLazIntfImage.Create(TRasterImage(Image.Picture.Graphic).RawImage, False);
TargetImg.DataDescription:= SourceImg.DataDescription; // use the same image format
xWidth:= SourceImg.Width - 1;
yHeight:= SourceImg.Height - 1;
if not AVertically then
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - x, y];
end;
end
else
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[ x,yHeight - y];
end;
end;
BitmapAssign(TRasterImage(Image.Picture.Graphic), TargetImg);
FreeAndNil(SourceImg);
FreeAndNil(TargetImg);
Q:= SysUtils.GetTickCount64;
BitmapMirror(TRasterImage(Image.Picture.Graphic), AVertically);
DebugLn('Mirror: ', IntToStr(SysUtils.GetTickCount64 - Q));
AdjustImageSize;
CreateTmp;
end;

View file

@ -33,6 +33,8 @@ procedure BitmapConvert(Bitmap: TRasterImage);
procedure BitmapAssign(Bitmap, Image: TRasterImage);
procedure BitmapConvert(ASource, ATarget: TRasterImage);
procedure BitmapAlpha(var ABitmap: TBitmap; APercent: Single);
procedure BitmapRotate(Bitmap: TRasterImage; ADegree: Integer);
procedure BitmapMirror(Bitmap: TRasterImage; AVertically: Boolean);
procedure BitmapAssign(Bitmap: TRasterImage; Image: TLazIntfImage);
procedure BitmapCenter(var Bitmap: TBitmap; Width, Height: Integer);
procedure BitmapMerge(ALow, AHigh: TLazIntfImage; const ADestX, ADestY: Integer);
@ -82,6 +84,207 @@ begin
RawImage^.ReleaseData;
end;
procedure BitmapRotate(Bitmap: TRasterImage; ADegree: Integer);
// ADegree now supported only 90,180,270 values
var
x, y: Integer;
tx, ty: Integer;
Bits32: Boolean;
xWidth, yHeight: Integer;
iWidth, iHeight: Integer;
SourceImg: TLazIntfImage;
TargetImg: TLazIntfImage;
SourceData, TargetData: PUInt32;
begin
TargetImg:= TLazIntfImage.Create(0, 0);
SourceImg := TLazIntfImage.Create(Bitmap.RawImage, False);
TargetImg.DataDescription:= SourceImg.DataDescription; // use the same image format
iWidth:= SourceImg.Width;
iHeight:= SourceImg.Height;
xWidth:= iWidth - 1;
yHeight:= iHeight - 1;
// Use fast 32 bit rotate function
Bits32:= (SourceImg.DataDescription.BitsPerPixel = 32) and
(SourceImg.DataDescription.LineOrder = riloTopToBottom) and
(SourceImg.DataDescription.LineEnd < rileQWordBoundary);
if Bits32 then
begin
SourceData:= PUInt32(SourceImg.PixelData);
TargetData:= PUInt32(TargetImg.PixelData);
end;
if ADegree = 90 then
begin
TargetImg.SetSize(iHeight, iWidth);
if Bits32 then
begin
for y:= 0 to yHeight do
begin
ty:= yHeight - y;
for x:= 0 to xWidth do
begin
TargetData[iHeight * x + ty]:= SourceData^;
Inc(SourceData);
end;
end;
end
else begin
for y:= 0 to xWidth do
begin
for x:= 0 to yHeight do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[y, yHeight - x];
end;
end;
end;
end
else if ADegree = 180 then
begin
TargetImg.SetSize(iWidth, iHeight);
if Bits32 then
begin
for y:= 0 to yHeight do
begin
ty:= yHeight - y;
for x:= 0 to xWidth do
begin
tx:= xWidth - x;
TargetData[iWidth * ty + tx]:= SourceData^;
Inc(SourceData);
end;
end;
end
else begin
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - x, yHeight - y];
end;
end;
end;
end
else if ADegree = 270 then
begin
TargetImg.SetSize(iHeight, iWidth);
if Bits32 then
begin
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
tx:= xWidth - x;
TargetData[iHeight * tx + y]:= SourceData^;
Inc(SourceData);
end;
end;
end
else begin
for y:= 0 to xWidth do
begin
for x:= 0 to yHeight do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - y, x];
end;
end;
end;
end;
BitmapAssign(Bitmap, TargetImg);
FreeAndNil(SourceImg);
FreeAndNil(TargetImg);
end;
procedure BitmapMirror(Bitmap: TRasterImage; AVertically: Boolean);
var
x, y: Integer;
tx, ty: Integer;
Bits32: Boolean;
xWidth, yHeight: Integer;
iWidth, iHeight: Integer;
SourceImg: TLazIntfImage;
TargetImg: TLazIntfImage;
SourceData, TargetData: PUInt32;
begin
TargetImg:= TLazIntfImage.Create(0, 0);
SourceImg := TLazIntfImage.Create(Bitmap.RawImage, False);
TargetImg.DataDescription:= SourceImg.DataDescription; // use the same image format
iWidth:= SourceImg.Width;
iHeight:= SourceImg.Height;
xWidth:= iWidth - 1;
yHeight:= iHeight - 1;
// Use fast 32 bit mirror function
Bits32:= (SourceImg.DataDescription.BitsPerPixel = 32) and
(SourceImg.DataDescription.LineOrder = riloTopToBottom) and
(SourceImg.DataDescription.LineEnd < rileQWordBoundary);
if Bits32 then
begin
SourceData:= PUInt32(SourceImg.PixelData);
TargetData:= PUInt32(TargetImg.PixelData);
end;
if not AVertically then
begin
if Bits32 then
begin
for y:= 0 to yHeight do
begin
ty:= iWidth * y;
for x:= 0 to xWidth do
begin
tx:= xWidth - x;
TargetData[ty + tx]:= SourceData^;
Inc(SourceData);
end;
end;
end
else begin
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[xWidth - x, y];
end;
end;
end;
end
else begin
if Bits32 then
begin
for y:= 0 to yHeight do
begin
ty:= iWidth * (yHeight - y);
for x:= 0 to xWidth do
begin
TargetData[ty + x]:= SourceData^;
Inc(SourceData);
end;
end;
end
else begin
for y:= 0 to yHeight do
begin
for x:= 0 to xWidth do
begin
TargetImg.Colors[x, y]:= SourceImg.Colors[x, yHeight - y];
end;
end;
end;
end;
BitmapAssign(Bitmap, TargetImg);
FreeAndNil(SourceImg);
FreeAndNil(TargetImg);
end;
procedure BitmapAssign(Bitmap: TRasterImage; Image: TLazIntfImage);
var
ARawImage: TRawImage;