View Issue Details

IDProjectCategoryView StatusLast Update
0029276LazarusWidgetsetpublic2020-04-01 10:37
ReporterMark Malakanov Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Platformamd64OSlinux 
Product Version1.4.4 
Summary0029276: Canvas.getPixel is not fully covered in TQtWidgetSet.DCGetPixel
DescriptionTQtWidgetSet.DCGetPixel gets pixels only from bitmap backed TCanvas (in Qt they have vImage).
It is not the case if Canvas belongs to TForm or other screen backed component, that in QT have only Painter, do not have vImage.
For compatibility with Lazarus canvas I've added support of screen backed canvases.
Steps To ReproduceCreate a form from TForm.
Try to get a pixel of form.canvas.pixels[x,y].
It will return clNone always.
Additional InformationI propose to add getting a pixel color from screen window of QT widget.
file qtobject.inc

class TQtWidgetSet ...
...
FInGetPixel : boolean;
...
function TQtWidgetSet.DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor;
var
  Color: QColorH=nil;
  Widget: QWidgetH=nil;
  Pixmap: QPixmapH=nil;
  Image: QImageH=nil;
  Painter: QPainterH=nil;
  Rgb: QRgb=0;
  WindId: longword=0;
begin
  Result := clNone;

  if not IsValidDC(CanvasHandle) then Exit;
  
  if (TQtDeviceContext(CanvasHandle).vImage <> nil) then
    begin
      Color := QColor_create(QImage_pixel(TQtDeviceContext(CanvasHandle).vImage.Handle, X, Y));
      Result := RGBToColor(QColor_red(Color), QColor_green(Color), QColor_blue(Color));
      QColor_destroy(Color);
    end
  else if (TQtDeviceContext(CanvasHandle).Widget <> nil) then
    begin
      Widget := TQtDeviceContext(CanvasHandle).Parent; //Parent is actually QWidgetH, and Widget is QPainterH.
      if (Widget = nil) then
        raise Exception.CreateFmt('TQtDeviceContext(CanvasHandle) %u : does not have Widget',[PtrUInt(CanvasHandle)]);
      if FInGetPixel then //to prevent recursive call (QPixmap_grabWidget -> Widget.paint -> DCGetPixel)*
        raise Exception.CreateFmt('TQtWidgetSet.DCGetPixel called recursively, probably from Paint method of Widget %u.',[PtrUInt(Widget)]);
      FInGetPixel := true;
      try
        Pixmap:= QPixmap_create(1,1);
        Image := QImage_create(1,1, QImageFormat_ARGB32);
        //QPixmap_grabWidget(Pixmap, Widget, X,Y, 1,1); //this calls Widget.paint directed to bitmap and gets gets pixels from it. Slower.
        WindId:=QWidget_winId(Widget);
        QPixmap_grabWindow(Pixmap, WindId ,X,Y,1,1); //this gets pixels from screen.
        QPixmap_toImage(PixMap,Image);
        Rgb := QImage_Pixel(Image, 0,0);
        Color := QColor_create(Rgb);
        Result := RGBToColor(QColor_red(Color), QColor_green(Color), QColor_blue(Color));
      finally
        if Pixmap <> nil then QPixmap_destroy(Pixmap); //It looks like Qt caches pixmap despite of destroy
        if Image <> nil then QImage_destroy(Image);
        if Color <> nil then QColor_destroy(Color);
        FInGetPixel := false;
      end;
    end
    else
     begin
       raise Exception.CreateFmt('TQtDeviceContext(CanvasHandle) %u : does not have vImage or Painter',[PtrUInt(CanvasHandle)]);
     end;
end;
TagsNo tags attached.
Fixed in Revision62840
LazTarget-
WidgetsetQT, QT5
Attached Files

Activities

Mark Malakanov

2015-12-29 05:45

reporter  

qtobject.inc (61,161 bytes)

Mark Malakanov

2015-12-29 06:28

reporter  

qt_getPixel_form.zip (3,277 bytes)

Zeljan Rikalo

2015-12-29 14:11

developer   ~0088397

Please create svn diff patch. http://wiki.freepascal.org/Creating_A_Patch

Mark Malakanov

2015-12-31 00:44

reporter  

patch-0029276.diff (3,452 bytes)   
Index: lcl/interfaces/qt/qtint.pp
===================================================================
--- lcl/interfaces/qt/qtint.pp	(revision 51082)
+++ lcl/interfaces/qt/qtint.pp	(working copy)
@@ -87,6 +87,7 @@
     FWindowManagerName: String; // Track various incompatibilities between WM. Initialized at WS start.
     {$ENDIF}
 
+    FInGetPixel: boolean; //prevent possible recursive call in GetPixel
 
     // qt style does not have pixel metric for themed menubar (menu) height
     // so we must calculate it somehow.
Index: lcl/interfaces/qt/qtobject.inc
===================================================================
--- lcl/interfaces/qt/qtobject.inc	(revision 51082)
+++ lcl/interfaces/qt/qtobject.inc	(working copy)
@@ -1211,18 +1211,54 @@
 
 function TQtWidgetSet.DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor;
 var
