Search code examples
delphipdfrave-reports

Add new Rave Report page using template in Delphi


I'm completely new to Rave Reports and struggling to get to grips with it.

The goal is to have a PDF that contains a cover page and then any number of what is essentially the same page but containing different images.

I have set up the pages using the designer and can get the report to print or save to PDF.

I cannot figure out how to dynamically duplicate / add the page that will contain the images.

The process would be:

  • Add cover page
  • Iterate over list of images and add image page from existing layout / template
  • Save to PDF

Any help or a point in the right direction would be much appreciated.

Thanks

--- UPDATE ---

I have used the following code but cannot figure out how to get it working. The report should have 4 images on each page so if there were 9 images there should be 3 pages. The loop created the correct amount of pages but the last images in the list are repeated on each page.

Any ideas?

procedure TForm1.Button1Click(Sender: TObject);
var
  ReportPages       : array of TRavePage;
  CoverPage         : TRavePage;
  MyProject         : TRaveReport;
  PageList          : TRaveComponentList;

  staffImage        : TRaveBitmap;

  numberOfPages     : Integer;
  numberOfImages    : Integer;

  imageNumber       : Integer;
  pageNumber        : Integer;
  imagesPerPage     : Integer;
  pageImageCounter  : Integer;

  isFirstImage      : Boolean;
  isLastImage       : Boolean;
begin
  buildImageList;

  imageNumber := 0;
  imagesPerPage := 4;

  numberOfImages := imageList.count;
  numberOfPages := ceil(numberOfImages / imagesPerPage);

  RvSystem1.DoNativeOutput := false;
  RvSystem1.RenderObject := RvRenderPDF1;
  RvSystem1.OutputFileName := 'Project1.pdf';
  RvProject1.Open;

  RvProject1.SetParam('Name1', Name1Edit.Text);
  RvProject1.SetParam('Name2', Name2Edit.Text);

  MyProject := RvProject1.ProjMan.FindReport('staffImageProof', true) as TRaveReport;

  CoverPage:= RvProject1.ProjMan.FindRaveComponent('coverPage', MyProject) as TRavePage;
  PageList:= TRaveComponentList.Create;
  PageList.Add(CoverPage);

  pageNumber := 0;
  pageImageCounter := 0;

  setLength(ReportPages, numberOfPages);

  for imageNumber := 0 to numberOfImages - 1 do
    begin
      inc(pageImageCounter);

      if pageImageCounter = 1 then
        begin
          ReportPages[pageNumber] := RvProject1.ProjMan.FindRaveComponent('imagePage', MyProject) as TRavePage;
        end;

      staffImage := ReportPages[pageNumber].FindComponent('staffImage' + intToStr(pageImageCounter)) as TRaveBitmap;
      staffImage.Image.LoadFromFile(imageList[imageNumber]);

      if (pageImageCounter = imagesPerPage) or (imageNumber = (numberOfImages - 1)) then
        begin
          PageList.Add(ReportPages[pageNumber]);
          pageImageCounter := 0;
          inc(pageNumber);
        end;
    end;

  MyProject.PageList := PageList;

  RvProject1.SelectReport('staffImageProof', false);
  RvProject1.StoreRAV := true;
  RvProject1.Execute;
  RvProject1.Close;
  Finalize(ReportPages);
end;

Solution

  • Considering you have a rave report file with a Report named 'Report1' with two pages :

    • 'CoverPage' : your cover page with all the stuff you want
    • 'ReportPage' : the template with a Bitmap component named 'Image' and all other things you need.

    In your Delphi code, on your form you need :

    • TRvProject 'RvProject1', with property 'ProjectFile' linked to your RaveReport file (extension .rav)
    • TRvSystem 'RvSystem1' to save your PDF
    • TRvRenderPDF 'RvRenderPDF1'

    In a ReportButton OnClick event, you have to use TRaveReport, TRavePage, an array of TRavePage, TRaveBitmap and TRaveComponentList :

    procedure TForm1.ReportButtonClick(Sender: TObject);
    var
      ReportPages: array of TRavePage;
      CoverPage: TRavePage;
      ImageFile: TRaveBitmap;
      MyProject: TRaveReport;
      PageList: TRaveComponentList;
      i: Integer;
    begin
      RvSystem1.DoNativeOutput:=false;
      RvSystem1.RenderObject:=RvRenderPDF1;
      RvSystem1.OutputFileName:='Project1.pdf';
      RvProject1.Open;
    
      MyProject:= RvProject1.ProjMan.FindReport('Report1', true) as TRaveReport;
    
      CoverPage:= RvProject1.ProjMan.FindRaveComponent('CoverPage', MyProject) as TRavePage;
      PageList:= TRaveComponentList.Create;
      PageList.Add(CoverPage);
    
      SetLength(ReportPages, PageCount);
      for i := 0 to PageCount - 1 do begin
        ReportPages[i]:= RvProject1.ProjMan.FindRaveComponent('ReportPage', MyProject) as TRavePage;
        ImageFile:=TRaveBitmap(RvProject1.ProjMan.FindRaveComponent('Image',ReportPages[i]));
        ImageFile.Image.LoadFromFile(MyImageList[i]);
        PageList.Add(ReportPages[i]);
      end;
      MyProject.PageList:= PageList;
    
      RvProject1.SelectReport('Report1', false);
      RvProject1.StoreRAV:=true;
      RvProject1.Execute;
      RvProject1.Close;
      Finalize(ReportPages);
    end;
    

    UPDATE

    Ok, after few hours of search, I found an explanation : you have to clone the template page to use it in your report. Otherwise, you just copy the page in your RvProject so the last image of the last page is copied in all other pages.

    To clone the page, you have to use TStreamHelper class in RvUtil unit :

    var
      AStreamHelper: TStreamHelper;
      AStream: TMemoryStream;
      OldName: string;
      TempName: string;
      TemplatePage: TRavePage;
    begin
    ...
    ...
      TemplatePage:= RVProject1.ProjMan.FindRaveComponent('imagePage', MyProject) as TRavePage;
    
      for imageNumber := 0 to numberOfImages - 1 do
      begin
        inc(pageImageCounter);
    
        if pageImageCounter = 1 then
        begin
          AStream := TMemoryStream.Create;
          AStreamHelper := TStreamHelper.Create(AStream);
          AStreamHelper.SavePos;
          TemplatePage.SaveToStreamHelper(AStreamHelper);
          AStreamHelper.RestorePos;
    
          OldName := TemplatePage.Name;
          TemplatePage.Name := 'template';
    
          ReportPages[pageNumber] := TRavePage.Create(MyProject);
          ReportPages[pageNumber].LoadFromStreamHelper(AStreamHelper);
          AStreamHelper.Destroy;
          AStream.Destroy;
    
          ReportPages[pageNumber].Name := 'imagePage'+IntToStr(pageNumber);
          TemplatePage.Name := OldName;
          ReportPages[pageNumber].Parent:= MyProject;
        end;
    
        staffImage := ReportPages[pageNumber].FindComponent('staffImage' + intToStr(pageImageCounter)) as TRaveBitmap;
        staffImage.Image.LoadFromFile(imageList[imageNumber]);
    
        if (pageImageCounter = imagesPerPage) or (imageNumber = (numberOfImages - 1)) then
        begin
          PageList.Add(ReportPages[pageNumber]);
          pageImageCounter := 0;
          inc(pageNumber);
        end;
      end;
      ...
      ...