Захват скриншота точно по границе окна.

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Захват скриншота точно по границе окна.

Сообщение Alex2013 » 16.03.2021 19:43:04

В общем раньше мене это было не очень важно . А тут программу в программу нужно добыть точный скрин без лишних сущностей в виде непонятных рамок (Похоже что оставленных для рисования тени ) по краям .
Зы
Можно конечно обрезать края самостоятельно ( размеры окна известны заранее ) но это явный "костыль" котрого хотелось бы избежать.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение Sharfik » 16.03.2021 23:12:18

НАйти форму, узнать размеры и координаты, преобразовать координаты в координаты экрана, сделать скриншот и обработать его по уже известной геометрии. Ну или сделать фокус на форму и имитировать нажатие Alt+PrtScr
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 759
Зарегистрирован: 20.07.2013 01:04:30

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 17.03.2021 04:27:41

Спасибо, за отзыв но рецепт немного не годится так-как нужно получить скрин свернутой или перекрытой формы. (хочу использовать для создания простого "пространственного" GUI интерфейса в OpenGL )

Select3D_test05_8_6_01_500.jpg

Свернутое окно пока не видит, но перекрытое или "спрятанное" например "по отрицательным координатам" видно отлично.(однако "рамка" все равно напрягает )
Последний раз редактировалось Alex2013 03.05.2023 23:58:12, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение Seenkao » 17.03.2021 06:26:30

Если в окне уже контекст OpenGL, просто сделай скрин с помощью него.

Ну... или обрежь этот скрин...
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: Захват скриншота точно по границе окна.

Сообщение olegy123 » 17.03.2021 12:52:55

Снапшотить GUI окно это еще тот прикол.

не проще рисовать само окно в OGL
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 17.03.2021 13:07:58

Seenkao писал(а):Если в окне уже контекст OpenGL, просто сделай скрин с помощью него.

Ну... или обрежь этот скрин...

1 "А что так можно?" :roll: :D (не буду скрывать что в OpenGL я еще не слишком много понимаю )
2 Обрезать можно но есть сомнения, что при включенном масштабировании и прочих приколах винды это будет работать всегда .
.
Мне бы найти что-то вроде Си-шного "Control.DrawToBitmap" .
То есть запустить прорисовку окна в место стандартного "дисплейного контекста" на контекст Bitmap .
Зы
Вообще то это разумеется изрядная блаж и вывод GUI форм в OpenGL делается совсем иначе...

FGL_240.jpg

.. но идея что называется "подкупает простотой". :idea:

Добавлено спустя 27 минут 3 секунды:
olegy123 писал(а):не проще рисовать само окно в OGL

Именно ! Просто кажется что скриншотить окно "вроде как проще", а на поверку "хрен его знает" .
Для теста сделал захват по таймеру + рисовал курсор мыши (причем по глобальным координатам).
Если идея окажется рабочей буду транслировать нужные события непосредственно в форму.
(Принципе если спрятать окно по отрицательным координатам то рамка всегда будет черная и можно или обрезать окно по черным краям или сделать "прозрачный цвет" но это все равно как-то "костыльно получается" )
Последний раз редактировалось Alex2013 03.05.2023 23:59:23, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение iskander » 17.03.2021 15:32:12

А вот такую процедурку не пробовал?
Код: Выделить всё
uses
  ..., LclType, LclIntf;
...
procedure TForm1.Screenshot;
var
  pic: TPicture;
  dc: hdc;
begin
  pic := TPicture.Create;
  try
    dc := GetDC(Handle);
    if dc <> 0 then
      begin
        pic.Bitmap.LoadFromDevice(dc);
        ReleaseDC(Handle, dc);
        pic.SaveToFile('screen.png');
      end;
  finally
    pic.Free;
  end;
end;

Емнип, если окно свёрнуто, она нарисует картину малевича.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 17.03.2021 17:59:01

У меня похожая штуковина...
Код: Выделить всё
procedure TCaptureForm.CreateSnapshotPlusWH (var B:TBitmap;W,H:Integer;WindowHD:HWND;Sbs:Integer);

  var
      wnd:HWND;
      dc:HDC;
      r:TRect;
      X,WS,HS:Longint;
  begin
  If B=Nil then exit;

      wnd :=WindowHD;
      if wnd = 0 then
          begin
           dc := GetDC(0);
        Ws:=Screen.Width;
        Hs:=Screen.Height;
          end
         else
          begin
          dc := GetWindowDC(wnd);
           GetWindowRect(wnd,r);
           Ws:=r.Right-r.Left;
           Hs:=r.Bottom-r.Top;
          end;

      if SBS in [1,2] then ws:=ws div 2;
      if SBS in [0,1] then X:=0;
      if SBS = 2 then x:=ws;
      b.SetSize(W,H);

  StretchBlt(B.Canvas.Handle,0,0,B.Width,B.Height,DC,x,0,WS,HS,SRCCOPY);
  ReleaseDC(wnd,dc);
  end;

А LoadFromDevice у меня не работает (То есть возможно на запись в файл все идет нормально но "текстуру не подхватывает" совсем )
Зы
Ещё пробовал PrintWindow вместо BitBlt (или StretchBlt) использовать ...
(Как-то так PrintWindow(wnd, B.Canvas.Handle, 0); )
Но от использования PrintWindow что-то нездоровое на исходной форме происходит....
Зы Зы
Вообщем похоже что там какие-то заморочки с форматом ( то что получается при чтении по HDC или HWND не заполняет всех нужных полей в ТBitmap даже мой "фирменный" захват через BitBlt работает как источник текстур только после странной "само-перерисовки " типа этой bmp.Canvas.Draw(0,0,bmp);)
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение Sharfik » 18.03.2021 00:45:04

