Home General
New Blog Posts: Merging Reports - Part 1 and Part 2

ArchiveReader and Streams

Hi,

Just wondering if there is an example on how to use the archive reader with a stream, or if you can please advise what is wrong with the below code?
MS1 := TMemoryStream.Create;
lArchiveReader := TppArchiveReader.Create(nil);
lArchiveDevice := TppArchiveDevice.Create(nil);
lArchiveDevice.Publisher := lArchiveReader.Publisher;
lArchiveDevice.OutputStream := MS1;
if not Table.isempty then
begin
while not Table.eof do
begin
MS2 := TMemoryStream.create;
TableReportData.SaveToStream(MS2);
MS2.position := 0;
lArchiveDevice.StartPrintJob := Table.Bof;
lArchiveDevice.EndPrintJob := (Table.RecNo = Table.RecordCount);
lArchiveReader.ArchiveStream := MS2;
lArchiveReader.PrintToDevices;
MS2.free;
Table.next;
end;

lArchiveReader.AllowPrintToFile := true;
lArchiveReader.ShowPrintDialog := False;
lArchiveReader.DeviceType := dtPDF;

lArchiveReader.PDFSettings.Author := Appname;
lArchiveReader.PDFSettings.Title := 'Title';
lArchiveReader.PDFSettings.OpenPDFFile := false;
lArchiveReader.TextFileName := 'c:\temp\merged.pdf';
lArchiveReader.Print;

ms1.free;
lArchiveDevice.Free;
lArchiveReader.Free;
Thanks & Regards

Adam.

Comments

  • Hi Adam,

    The issue is that your merged archive data is held in the MS1 stream, yet you never assign it to the ArchiveReader after the loop.

    Your code above merges multiple archives to a single archive, then exports that to PDF. You could skip the first step and merge the multiple archives (from your DB) directly to PDF.
    begin

    lArchiveReader := TppArchiveReader.Create(nil);
    lPDFDevice := TppPDFDevice.Create(nil);

    try

    lPDFDevice.FileName := 'c:\temp\merged.pdf';
    lPDFDevice.PDFSettings.Title := 'Title';
    lPDFDevice.OpenFile := False;

    lPDFDevice.Publisher := lArchiveReader.Publisher;

    if not(Table.isempty) then
    begin

    while not(Table.eof) do
    begin
    MS2 := TMemoryStream.create;
    try
    TableReportData.SaveToStream(MS2);
    MS2.position := 0;
    lPDFDevice.StartPrintJob := Table.Bof;
    lPDFDevice.EndPrintJob := (Table.RecNo = Table.RecordCount);
    lArchiveReader.ArchiveStream := MS2;
    lArchiveReader.PrintToDevices;
    Table.next;
    finally
    MS2.free;
    end;
    end;
    end;

    finally
    lPDFDevice.Free;
    lArchiveReader.Free;
    end;

    end;
    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • Wonderful - thanks Nico!

    And thanks for all your help this year too!
  • Hi Nard,

    Just a quick question. Instead of using

    lPDFDevice.FileName := 'c:\temp\merged.pdf';

    I was hoping to save the end result to MS1. (TMemoryStream). Just wondering if this is possible, or whether I have to offload it to a file, and then re-import it?

    Thanks & Regards

    Adam.
  • Hi Adam,

    Rather than assigning the FileName of the PDFDevice, simply set its OutputStream property to the memory stream you would like to write to (MS1).
    begin

    MS1 := TMemoryStream.Create;
    lArchiveReader := TppArchiveReader.Create(nil);
    lPDFDevice := TppPDFDevice.Create(nil);

    try

    lPDFDevice.OutputStream := MS1;

    ...
    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • Thanks Nico. Got it all working well now! Appreciate the help.
  • edited January 2023
    For anyone else who may come across this in the future, I ran into some issues with this still not working, and had to add the line:

    lDevice.reset

    after each itteration of PrintToDevices.


    The end result is the following functions/procedures which I leave here in case it may come in handy for anyone else looking to do anything similar in the future. (Or incase I forget and find my own question 10 years from now... it's happened before ;-)
    function CombineReports(const ReportList: TList<TMemoryStream>): TMemoryStream;
    var
      lArchiveReader: TppArchiveReader;
      lDevice: TppArchiveDevice;
      i: Integer;
    begin
      Result := TMemoryStream.Create;
      lArchiveReader := TppArchiveReader.Create(nil);
      try
        lDevice := TppArchiveDevice.Create(nil);
        try
          lDevice.Publisher := lArchiveReader.Publisher;
          lDevice.OutputStream := Result;
    
          for i := 0 to ReportList.Count - 1 do
          begin
            lDevice.StartPrintJob := (i = 0);
            lDevice.EndPrintJob := (i = ReportList.Count - 1);
            lArchiveReader.ArchiveStream := ReportList[i];
            lArchiveReader.PrintToDevices;
            lDevice.reset;
          end;
        finally
          lDevice.Free;
        end;
      finally
        lArchiveReader.Free;
      end;
    end;
    
    
    procedure RenderRBArchivesToStream(ML: TList<TMemoryStream>; var MS: TMemoryStream; DeviceType: string = dtPDF);
    var
      ms1: TMemoryStream;
      LDevice: TppArchiveDevice;
      LPDFDevice: TppPDFDevice;
      lArchiveReader: TppArchiveReader;
    begin
      if ML = nil then
        exit;
    
      try
        MS1 := CombineReports(ML);
    
    
        if MS1 <> nil then
        begin
          if DeviceType = dtArchive then
            MS.LoadFromStream(MS1)
          else
          begin
            lArchiveReader := TppArchiveReader.Create(nil);
            lPDFDevice := TppPDFDevice.Create(nil);
            LPDFDevice.Publisher := lArchiveReader.Publisher;
            LPDFDevice.outputstream := MS;
            LPDFDevice.StartPrintJob := true;
            LPDFDevice.EndPrintJob := true;
            lArchiveReader.ArchiveStream := ms1;
            lArchiveReader.PrintToDevices;
    
            LPDFDevice.Free;
            lArchiveReader.Free;
          end;
    
          FreeAndNil(MS1);
        end;
    
      except
        try
          LDevice.Free;
          lArchiveReader.Free;
        finally
    
        end;
        raise;
      end;
    
    end;
    
    
    procedure PrintToStream(Report: TPPReport; var MS: TMemoryStream);
    var
      LDevice: TppArchiveDevice;
    begin
      ms := TMemoryStream.create;
      lDevice := TppArchiveDevice.Create(nil);
      if not assigned(MS) then
        ms := TMemoryStream.create
      else
        ms.clear;
    
      try
        lDevice.OutputStream := MS; // assign output stream
        lDevice.Publisher := Report.Publisher;
        Report.PrintToDevices;
        ldevice.free;
      except
        ldevice.free;
        raise;
      end;
      MS.Position := 0;
    end;
Sign In or Register to comment.