我需要旋轉TMetafile圖像,至少90度的步驟。 通過在位圖畫布上繪製我的圖元文件然後旋轉位圖很容易將其旋轉,但我更願意將其保存爲矢量圖像格式。這可能嗎?如果是,那我該怎麼做?是否可以旋轉元文件圖像而不將其轉換爲位圖?
回答
創建第二個圖元文件。使用SetWorldTransform創建旋轉變換。將第一個圖元文件繪製到第二個元素上,然後讓其他元素完成。
工作代碼示例,由David的建議製作。每點擊一次按鈕將會將存儲在TImage內部的圖元文件旋轉90度。
procedure TfMain.btnRotateClick(Sender: TObject);
var
SourceMetafile: TMetafile;
DestMetafile: TMetafile;
DestCanvas: TMetafileCanvas;
TransformMatrix: XFORM;
Angle: Double;
begin
Assert(imgRender.Picture.Graphic is TMetafile);
SourceMetafile := imgRender.Picture.Graphic as TMetafile;
DestMetafile := TMetafile.Create();
DestMetafile.Width := SourceMetafile.Height;
DestMetafile.Height := SourceMetafile.Width;
try
DestCanvas := TMetafileCanvas.Create(DestMetafile, Canvas.Handle);
try
SetGraphicsMode(DestCanvas.Handle, GM_ADVANCED);
ZeroMemory(@TransformMatrix, SizeOf(TransformMatrix));
TransformMatrix.eM11 := 1;
TransformMatrix.eM12 := 0;
TransformMatrix.eM21 := 0;
TransformMatrix.eM22 := 1;
TransformMatrix.eDx := -SourceMetafile.Width div 2;
TransformMatrix.eDy := -SourceMetafile.Height div 2;
SetWorldTransform(DestCanvas.Handle, TransformMatrix);
ZeroMemory(@TransformMatrix, SizeOf(TransformMatrix));
Angle := DegToRad(90);
TransformMatrix.eM11 := Cos(Angle);
TransformMatrix.eM12 := Sin(Angle);
TransformMatrix.eM21 := -Sin(Angle);
TransformMatrix.eM22 := Cos(Angle);
TransformMatrix.eDx := 0;
TransformMatrix.eDy := 0;
ModifyWorldTransform(DestCanvas.Handle, TransformMatrix, MWT_RIGHTMULTIPLY);
ZeroMemory(@TransformMatrix, SizeOf(TransformMatrix));
TransformMatrix.eM11 := 1;
TransformMatrix.eM12 := 0;
TransformMatrix.eM21 := 0;
TransformMatrix.eM22 := 1;
TransformMatrix.eDx := SourceMetafile.Height div 2;
TransformMatrix.eDy := SourceMetafile.Width div 2;
ModifyWorldTransform(DestCanvas.Handle, TransformMatrix, MWT_RIGHTMULTIPLY);
DestCanvas.Draw(0, 0, SourceMetafile);
finally
DestCanvas.Free();
end;
imgRender.Picture.Assign(DestMetafile);
finally
DestMetafile.Free();
end;
end;
安德魯的 「btnRotateClick」 有的錯誤!
- 10-15次點擊後,執行時間快速增加。
- 如果用戶更改控制面板\ Display中的全局窗口設置或使用「dpiScaling.exe」,則圖像會在每次單擊時收縮。
我已經寫了一個更簡單的btnRotateClick版本,它避免了div 2的舍入錯誤,但仍然存在錯誤。
procedure TfrmPreviewImage.RotateMetafile(ClockWise: Boolean);
// Not risolved: Fast increasing rotation time after about 15 rotations.
// Not resolved: Control panel Screen Change dimension of all elements
var
DestMetafile: TMetafile;
DestCanvas: TMetafileCanvas;
TransformMatrix: XFORM;
begin
Assert(Image1.Picture.Graphic is TMetafile);
DestMetafile := TMetafile.Create;
DestMetafile.Enhanced := True;
DestMetafile.SetSize(Image1.Picture.Metafile.Height, Image1.Picture.Metafile.Width);
try
DestCanvas := TMetafileCanvas.Create(DestMetafile, Canvas.Handle);
DestCanvas.Lock;
Try
SetGraphicsMode(DestCanvas.Handle, GM_ADVANCED);
SetMapMode(DestCanvas.Handle, MM_TEXT);
if ClockWise then
begin
Fillchar(TransformMatrix, SizeOf(TransformMatrix), 0);
// Angle := DegToRad(90);
TransformMatrix.eM11 := 0; // Cos(Angle);
TransformMatrix.eM12 := -1; // Sin(Angle);
TransformMatrix.eM21 := 1; // -Sin(Angle);
TransformMatrix.eM22 := 0; // Cos(Angle);
TransformMatrix.eDx := 0;
TransformMatrix.eDy := image1.Picture.Metafile.Width;
end
else
begin
Fillchar(TransformMatrix, SizeOf(TransformMatrix), 0);
// Angle := DegToRad(90);
TransformMatrix.eM11 := 0; // Cos(Angle);
TransformMatrix.eM12 := 1; // Sin(Angle);
TransformMatrix.eM21 := -1; // -Sin(Angle);
TransformMatrix.eM22 := 0; // Cos(Angle);
TransformMatrix.eDx := image1.Picture.Metafile.Height;
TransformMatrix.eDy := 0;
end;
SetWorldTransform(DestCanvas.Handle, TransformMatrix);
DestCanvas.Draw(0, 0, Image1.Picture.Graphic);
Finally
DestCanvas.Unlock;
DestCanvas.Free();
End;
Image1.Picture.Metafile.Assign(DestMetafile);
finally
DestMetafile.Free;
end;
end;
解的全局顯示設置改變:
如果一個用戶改變在控制面板全球顯示器設置,所有組件 窗體上的像素寬度保持相同。但屏幕寬度會發生變化。 我的顯示器有horzontaly 1680 px。 更改顯示設置後的Screen.Width返回1344 px。 在世界轉換之前,您需要更正目標元文件大小。
w1 := MulDiv(w, Screen.Width, ScreenSize.cx);
h1 := MulDiv(h, Screen.Height, ScreenSize.cy);
DestMetafile.SetSize(h1, w1);
經過長時間的搜索,知道,我發現屏幕的「真實」尺寸:
const
ENUM_CURRENT_SETTINGS: DWORD = $FFFFFFFF;
EnumDisplaySettings(nil, ENUM_CURRENT_SETTINGS, DevMode);
ScreenSize.cx := DevMode.dmPelsWidth;
這correcion旋轉的圖像,不改變尺寸後。
解決方案在每一個旋轉增加執行時間。
我在這裏給出一個表格來說明問題。
累積旋轉會導致執行時間增加。
隨着累積旋轉我的意思是已經旋轉旋轉圖像。
ENHMETAHEADER Size
Angle nHandles nRecords (Bytes)
0 4 173 4192
90 7 214 5372
180 10 273 6998
...
450 19 692 20064
540 22 1081 36864
爲了避免這種情況,請不要旋轉已經旋轉的圖像,而是旋轉原始圖像。
對這個問題的答案取決於你寫的,如果你使用SetWorldTransform程序的類型。
另一種方法是更改每個元文件記錄的座標。 微軟在2014年發佈了:[MS-EMF] .pdf:增強型圖元文件格式。看起來很多工作。
還有其他問題。
有信息
虧損的旋轉型圖元文件已經失去了作者和說明。在旋轉之前,您不能簡單地保存此信息 並在旋轉後恢復此信息。屬性CreatedBy和描述 不可寫。 用途:
DestCanvas := TMetafileCanvas.CreateWithComment
也看到
單元Winapi.GDIPAPI對圖元文件擴展的詳細信息。
聯機文檔EnumDisplaySettings。
備註
旋轉圖元文件作爲位圖給出了一個質量損失。 我決定複製並粘貼Andrew的代碼,但發現錯誤。 我寫了下面的代碼,但我的測試可能性很差。我只有一個EMFPLUS文件和一個監視器。測試在Windows8.1
這裏是我的代碼:(德爾福XE3)
unit UEmfRotate;
{
Use:
var
FRotationPos : TRotationPosition;
FRotationPos := GetNewPosition(Clockwise, FRotationPos);
UEmfRotate.RotateMetafile(Filename, image1, FRotationPos);
}
interface
uses
System.Types, Vcl.ExtCtrls;
type
TRotationPosition = -3 .. 3;
procedure RotateMetafile(const Path: string; image: TImage;
Position: TRotationPosition);
function GetNewPosition(Clockwise: boolean;
OldPosition: TRotationPosition): TRotationPosition;
implementation
uses
Winapi.Windows, Vcl.Graphics, Vcl.Forms, System.Math;
{
// Resolved: Fast increasing rotation time after about 15 rotations.
// Resolved: Control panel Display Change (dimension of all elements)
// Resolved: Loose of CreatedBy and Description after rotation
}
{
All destination positions from -3 to 3 (-270.. 270)
0 1 2 3
WWW AW AAA WA
AAA AW WWW WA
AW WA
0 -1 -2 -3
WWW WA AAA AW
AAA WA WWW AW
WA AW
}
type
TDestinationArray = array [boolean, TRotationPosition] of TRotationPosition;
TDegrees = array [TRotationPosition] of cardinal;
const // OldPosition -3 -2 -1 0 -1 -2 -3 Clockwise
DestinationArray: TDestinationArray = ((0, -3, -2, -1, 0, 1, 2), // False
(-2, -1, 0, 1, 2, 3, 0)); // True
// Position -3, -2, -1, 0, 1, 2, 3
Degrees: TDegrees = (90, 180, 270, 0, 90, 180, 270);
function GetNewPosition(Clockwise: boolean;
OldPosition: TRotationPosition): TRotationPosition;
begin
Result := DestinationArray[Clockwise, OldPosition];
end;
function GetDegrees(Position: Integer): cardinal;
begin
Result := Degrees[Position];
end;
function GetScreenSize(out Size: System.Types.TSize): boolean;
// Used to correct for a change in windows global display settings.
const
ENUM_CURRENT_SETTINGS: DWORD = $FFFFFFFF;
var
DevMode: TDevMode;
begin
Size.cx := 0;
Size.cy := 0;
DevMode.dmSize := SizeOf(TDevMode);
Result := EnumDisplaySettings(nil, ENUM_CURRENT_SETTINGS, DevMode);
if Result then
begin
Size.cx := DevMode.dmPelsWidth;
Size.cy := DevMode.dmPelsHeight;
end;
end;
procedure RotateMetafile90(image: TImage);
var
DestMetafile: TMetafile;
DestCanvas: TMetafileCanvas;
TransformMatrix: XFORM;
w, h: Integer;
w1, h1: Integer;
ScreenSize: System.Types.TSize;
begin
w := image.Picture.Width;
h := image.Picture.Height;
// Get screen dimension independent of the control panel display settings.
if GetScreenSize(ScreenSize) then
begin
w1 := MulDiv(w, Screen.Width, ScreenSize.cx);
h1 := MulDiv(h, Screen.Height, ScreenSize.cy);
end
else
begin
// Can not do anything
w1 := w;
h1 := h;
end;
DestMetafile := TMetafile.Create;
DestMetafile.Enhanced := True;
DestMetafile.SetSize(h1, w1);
try
DestCanvas := TMetafileCanvas.CreateWithComment(DestMetafile, 0,
image.Picture.Metafile.CreatedBy, image.Picture.Metafile.Description);
DestCanvas.Lock;
Try
SetGraphicsMode(DestCanvas.Handle, GM_ADVANCED);
SetMapMode(DestCanvas.Handle, MM_TEXT);
Fillchar(TransformMatrix, SizeOf(TransformMatrix), 0);
TransformMatrix.eM11 := 0; // Cos(Angle);
TransformMatrix.eM12 := 1; // Sin(Angle);
TransformMatrix.eM21 := -1; // -Sin(Angle);
TransformMatrix.eM22 := 0; // Cos(Angle);
TransformMatrix.eDx := h;
TransformMatrix.eDy := 0;
SetWorldTransform(DestCanvas.Handle, TransformMatrix);
DestCanvas.Draw(0, 0, image.Picture.Graphic); // Same as Play
Finally
DestCanvas.Unlock;
DestCanvas.Free();
End;
image.Picture := nil;
image.Picture.Metafile.Assign(DestMetafile);
finally
DestMetafile.Free;
end;
end;
procedure RotateMetafile180(image: TImage);
var
DestMetafile: TMetafile;
DestCanvas: TMetafileCanvas;
TransformMatrix: XFORM;
w, h: Integer;
w1, h1: Integer;
ScreenSize: System.Types.TSize;
begin
w := image.Picture.Width;
h := image.Picture.Height;
// Get screen dimension independent of the control panel display settings.
if GetScreenSize(ScreenSize) then
begin
w1 := MulDiv(w, Screen.Width, ScreenSize.cx);
h1 := MulDiv(h, Screen.Height, ScreenSize.cy);
end
else
begin
// Can not do anything
w1 := w;
h1 := h;
end;
DestMetafile := TMetafile.Create;
DestMetafile.Enhanced := True;
DestMetafile.SetSize(w1, h1);
try
DestCanvas := TMetafileCanvas.CreateWithComment(DestMetafile, 0,
image.Picture.Metafile.CreatedBy, image.Picture.Metafile.Description);
DestCanvas.Lock;
Try
SetGraphicsMode(DestCanvas.Handle, GM_ADVANCED);
SetMapMode(DestCanvas.Handle, MM_TEXT);
Fillchar(TransformMatrix, SizeOf(TransformMatrix), 0);
TransformMatrix.eM11 := -1; // Cos(Angle);
TransformMatrix.eM12 := 0; // Sin(Angle);
TransformMatrix.eM21 := 0; // -Sin(Angle);
TransformMatrix.eM22 := -1; // Cos(Angle);
TransformMatrix.eDx := w;
TransformMatrix.eDy := h;
SetWorldTransform(DestCanvas.Handle, TransformMatrix);
DestCanvas.Draw(0, 0, image.Picture.Graphic); // Same as Play
Finally
DestCanvas.Unlock;
DestCanvas.Free();
End;
image.Picture := nil;
image.Picture.Metafile.Assign(DestMetafile);
finally
DestMetafile.Free;
end;
end;
procedure RotateMetafile270(image: TImage);
var
DestMetafile: TMetafile;
DestCanvas: TMetafileCanvas;
TransformMatrix: XFORM;
w, h: Integer;
w1, h1: Integer;
ScreenSize: System.Types.TSize;
begin
w := image.Picture.Width;
h := image.Picture.Height;
// Get screen dimension independent of the control panel display settings.
if GetScreenSize(ScreenSize) then
begin
w1 := MulDiv(w, Screen.Width, ScreenSize.cx);
h1 := MulDiv(h, Screen.Height, ScreenSize.cy);
end
else
begin
// Can not do anything
w1 := w;
h1 := h;
end;
DestMetafile := TMetafile.Create;
DestMetafile.Enhanced := True;
DestMetafile.SetSize(h1, w1);
try
DestCanvas := TMetafileCanvas.CreateWithComment(DestMetafile, 0,
image.Picture.Metafile.CreatedBy, image.Picture.Metafile.Description);
DestCanvas.Lock;
Try
SetGraphicsMode(DestCanvas.Handle, GM_ADVANCED);
SetMapMode(DestCanvas.Handle, MM_TEXT);
Fillchar(TransformMatrix, SizeOf(TransformMatrix), 0);
TransformMatrix.eM11 := 0; // Cos(Angle);
TransformMatrix.eM12 := -1; // Sin(Angle);
TransformMatrix.eM21 := 1; // -Sin(Angle);
TransformMatrix.eM22 := 0; // Cos(Angle);
TransformMatrix.eDx := 0;
TransformMatrix.eDy := w;
SetWorldTransform(DestCanvas.Handle, TransformMatrix);
DestCanvas.Draw(0, 0, image.Picture.Graphic); // Same as Play
Finally
DestCanvas.Unlock;
DestCanvas.Free();
End;
image.Picture := nil;
image.Picture.Metafile.Assign(DestMetafile);
finally
DestMetafile.Free;
end;
end;
procedure RotateMetafile(const Path: string; image: TImage;
Position: TRotationPosition);
{
Cumulative rotating causes increasing execution time
With cumulative rotating i mean rotate an image already rotated
ENHMETAHEADER Size
Angle nHandles nRecords (Bytes)
0 4 173 4192
90 7 214 5372
180 10 273 6998
270 13 354 9352
360 16 479 13212
450 19 692 20064
540 22 1081 36864
To avoid this never rotate an already rotated image, but rotate the
original image.
}
begin
image.Picture.Metafile.LoadFromFile(Path);
Assert(image.Picture.Graphic is TMetafile);
case GetDegrees(Position) of
90:
RotateMetafile90(image);
180:
RotateMetafile180(image);
270:
RotateMetafile270(image);
end;
// image.Picture.SaveToFile('emf.emf');
end;
end.
- 1. 是否可以將網格轉換爲位圖等圖像文件?
- 2. 旋轉位圖不旋轉
- 3. 是否可以將Google地圖轉換爲特定方位?
- 4. 是否可以將Windows位圖與Alpha通道轉換爲MagickImage?
- 5. 是否可以繪製佈局並轉換爲位圖而不可見
- 6. 在Matlab上將2D圖像轉換爲旋轉的3D圖像
- 7. 將Base64轉換爲PDF而不將其轉換爲JAVA中的圖像
- 8. 是否可以將PPT轉換爲Windows Phone中的圖像?
- 9. 是否可以使用itextSharp將PDF頁面轉換爲圖像?
- 10. Android:是否可以將TIFF圖像轉換爲JPG,PNG格式?
- 11. Android ||位圖圖像旋轉
- 12. 旋轉位圖圖像
- 13. CSS圖像旋轉轉換
- 14. 在JavaScript中旋轉SVG組元素的位置而不旋轉整個圖像
- 15. 將字節轉換爲位圖圖像
- 16. 將位圖轉換爲javascript圖像
- 17. 將PictureBox圖像轉換爲位圖
- 18. 將圖像轉換爲位圖
- 19. 如何將圖像轉換爲位圖
- 20. 將圖像轉換爲位圖android
- 21. 如何將位圖轉換爲圖像
- 22. 將位圖轉換爲圖像
- 23. 將位圖轉換爲WebP圖像?
- 24. 將圖像轉換爲位圖
- 25. 是否可以在網頁上顯示.bin圖像文件而無需將其轉換爲jpg/png/gif?
- 26. 根據其他圖像的位置將圖像旋轉90度
- 27. 只旋轉視圖而不旋轉其子視圖
- 28. 旋轉圖像並將圖像保存爲旋轉狀態
- 29. 將文本轉換爲圖像和旋轉它
- 30. 如何將文本轉換爲圖像然後垂直旋轉
謝謝,大衛!像往常一樣,你可以節省很多小時的生活。 :)我在下面發佈了一個代碼示例 – Andrew