New Blog Post: PDF/A and Metadata

Reading all text off a report - (spell checking)

edited March 2016 in General
Hi,

One of the things I would like to include within my applications for my
users is a spell checker for reports *after* they have been generated.

From Reportbuilder itself, all I need is the ability to scan and
extract text once the report has been generated. I was wondering if
there is a simple way to do this?

Since the text on the report I'm looking at adopting this from can be
populated by a variety of methods including data fields, by OnGetText
events, and even by end users editing the report templates themselves I
figure that the best way of performing some sort of spell check would be
to grab a list of all text from the report after it has been created
(ie, during preview), and work through that text through another
separate unit.

I don't need to do anything fancy such as highlighting the spelling
errors. My initial thought is just to display a list of words or text
that don't existing in a dictionary.

Is it possible to load all text from a particular report's text fields
after it's been generated in a previewer?

Thanks & Regards

Adam

Comments

  • edited March 2016
    Hi Adam,

    The best place to retrieve all text in a report would be the
    Device.OnPageReceive event. From there you could loop through all
    TppPage.DrawCommands and save all text needed. Unfortunately with the
    current design, it is not possible to use this event with multi-page
    viewing screen device. This is something we will look at improving for
    a future release.

    Below are a couple options to work around this:

    Option 1:
    Set the Report.PreviewFormSettings.SinglePageOnly property to True.
    This will allow you to implement the OnPageReceive event of the Screen
    device and gather all text in each page.

    Sample Code:

    uses
    ppViewr,
    ppDevice,
    ppDrwCmd;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    ppReport1.PreviewFormSettings.SinglePageOnly := True;
    ppReport1.Print;

    end;

    procedure TForm1.ehPageReceive(Sender, aPage: TObject);
    var
    lPage: TppPage;
    lDrawText: TppDrawText;
    liIndex: Integer;
    begin

    lPage := TppPage(aPage);

    for liIndex := 0 to lPage.DrawCommandCount - 1 do
    if lPage.DrawCommands[liIndex] is TppDrawText then
    begin
    lDrawText := TppDrawText(lPage.DrawCommands[liIndex]);

    if lDrawText.IsMultiLine then
    FList.AddStrings(lDrawText.WrappedText)
    else
    FList.Add(lDrawText.Text);
    end;

    end;

    procedure TForm1.ppReport1PreviewFormCreate(Sender: TObject);
    begin
    TppViewer(ppReport1.PreviewForm.Viewer).ScreenDevice.OnPageReceive :=
    ehPageReceive;

    end;

    Option 2:
    Create a "dummy" device and generate the report before generating to screen.

    Sample Code:

    procedure TForm1.Button1Click(Sender: TObject);
    var
    lDevice: TppDevice;
    begin

    lDevice := TppDevice.Create(Self);
    try
    lDevice.Publisher := ppReport1.Publisher;
    lDevice.OnPageReceive := ehPageReceive;
    ppReport1.PrintToDevices;
    finally
    lDevice.Publisher := nil;
    lDevice.Free;
    end;

    ppReport1.Print;

    end;

    procedure TForm1.ehPageReceive(Sender, aPage: TObject);
    //Same as above...



    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2016
    Hi Adam,

    After looking into this further, the TppViewer has a passthru
    OnPageReceive event that can be used so there is no need to access the
    screen device or set SinglePageOnly to True.

    uses
    ppViewr,
    ppDevice,
    ppDrwCmd;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    ppReport1.Print;

    end;

    procedure TForm1.ehPageReceive(Sender, aPage: TObject);
    var
    lPage: TppPage;
    lDrawText: TppDrawText;
    liIndex: Integer;
    begin

    lPage := TppPage(aPage);

    for liIndex := 0 to lPage.DrawCommandCount - 1 do
    if lPage.DrawCommands[liIndex] is TppDrawText then
    begin
    lDrawText := TppDrawText(lPage.DrawCommands[liIndex]);

    if lDrawText.IsMultiLine then
    FList.AddStrings(lDrawText.WrappedText)
    else
    FList.Add(lDrawText.Text);
    end;

    end;

    procedure TForm1.ppReport1PreviewFormCreate(Sender: TObject);
    begin
    TppViewer(ppReport1.PreviewForm.Viewer).OnPageReceive := ehPageReceive;

    end;

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2016
    Hi Nico,

    Thanks very much for your reply...

    The OnPageReceive event and your code seems to work well.

    The only problem I'm having is that it's skipping any text that's in
    RichText components.

    I was just wondering if there's something we can add to have it also
    include rich text?

    Thanks & Regards

    Adam.
  • edited March 2016
    Hi Adam,

    You can use the CreateCompatibleDrawText routine of the TppDrawRichText
    class to gain access to the underlying text of a rich text component.

    For example, you could change the PageReceive event to the following...

    var
    lPage: TppPage;
    lDrawText: TppDrawText;
    liIndex: Integer;
    begin

    lPage := TppPage(aPage);

    for liIndex := 0 to lPage.DrawCommandCount - 1 do
    begin
    lDrawText := nil;

    if (lPage.DrawCommands[liIndex] is TppDrawText) then
    begin
    lDrawText := TppDrawText.Create(nil);
    lDrawText.Assign(TppDrawText(lPage.DrawCommands[liIndex]));
    end;

    if (lPage.DrawCommands[liIndex] is TppDrawRichText) then
    lDrawText :=
    TppDrawRichText(lPage.DrawCommands[liIndex]).CreateCompatibleDrawText(nil);

    try

    if lDrawText <> nil then
    if lDrawText.IsMultiLine then
    FList.AddStrings(lDrawText.WrappedText)
    else
    FList.Add(lDrawText.Text);

    finally
    lDrawText.Free;
    end;

    end;


    end;

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2016
    Hi Nico


    That example works perfectly for me! Thank you very much!

    Best Regards

    Adam.
This discussion has been closed.