Alex2013 писал(а):Спасибо, за отзыв но рецепт немного не годится так-как нужно получить скрин свернутой или перекрытой формы. (хочу использовать для создания простого "пространственного" GUI интерфейса в OpenGL )

Ну так надо было говорить, что все должно быть супер круто как в кино))
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 759
Зарегистрирован: 20.07.2013 01:04:30

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 18.03.2021 03:50:16

Sharfik писал(а):Ну так надо было говорить, что все должно быть супер круто как в кино))

:D
У меня сейчас даже немного круче чем "в кино"... по тому что проект крутится вокруг ВиАр-технологии что неплохо его стимулирует . ("просто трехмерный интерфейс" на экране компьютера это сейчас довольно банально и чуть уныло ) Правда это не отменяет того факта что я еще даже в OpenGL еще "плаваю" почти по полной программе. (Весь "редер" моей "типа ВиАр" техно-демки занимает пока от силы пару сот строк кода )

Но "дорогу осилит идущий" ... :idea:
(Кстати глядя на этот скрин уже можно догадаться куда идет разработка... )
Select3D_test05_8_6_02_800.jpg
"Лазарус ВР" ? :wink: К сожалению нет, но "HiAsm VR" (точнее внешний редактор SHA схем ) вполне возможен .
Последний раз редактировалось Alex2013 04.05.2023 00:01:08, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение Cheb » 18.03.2021 17:43:12

Код: Выделить всё
type
  TWindowManagerRect = record left, top, width, height: longint end; 

  function TWinApiFramework.GetWindowClientRect(): TWindowManagerRect;
  var
    r: TRect; //winapi type
    point: TPoint; //winapi type
  begin
    point.x:= 0;
    point.y:= 0;
    with Framework as TWinApiFramework do begin
      GetClientRect(WindowHandle, r); //winapi. This syka always returns 0,0 for the top left corner!
      ScreenToClient(WindowHandle, point); //winapi
    end;
    Result:= WindowsRectToWmRect(r); //
    Result.Top-= point.y;
    Result.Left-= point.x;
  end;

  function WindowsRectToWmRect(r: TRect): TWindowManagerRect;
  begin
    Result.left:= r.left;
    Result.top:= r.top;
    Result.width:= r.Right - r.left;
    Result.height:= r.Bottom - r.top;
  end;

  function TWinApiFramework.GetWindowOuterRect(): TWindowManagerRect;
  var r: TRect;
  begin
    GetWindowRect(WindowHandle, r); // winapi
    Result:= WindowsRectToWmRect(r);
  end; 


Добавлено спустя 9 минут 33 секунды:
Также,
To get the window bounds excluding the drop shadow, use DwmGetWindowAttribute, specifying DWMWA_EXTENDED_FRAME_BOUNDS. Note that unlike the Window Rect, the DWM Extended Frame Bounds are not adjusted for DPI. Getting the extended frame bounds can only be done after the window has been shown at least once.


Добавлено спустя 2 минуты 3 секунды:
Также,
In conformance with conventions for the RECT structure, the bottom-right coordinates of the returned rectangle are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 19.03.2021 13:45:21

Спасибо, попробую ! :idea:
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 24.03.2021 21:25:58

Нашел я вот такую штуку на Си ...
Код: Выделить всё
  public static Bitmap CaptureWindow(IntPtr wnd, WindowSettings settings, out SIZE size, out Win32Stuff.WINDOWINFO info)
        {
            IntPtr hBitmap;
            IntPtr hDC = Win32Stuff.GetDC(Win32Stuff.GetDesktopWindow());
            IntPtr hMemDC = GDIStuff.CreateCompatibleDC(hDC);


            info = new Win32Stuff.WINDOWINFO();
            info.cbSize = (uint)Marshal.SizeOf(info);
            Win32Stuff.GetWindowInfo(wnd, ref info);
            size.cx = Math.Max(1, info.rcClient.Width + settings.offsetRight - settings.offsetLeft);
            size.cy = Math.Max(1, info.rcClient.Height + settings.offsetBottom - settings.offsetTop);

            hBitmap = GDIStuff.CreateCompatibleBitmap(hDC, size.cx, size.cy);

            if (hBitmap != IntPtr.Zero)
            {
                IntPtr hOld = (IntPtr)GDIStuff.SelectObject(hMemDC, hBitmap);

                GDIStuff.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, info.rcWindow.X + settings.offsetLeft, info.rcWindow.Y + settings.offsetTop, GDIStuff.SRCCOPY);

                GDIStuff.SelectObject(hMemDC, hOld);
                GDIStuff.DeleteDC(hMemDC);
                Win32Stuff.ReleaseDC(Win32Stuff.GetDesktopWindow(), hDC);
                Bitmap bmp = System.Drawing.Image.FromHbitmap(hBitmap);
                GDIStuff.DeleteObject(hBitmap);
                GC.Collect();
                return bmp;
            }
            return null;
        }
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

Re: Захват скриншота точно по границе окна.

Сообщение Sharfik » 28.03.2021 16:50:05

А возможно создать сферу и натянуть на внутреннюю поверхность картинку? Разместив тв центре камеру?
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 759
Зарегистрирован: 20.07.2013 01:04:30

Re: Захват скриншота точно по границе окна.

Сообщение Alex2013 » 29.03.2021 01:22:10

Sharfik писал(а):А возможно создать сферу и натянуть на внутреннюю поверхность картинку? Разместив тв центре камеру?

Так как-бы именно это я и сделал ... :idea:

Изображение

И более того добавил возможность превращать сферу в вогнутый виртуальный экран

Изображение
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 37

Рейтинг@Mail.ru