Access Violation related to pictureStream or big documents ?

Knowledge exchange related to the VPE Report Engine and PDF Library

Moderator: IDEAL Software Support

Access Violation related to pictureStream or big documents ?

Postby nicolasBBS » Thu Nov 03, 2016 12:03 pm

Hello,

I've been using VPE for maybe 10 years now, and I have some problems when printing big documents.

I'm currently using VPE 3271 with Delphi 10.1.

Before now I had this problem occasionally when generating documents with a lot of pages (several hundreds), and I didn't know how to identify the cause...
It could be related to VPE.Picture or VPE.PictureResID, because I used it for a few small images per page, but maybe it was not related to images at all, because I used a lot of other functions...

But now I'm generating some new documents with only large images (one 257x190mm 600dpi bitmap on each page) with pictureStream, and I always have this violation when the number of pages is more than around 15.
I saw this problem was discussed on this thread, but not solved : viewtopic.php?f=7&t=1224&p=3301

I get an access violation message : "Violation d'accès à l'adresse 0F4EA6AE dans le module 'vpee3271.DLL'. Lecture de l'adresse 00000000."
In english : Access violation at 0F4EA6AE in vpee3271.DLL, reading address 00000000.

I have isolated the generation code, I can send you a ready to run sample project (with source code, exe and image sample used), but I don't know how to attach files in this forum.

Note that the hard way to do this simple bitmap printing (using Device Contexts and MemoryStream) is the only way I've found to get compliance between VPE and some grid component printing functions that I'm using (this TMS component uses a TCanvas, it takes care of dpi, and it is able to split onto several pages, but I had to use its preview function and customize it to get each page on a bitmap in preview mode).

Please can you tell me how to send you my sample project ?
Thank you !
nicolasBBS
 
Posts: 9
Joined: Fri Dec 10, 2010 5:42 pm

Re: Access Violation related to pictureStream or big documen

Postby nicolasBBS » Thu Nov 03, 2016 2:44 pm

Hello,

As I don't find how to post attached files, this is at least my sample source code, you only need to create a project with a button and a TVPEngine on a form and add this code in the button click event :
And Use some bitmap file of your choice, mine is 1430x2089 pixels, but it should work with any bitmap because I use a StrechDraw.
Please read comments into the code, they explain what I do and why I do it, and maybe you could have some comments about it...

Code: Select all
uses ShellAPI, printers;

procedure TForm1.Button1Click(Sender: TObject);
var sample:TBitmap;
    i:integer;
    ms:TMemoryStream;
    s1:TVPEStream;
    frameWidth,frameheight,imgwidth,imgheight,oldpensize:double;
    hMemDC,DC:HDC;
    hBmp:HBITMAP;
    hOldBmp:HGDIOBJ;
    rect_:TRect;
    mm:integer;
    FCanvas:TCanvas;
    FImgGrid:TBitmap;
    cl:TColor;