-  Color: QColorH;
+  Color: QColorH=nil;
+  Widget: QWidgetH=nil;
+  Pixmap: QPixmapH=nil;
+  Image: QImageH=nil;
+  Painter: QPainterH=nil;
+  Rgb: QRgb=0;
+  WindId: longword=0;
 begin
   Result := clNone;
 
   if not IsValidDC(CanvasHandle) then Exit;
-  
-  if (TQtDeviceContext(CanvasHandle).vImage <> nil) then
-  begin
-    Color := QColor_create(QImage_pixel(TQtDeviceContext(CanvasHandle).vImage.Handle, X, Y));
-    Result := RGBToColor(QColor_red(Color), QColor_green(Color), QColor_blue(Color));
-    QColor_destroy(Color);
-  end;
+
+  if (TQtDeviceContext(CanvasHandle).vImage <> nil)
+    and (TQtDeviceContext(CanvasHandle).vImage.Handle <> nil) then
+    begin
+      Color := QColor_create(QImage_pixel(TQtDeviceContext(CanvasHandle).vImage.Handle, X, Y));
+      Result := RGBToColor(QColor_red(Color), QColor_green(Color), QColor_blue(Color));
+      QColor_destroy(Color);
+    end
+  else if (TQtDeviceContext(CanvasHandle).Widget <> nil) then
+    begin
+      Widget := TQtDeviceContext(CanvasHandle).Parent; //Parent is actually QWidgetH, and Widget is QPainterH.
+      if (Widget = nil) then
+        raise Exception.CreateFmt('TQtDeviceContext(CanvasHandle) %u : does not have Widget',[PtrUInt(CanvasHandle)]);
+      if FInGetPixel then //to prevent recursive call (QPixmap_grabWidget -> Widget.paint -> DCGetPixel)*
+        raise Exception.CreateFmt('TQtWidgetSet.DCGetPixel called recursively, probably from Paint method of Widget %u.',[PtrUInt(Widget)]);
+      FInGetPixel := true;
+      try
+        Pixmap:= QPixmap_create(1,1);
+        Image := QImage_create(1,1, QImageFormat_ARGB32);
+        //QPixmap_grabWidget(Pixmap, Widget, X,Y, 1,1); //this calls Widget.paint directed to bitmap and gets gets pixels from it. Slower.
+        WindId:=QWidget_winId(Widget);
+        QPixmap_grabWindow(Pixmap, WindId ,X,Y,1,1); //this gets pixels from screen.
+        QPixmap_toImage(PixMap,Image);
+        Rgb := QImage_Pixel(Image, 0,0);
+        Color := QColor_create(Rgb);
+        Result := RGBToColor(QColor_red(Color), QColor_green(Color), QColor_blue(Color));
+      finally
+        if Pixmap <> nil then QPixmap_destroy(Pixmap); //It looks like Qt caches pixmap despite of destroy
+        if Image <> nil then QImage_destroy(Image);
+        if Color <> nil then QColor_destroy(Color);
+        FInGetPixel := false;
+      end;
+    end
+    else
+     begin
+       raise Exception.CreateFmt('TQtDeviceContext(CanvasHandle) %u : does not have vImage or Painter',[PtrUInt(CanvasHandle)]);
+     end;
 end;
 
 procedure dbgcolor(msg: string; C:TQColor);
patch-0029276.diff (3,452 bytes)   

Mark Malakanov

2015-12-31 00:45

reporter   ~0088447

patch-0029276.diff uploaded.

Zeljan Rikalo

2020-04-01 10:37

developer   ~0121820

Please test and close if ok. Note that Qt5 is also fixed, I've changed your patch a bit.

Issue History

Date Modified Username Field Change
2015-12-29 05:26 Mark Malakanov New Issue
2015-12-29 05:45 Mark Malakanov File Added: qtobject.inc
2015-12-29 06:28 Mark Malakanov File Added: qt_getPixel_form.zip
2015-12-29 14:10 Zeljan Rikalo Assigned To => Zeljan Rikalo
2015-12-29 14:10 Zeljan Rikalo Status new => assigned
2015-12-29 14:11 Zeljan Rikalo LazTarget => -
2015-12-29 14:11 Zeljan Rikalo Note Added: 0088397
2015-12-29 14:11 Zeljan Rikalo Status assigned => feedback
2015-12-31 00:44 Mark Malakanov File Added: patch-0029276.diff
2015-12-31 00:45 Mark Malakanov Note Added: 0088447
2015-12-31 00:45 Mark Malakanov Status feedback => assigned
2020-04-01 10:37 Zeljan Rikalo Status assigned => resolved
2020-04-01 10:37 Zeljan Rikalo Resolution open => fixed
2020-04-01 10:37 Zeljan Rikalo Fixed in Revision => 62840
2020-04-01 10:37 Zeljan Rikalo Widgetset QT => QT, QT5
2020-04-01 10:37 Zeljan Rikalo Note Added: 0121820