Forum > TAChart

Error when generating TChart image in Custom CGI Application on linux

(1/2) > >>

MaartenJB:
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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---ARasterImage := AChart.SaveToImage(TBitmap); // This generates the error
This is the full procedure I use to generate an image from a tchart:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure GenChart(AWidth, AHeight: Integer; APngResult: TStream);var  ABgraBitmap : TBGRANoGUIBitmap;  ARasterImage : TRasterImage;  AStream : TMemoryStream;  ABMPReader : TFPReaderBMP;  AChart: TChart;begin  if (not Assigned(APngResult))  then Exit;   AChart := TChart.Create(nil);  AChart.Width := AWidth;  AChart.Height := AHeight;  try    AStream := TMemoryStream.Create;    ABMPReader := TFPReaderBMP.Create;     ARasterImage := AChart.SaveToImage(TBitmap); // <<---- This will generate the error    try      ARasterImage.SaveToStream(AStream);      AStream.Position:=0;       ABgraBitmap := TBGRANoGUIBitmap.Create;      try        ABgraBitmap.LoadFromStream(AStream, ABMPReader);        ABgraBitmap.FontFullHeight:=22;         {$IFDEF WINDOWS}          ABgraBitmap.FontName:='C:\windows\fonts\arial.ttf';        {$ELSE}          ABgraBitmap.FontName:='/home/maarten/Documents/lazarus-components/bgrabitmap-master/test/test4other/arial.ttf';        {$ENDIF}        ABgraBitmap.TextOut(50,10, TimeToStr(Now), CSSRed);         APngResult.Position := 0;        ABgraBitmap.SaveToStreamAsPng(APngResult);      finally        ABgraBitmap.Free;      end;    finally      ARasterImage.Free;    end;   finally    AStream.Free;    ABMPReader.Free;    AChart.Free;  end;end;  
I've tried the nogui demo application in tachart, but this has other problems, probably outdated.

MaartenJB:
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:
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:
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:
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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program project1; {$mode objfpc}{$H+} uses  Classes,  FPCanvas, FPImage, FPImgCanv, FPWriteBmp; const  W = 300;  H = 200;var  img: TFPMemoryImage;  c: TFPImageCanvas;  writer: TFPWriterBMP;  stream: TFileStream;begin  img := TFPMemoryImage.Create(W, H);  try    c := TFPImageCanvas.Create(img);    try      c.Brush.FPColor := colYellow;      c.FillRect(0, 0, W, H);      c.Pen.FPColor := colRed;      c.Pen.Width := 3;      c.Line(0, 0, W, H);      c.Line(0, H, W, 0);      writer := TFPWriterBMP.Create;      try        stream := TFileStream.Create('test.bmp', fmCreate + fmOpenWrite);        try          writer.ImageWrite(stream, img);        finally          stream.Free;        end;      finally        writer.Free;      end;    finally      c.Free;    end;  finally    img.Free;  end;   WriteLn('Done.');  ReadLn;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).

Navigation

[0] Message Index

[#] Next page

Go to full version