begin
   VPEngine1.OpenDoc;
   VPEngine1.License({'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'});
   VPEngine1.SaveFileName := '*.pdf';
   VPEngine1.Compression := DOC_COMPRESS_FLATE;

   //Some sample image loaded from a file, but the real image is generated by some grid component.
   sample:=TBitmap.Create;
   sample.LoadFromFile('Sans titre.bmp');
   sample.Canvas.Brush.Color:=clblue;

   if printer.printers.Count>0 then
   begin
     printer.printerIndex:=-1;
     DC := CreateDC(0, PChar(printer.printers[printer.printerIndex]),nil, nil);
   end
   else
   begin
     showmessage('Please install a printer !');
     exit;
   end;

   rect_.Top:=0;
   rect_.Left:=0;
   rect_.Right:=1900;//19cm in 0.1mm
   rect_.Bottom:=-2570;//25,7cm
   mm:=GetMapMode(DC);
   SetMapMode(DC,MM_LOMETRIC);
   lptodp(DC,rect_.Topleft,1);
   lptodp(DC,rect_.Bottomright,1);
   setMapMode(DC,mm);

   //Create some Memory Device Context base on some printer (to get its definition because screen defintion is too bad).
   //And some compatible bitmap, at the size of our printing area.
   hMemDC :=CreateCompatibleDC(DC);
   hBmp   :=CreateCompatibleBitmap(DC,rect_.Width, rect_.height);
   hOldBmp:=SelectObject(hMemDC,hBmp);

   //My printing component works with a Canvas, not directly with a DC handle.
   //So I create this canvas and I associate it with the Memory DC.
   FCanvas:=TCanvas.Create;
   FCanvas.Handle:=hMemDC;   //Old canvas Handle was not allocated.
   //We will need to access to the bitmap through some TBitmap object, using its SaveToStream function.
   //So I create the TBitmap and associate it with the Memory Bitmap Handle.
   FImgGrid:=TBitmap.Create;
   FImgGrid.Handle:=hBmp;    //Old Tbitmap Handle was not allocated.

   //Initialze the canvas to white color, otherwise it is black with printer's DC (strange but the grid component do the same into some printing routines).
   mm:=GetMapMode(hMemDC);
   SetMapMode(hMemDC,MM_TEXT);
   Fcanvas.Brush.Color:=clWhite;
   Fcanvas.FillRect(rect_);
   setMapMode(hMemDC,mm);


   //Normally I call the grid preview function :
   //But here I'll draw the sample bitmap onto the canvas into the loop...
   //grid.OnPrintPageDone:=gridPrintPageDone;
   //grid.PrintPreview(FCanvas,Rect_);

   for i := 0 to 20 do //access violation at round 15
   begin
     Sample.Canvas.FillRect(Rect(2*i,2*i,10*i,20*i)); //Just to modify the sample image between two pages
     caption:='Printing image '+intToStr(i+1);//showing progress

     //Simulate grid drawing with my sample bitmap.
     FCanvas.StretchDraw(rect_,sample);

     //In real world, the code in this loop is called by the grid OnPrintPageDone call back.

     ms:=TMemoryStream.create;
     FImgGrid.SaveToStream(ms);

     //print MemoryStream
     s1:=VPEngine1.CreateMemoryStream(ms.Size);
     s1.Write(ms.memory^,ms.Size);
     s1.Seek(0);
     with VPEngine1 do
     begin
        //Calculate image size
        PictureBestFit:=true;
        frameWidth:=nRightMargin-nLeftMargin-0.06;
        frameHeight:=nBottomMargin-nTopMargin-0.06;
        RenderPictureStream(s1,frameWidth,frameHeight,'FTable');
        imgWidth:=nRenderWidth;
        imgHeight:=nRenderHeight;
        //Print wiht VPE
        oldPenSize:=pensize;
        PenSize:=0;
        PictureStream(s1,nLeftMargin+0.03+(frameWidth-imgWidth)/2,nTopMargin+0.03+(frameHeight-imgHeight)/2  ,nRightMargin-0.03-(frameWidth-imgWidth)/2 ,nBottomMargin-0.03-(frameHeight-imgHeight)/2,'FTable');
        PenSize:=oldPenSize;
        //Page number and legend
        SetOutRect(1,1,PageWidth-1,PageHeight-1);
        TextAlignment:=ALIGN_CENTER;
        Write(nLeftMargin,nTopMargin-0.5,nRightMargin,nTopMargin,'Some text Here');
        TextAlignment:=ALIGN_RIGHT;
        WriteBox(nRightMargin-1.5,nBottomMargin-0.5,nRightMargin,nBottomMargin,format('%d/%d',[i,40]));
        TextAlignment:=ALIGN_LEFT;

        //Note that in real world, page titles and frames are loaded and printed from some VPE template, and it sets the margins.
     end;
     ms.Free;
     s1.close;
     VPEngine1.PageBreak;

     //Prepare new page :
     //With screen DC it is unnecessary, but with a printer DC I can't redraw on the same bitmap, I don't know why.
     //So I change all Handles to start again on a new clear bitmap.
     //But I continue to have some strange results : when displaying the PDF file with Adobe Reader, images don't always show fully.
     //And if you change zoom level into Adobe Reader, images redraw and generally are shown correctly.
     //It seems like if the white area overlapped the real image, but not always (two layers at the same level).
     //I have this behavior when the grid is really drawing onto the canvas, but not with the stretchDraw into this test.
     selectObject(hMemDC,hOldBmp);
     deleteObject(hbmp);
     DeleteDC(hMemDC);
     deleteObject(hOldBmp);
     hMemDC :=CreateCompatibleDC(DC);
     hBmp   :=CreateCompatibleBitmap(DC,rect_.Width, rect_.height);
     hOldBmp:=selectObject(hMemDC,hBmp);
     FImgGrid.Handle:=hBmp;
     FCanvas.Handle:=hMemDC;
     //Initialize the Canvas with a white area.
     mm:=getMapMode(Fcanvas.Handle);
     setMapMode(Fcanvas.Handle,MM_TEXT);
     cl:=Fcanvas.Brush.Color;
     Fcanvas.Brush.Color:=clWhite;
     Fcanvas.FillRect(rect_);
     Fcanvas.Brush.Color:=cl;
     setMapMode(Fcanvas.Handle,mm);

   end;


   VPEngine1.WriteDoc('essai.pdf');

   ShellExecute(application.Handle, 'open', PChar('essai.pdf'), '', '',SW_SHOWMAXIMIZED);
   VPEngine1.CloseDoc;

   //release Memory DC
   SelectObject(hMemDC,hOldBmp);
   DeleteDC(hMemDC);   //Maybe it is done by FCanvas when it is destroyed, but I prefer doing it twice than not at all.
   DeleteObject(hOldBmp);
   //release Bitmap
   DeleteObject(hBmp); //Maybe it is done by FImgGrid when it is destroyed, but I prefer doing it twice than not at all.
   FreeAndNil(FCanvas);
   FreeAndNil(FImgGrid);
   //release the real printer DC.
   deleteDC(DC);

end;
nicolasBBS
 
Posts: 9
Joined: Fri Dec 10, 2010 5:42 pm

Re: Access Violation related to pictureStream or big documen

Postby IDEAL Software Support » Fri Nov 04, 2016 10:02 am

Please send complete projects as ZIP file to our support e-mail address.

See http://www.idealsoftware.com/en/support/contact.html for details.
IDEAL Software Support
 
Posts: 1633
Joined: Thu Nov 18, 2004 4:03 pm

Re: Access Violation related to pictureStream or big documen

Postby IDEAL Software Support » Mon Apr 03, 2017 2:16 pm

To provide updated information for other users:

The customer created *many very huge* in-memory bitmaps, which consumed all available system memory space. Therefore at some point the application crashed.

If there is the requirement to use many huge bitmaps, a better design is to store the bitmaps on disk, and to use the normal Picture() method provided by VPE, which expects a file name as image source. This way VPE can make use of its image cache and load/unload images dynamically to/from memory as desired (i.e. when an image is displayed, printed or exported to PDF).
IDEAL Software Support
 
Posts: 1633
Joined: Thu Nov 18, 2004 4:03 pm


Return to VPE Open Forum

Who is online

Users browsing this forum: No registered users and 12 guests

cron