![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Вращение TMetafile без преобразования в формат bitmapDelphi , Графика и Игры , MetaFileВозможно ли повернуть векторное изображение TMetafile без преобразования в формат bitmap? Мне нужно повернуть изображение TMetafile хотя бы на 90 градусов. Легко можно повернуть его, нарисовав его на полотне bitmap, а затем повернув bitmap, но я бы предпочел сохранить его в формате векторного изображения. Возможно ли это вообще? Если да, то как это сделать? Подтвержденный ответ: Создайте второй metafile. Используйте SetWorldTransform для создания трансформации вращения. Нарисуйте первый metafile на второй и дайте трансформации сделать остальное. Комментарий: Спасибо, Дэвид! Как всегда, ты спас мне много часов жизни. :) Я привел пример кода ниже. Код:
Альтернативный ответ:
У кода
Я написал более простую версию Код:
Решение для изменения глобальных настроек экрана: Если пользователь меняет глобальные настройки экрана в панели управления, пиксельная ширина всех компонентов на форме остается прежней, но ширина экрана меняется. Мое отображающее устройство имеет горизонтальную ширину 1680 пикселей. Ширина экрана после изменения настроек экрана возвращает 1344 пикселя. Перед мировой трансформацией необходимо скорректировать размер целевого metafile.
После долгих поисков, чтобы узнать "настоящие" размеры экрана, я нашел:
После этой корректировки повернутое изображение не меняет размеров. Решение для увеличения времени выполнения при каждом вращении: Таблица, иллюстрирующая проблему: Увеличение времени выполнения при каждом вращении. При накопленном вращении я имею в виду вращение уже повернутого изображения. Angle nHandles nRecords Size (Bytes) 0 4 173 4192 90 7 214 5372 180 10 273 6998 ... 450 19 692 20064 540 22 1081 36864 Чтобы избежать этого, никогда не вращайте уже повернутое изображение, а вращайте исходное изображение. Ответ на вопрос зависит от типа программы, которую вы пишете, если вы используете SetWorldTransform. ALTERNATIVE APPROACH: Change the coordinates of every metafile record. Microsoft published in 2014: [MS-EMF].pdf: Enhanced Metafile Format. Seems a lot of work. There are other problems. There is a loss of information The rotated Metafile has lost the author and description. You can not simply save this information before rotating and restore this information after rotating. The properties CreatedBy and Description are not writable. Use: DestCanvas := TMetafileCanvas.CreateWithComment See also unit Winapi.GDIPAPI for more information on metafile extensions. online documentation EnumDisplaySettings. Remarks Rotating a metafile as bitmap gives a quality loss. I decided to copy and paste the code of Andrew, but found bugs. I wrote the code below, but my testing possibilities are scarse. I have only one EMFPLUS file and one monitor. Tested on Windows8.1 Here is my code: (Delphi XE3) Unit UEmfRotate; uses System.Types, Vcl.ExtCtrls; type TRotationPosition = -3 .. 3; procedure RotateMetafile(const Path: string; image: TImage; Position: 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 } type TDestinationArray = array [boolean, TRotationPosition] of TRotationPosition; TDegrees = array [TRotationPosition] of cardinal; const { All destination positions from -3 to 3 (-270.. 270) 0 1 2 3 WWW AW AAA WA AAA AW WWW WA AW AW WA 0 -1 -2 -3 WWW WA AAA AW WWW AW AW WA WA AW } 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. ``` В заключение, вращение изображения TMetafile без преобразования в формат bitmap возможно с помощью создания второго metafile и использования SetWorldTransform для создания трансформации вращения. Затем первый metafile рисуется на втором, и трансформация делает остальное. При этом необходимо учитывать потерю информации, такую как автор и описание, и использовать TMetafileCanvas.CreateWithComment для их сохранения. Также важно учитывать изменение глобальных настроек экрана и корректировать размер целевого metafile с помощью MulDiv и EnumDisplaySettings. Вопрос о том, возможно ли повернуть векторное изображение TMetafile без преобразования в формат bitmap. Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
|
||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |