Recent

Author Topic: Error when generating TChart image in Custom CGI Application on linux  (Read 3234 times)

MaartenJB

  • Full Member
  • ***
  • Posts: 112
Hi, I'm trying to generate a bitmap from a TChart from within a Custom CGI Application. On windows this works without problems, but on Linux this doesnt work.

When I use the code below, it generates an error when executing:

"Canvas does not allow drawing TRasterImage.BitmapHandleNeeded: Unable to create handles, using default"

Code: Pascal  [Select][+][-]
  1. ARasterImage := AChart.SaveToImage(TBitmap); // This generates the error

This is the full procedure I use to generate an image from a tchart:
Code: Pascal  [Select][+][-]
  1. procedure GenChart(AWidth, AHeight: Integer; APngResult: TStream);
  2. var
  3.   ABgraBitmap : TBGRANoGUIBitmap;
  4.   ARasterImage : TRasterImage;
  5.   AStream : TMemoryStream;
  6.   ABMPReader : TFPReaderBMP;
  7.   AChart: TChart;
  8. begin
  9.   if (not Assigned(APngResult))
  10.   then Exit;
  11.  
  12.   AChart := TChart.Create(nil);
  13.   AChart.Width := AWidth;
  14.   AChart.Height := AHeight;
  15.   try
  16.     AStream := TMemoryStream.Create;
  17.     ABMPReader := TFPReaderBMP.Create;
  18.  
  19.     ARasterImage := AChart.SaveToImage(TBitmap); // <<---- This will generate the error
  20.     try
  21.       ARasterImage.SaveToStream(AStream);
  22.       AStream.Position:=0;
  23.  
  24.       ABgraBitmap := TBGRANoGUIBitmap.Create;
  25.       try
  26.         ABgraBitmap.LoadFromStream(AStream, ABMPReader);
  27.         ABgraBitmap.FontFullHeight:=22;
  28.  
  29.         {$IFDEF WINDOWS}
  30.           ABgraBitmap.FontName:='C:\windows\fonts\arial.ttf';
  31.         {$ELSE}
  32.           ABgraBitmap.FontName:='/home/maarten/Documents/lazarus-components/bgrabitmap-master/test/test4other/arial.ttf';
  33.         {$ENDIF}
  34.         ABgraBitmap.TextOut(50,10, TimeToStr(Now), CSSRed);
  35.  
  36.         APngResult.Position := 0;
  37.         ABgraBitmap.SaveToStreamAsPng(APngResult);
  38.       finally
  39.         ABgraBitmap.Free;
  40.       end;
  41.     finally
  42.       ARasterImage.Free;
  43.     end;
  44.  
  45.   finally
  46.     AStream.Free;
  47.     ABMPReader.Free;
  48.     AChart.Free;
  49.   end;
  50. end;  

I've tried the nogui demo application in tachart, but this has other problems, probably outdated.

MaartenJB

  • Full Member
  • ***
  • Posts: 112
Re: Error when generating TChart image in Custom CGI Application on linux
« Reply #1 on: September 14, 2021, 12:32:17 pm »
Problem seems to be the nogui of the unit "Interfaces". If I use the nogui version on Windows I get the same error. If I use any other than the nogui on linux in the CGI it doesnt work.

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Error when generating TChart image in Custom CGI Application on linux
« Reply #2 on: September 14, 2021, 02:36:47 pm »
I did not check out your posted code since BGRABitmap is involved which makes the situation more complicated. Please extract the problematic code into a separate, compilable project so that I can see the issue in every detail. Remove BGRABitmap - in your code the error happens before BGRABitmap is used, and thus BGRABitmap is not needed (or it is the real cause of the issue).

When I run the nogui demo which comes with Lazarus there is no error - there is an issue with fonts, though, which seem to render at all. What are the "other problems" that you mention in your first post?

MaartenJB

  • Full Member
  • ***
  • Posts: 112
Re: Error when generating TChart image in Custom CGI Application on linux
« Reply #3 on: September 14, 2021, 03:05:13 pm »
Hi wp, you're right, I should have only included the source of my problem, but usually you get the question: "why do you want that" or something similar.

I've created a tiny project, attached in the zip. Be aware I've set the lclwidgettype to nogui. If you run it you'll get the "TRasterImage.BitmapHandleNeeded: Unable to create handles, using default" error.

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: Error when generating TChart image in Custom CGI Application on linux
« Reply #4 on: September 14, 2021, 03:55:49 pm »
Never worked a lot with the nogui widgetset, so maybe the following thoughts are not correct...

But when you compare the contents of the directory (lazarus)/lcl/interfaces/nogui with those of, say, (lazarus)/lcl/interfaces/win32 you see that there almost no files. This means that most of the features available in the win32 or gtk2 or qt widgetsets is not available. Under "Project options" > "Additions and overrides" add a new option "-gw2" which forces rebuilding all required units with Dwarf-2 debug information. Then set a breakpoint on  AChart.SaveToBitmap and step into the procedure. This will lead you to TCanvas.Requiredstate where a handle for the canvas is created (CreateHandle). Debugging into CreateHandle finally leads you to RawImage_CreateBitmaps which is a widgetset function; but for nogui this is not implemented and it will do nothing. No way to create a bitmap image under nogui this way...

Rather than that, you must follow the steps proposed by the noguidemo of TAChart: Create an FPMemoryImage and an associated FPImageCanvas and paint on this handle-free canvas.

Here is a simple demo how this could be done:
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes,
  7.   FPCanvas, FPImage, FPImgCanv, FPWriteBmp;
  8.  
  9. const
  10.   W = 300;
  11.   H = 200;
  12. var
  13.   img: TFPMemoryImage;
  14.   c: TFPImageCanvas;
  15.   writer: TFPWriterBMP;
  16.   stream: TFileStream;
  17. begin
  18.   img := TFPMemoryImage.Create(W, H);
  19.   try
  20.     c := TFPImageCanvas.Create(img);
  21.     try
  22.       c.Brush.FPColor := colYellow;
  23.       c.FillRect(0, 0, W, H);
  24.       c.Pen.FPColor := colRed;
  25.       c.Pen.Width := 3;
  26.       c.Line(0, 0, W, H);
  27.       c.Line(0, H, W, 0);
  28.       writer := TFPWriterBMP.Create;
  29.       try
  30.         stream := TFileStream.Create('test.bmp', fmCreate + fmOpenWrite);
  31.         try
  32.           writer.ImageWrite(stream, img);
  33.         finally
  34.           stream.Free;
  35.         end;
  36.       finally
  37.         writer.Free;
  38.       end;
  39.     finally
  40.       c.Free;
  41.     end;
  42.   finally
  43.     img.Free;
  44.   end;
  45.  
  46.   WriteLn('Done.');
  47.   ReadLn;
  48. end.

This code does not require the Graphics unit and thus is independent of the LCL. In case of TAChart, however, this becomes more difficult because it DOES use the Graphics unit, and in case of the nogui widgetset all its graphics calls would run into nowhere. Therefore, TAChart has the concept of drawing backends which redirects all drawing commands to an internal "drawer" class. In our case, the correct drawer is the TFPCanvasDrawer, which paints on a TFPCanvas like in above example. All drawing codes require this drawer as a parameter.

Please study the noguidemo of the TAChart installation. Tell me what is not working here (except for the fonts issue which I already know).

MaartenJB

  • Full Member
  • ***
  • Posts: 112
Re: Error when generating TChart image in Custom CGI Application on linux
« Reply #5 on: September 14, 2021, 04:21:58 pm »
Thanks for the explanation, I understand.

The issue I have with the nogui demo of tchart is only that the fonts are not working, which is pretty important.

I am able to render images in nogui, with this demo and with the use of tbgrabitmap. I can even put text on an image like in my first post.

 

TinyPortal © 2005-2018