I've managed to build PDFium into a shared library on Ubuntu 16.04.  (I'll
announce a blog post on this later.)
Now I'm considering the best bitmap format to bring the rendered page back
into Pharo.
I'm seeking advise on...

Q1. Looking at the two significant bitmap creation functions below from the
C header file,
which of PDFium's bitmap formats is the best match for Pharo?

// Gray scale bitmap, one byte per pixel.
#define FPDFBitmap_Gray 1
// 3 bytes per pixel, byte order: blue, green, red.
#define FPDFBitmap_BGR 2
// 4 bytes per pixel, byte order: blue, green, red, unused.
#define FPDFBitmap_BGRx 3
// 4 bytes per pixel, byte order: blue, green, red, alpha.
#define FPDFBitmap_BGRA 4

typedef void* FPDF_BITMAP;


// Function: FPDFBitmap_CreateEx
//          Create a device independent bitmap (FXDIB)
// Parameters:
//          width       -   The number of pixels in width for the bitmap.
//                          Must be greater than 0.
//          height      -   The number of pixels in height for the bitmap.
//                          Must be greater than 0.
//          format      -   A number indicating for bitmap format, as
defined
//                          above.
//          first_scan  -   A pointer to the first byte of the first line if
//                          using an external buffer. If this parameter is
NULL,
//                          then the a new buffer will be created.
//          stride      -   Number of bytes for each scan line, for external
//                          buffer only.
// Return value:
//          The bitmap handle, or NULL if parameter error or out of memory.
// Comments:
//          Similar to FPDFBitmap_Create function, but allows for more
formats
//          and an external buffer is supported. The bitmap created by this
//          function can be used in any place that a FPDF_BITMAP handle is
//          required.
//
//          If an external buffer is used, then the application should
destroy
//          the buffer by itself. FPDFBitmap_Destroy function will not
destroy
//          the buffer.
FPDF_BITMAP
FPDFBitmap_CreateEx(
                                      int width,
                                      int height,
                                      int format,
                                      void* first_scan,
                                      int stride);


// Function: FPDFBitmap_Create
//          Create a device independent bitmap (FXDIB).
// Parameters:
//          width       -   The number of pixels in width for the bitmap.
//                          Must be greater than 0.
//          height      -   The number of pixels in height for the bitmap.
//                          Must be greater than 0.
//          alpha       -   A flag indicating whether the alpha channel is
used.
//                          Non-zero for using alpha, zero for not using.
// Return value:
//          The created bitmap handle, or NULL if a parameter error or out
of
//          memory.
// Comments:
//          The bitmap always uses 4 bytes per pixel. The first byte is
always
//          double word aligned.
//
//          The byte order is BGRx (the last byte unused if no alpha
channel) or
//          BGRA.
//
//          The pixels in a horizontal line are stored side by side, with
the
//          left most pixel stored first (with lower memory address).
//          Each line uses width * 4 bytes.
//
//          Lines are stored one after another, with the top most line
stored
//          first. There is no gap between adjacent lines.
//
//          This function allocates enough memory for holding all pixels in
the
//          bitmap, but it doesn't initialize the buffer. Applications can
use
//          FPDFBitmap_FillRect to fill the bitmap using any color.
FPDF_BITMAP
FPDFBitmap_Create(
                                  int width,
                                  int height,
                                  int alpha);


// Function: FPDFBitmap_Destroy
//          Destroy a bitmap and release all related buffers.
// Parameters:
//          bitmap      -   Handle to the bitmap. Returned by
FPDFBitmap_Create.
// Return value:
//          None.
// Comments:
//          This function will not destroy any external buffers provided
when
//          the bitmap was created.
void FPDFBitmap_Destroy(FPDF_BITMAP bitmap);


Pharo's relevant class comments are...

* Bitmap - My instances provide contiguous storage of bits, primarily to
hold the graphical data of Forms. Forms and their subclasses provide the
additional structural information as to how the bits should be interpreted
in two dimensions.

* Form - A rectangular array of pixels, used for holding images.  All
pictures, including character images are Forms.  The depth of a Form is how
many bits are used to specify the color at each pixel.  The actual bits are
held in a Bitmap, whose internal structure is different at each depth.
The supported depths (in bits) are 1, 2, 4, 8, 16, and 32.  The number of
actual colors at these depths are: 2, 4, 16, 256, 32768, and 16 million.
Forms are indexed starting at 0 instead of 1; thus, the top-left pixel of a
Form has coordinates 0@0.
Forms are combined using BitBlt.  See the comment in class BitBlt.  Forms
that repeat many times to fill a large destination are InfiniteForms.

So it seems Bitmap is agnostic to the format stored inside it, and it is
Form that interprets the bitmap format.
A 32 bit depth Form seems an obvious choice, but I'm not sure about the
alpha options.


Q2. Tips on how to display such a bitmap in Pharo?

 I found this example...
   | extent form ptr |
   extent := 400@300.
   form := ExternalForm extent: extent depth: 32.
   ptr := ExternalAddress gcallocate: (extent x * extent y * 4).
   form setManualSurfacePointer: ptr.
      "insert here call to PDFium to render page to bitmap"
   Display displayScaledOn: form.
   form displayAt: 0@0.
   form destroySurface.

where in my case I guess the "ptr:="  line might be replaced by...
   ptr := ffi_FPDFBitmap_Create
             width: extent x
             height: extent y
             alpha: 0.

or...
   ptr := ffi_FPDFBitmap_CreateEx
                  width: extent x
                  height: extent y
                  format: ??
                  first_scan: 0
                  stride: 0

but it seems ExternalForm doesn't exist in Pharo 6.
ExternalForm seems to have been taken over by OSSDL2ExternalForm... ???

* OSSDL2ExternalForm - An ExternalForm is a specialized Form whose
pixel-data is stored in memory that the user provides a pointer to.  This
can simply be memory on the C heap, or (the motivating use-case...) it can
be a pointer that is temporarily "mapped" from GPU memory by an API such as
OpenCL.
IMPORTANT: Moved form FFI to SDL2 because is not needed there anymore but
OSWindow-SDL2 package uses it.
The user is responsible for both releasing the image-memory, as well as
destroying the surface handle (perhaps the latter should be handled by
automatic finalization).



Q3a. Are there any general guiding FFI principals whether its better to use
memory allocated by the library, or memory allocated by Pharo?  Perhaps
instead I should use...
   pharo_allocated := ExternalAddress gcallocate: (extent x * extent y * 4).
   ptr := ffi_FPDFBitmap_CreateEx
                  width: extent x
                  height: extent y
                  format: ??
                  first_scan: pharo_allocated
                  stride: ??

Q3b. Is it possible/advisable to pin a Bitmap and pass it to an external
library?  Maybe it would be preferable to do something like...
   aBitmap := Bitmap new: (extent x * extent y * 4).
   ptr := ffi_FPDFBitmap_CreateEx
                  width: extent x
                  height: extent y
                  format: ??
                  first_scan: aBitmap pinnedAddress
                  stride: ??


cheers -ben


On Sun, Nov 5, 2017 at 11:24 PM, teso...@gmail.com <teso...@gmail.com>
wrote:

> Hello Ben,
>    UFFI does not allow you to call static libraries. Static libraries are
> not executable per se, they need to be linked in another program.
> As I know, the only way of using an static library from Pharo is to:
>   - Build a plugin that wraps it.
>   - Build a DLL exposing all the functions in the library and then they
> are used through UFFI.
>
> The second option is the easiest to me, but it depends how the library is
> built up. For example, if the library uses a lot of compile time code
> generation (like macros or templates) making a generic DLL is not so easy.
>
> I think it is better to see if not other project has already tackle this
> problem when using the desired static library.
>
> Cheers,
> Pablo
>
> On Sun, Nov 5, 2017 at 1:39 PM, Ben Coman <b...@openinworld.com> wrote:
>
>> I'm looking into calling PDFium from Pharo via FFI.
>> Currently I'm stalled a bit since it doesn't have a shared-library target.
>>
>> If you consider access to such a library would be useful to the
>> community,
>> please take a few moments to star this issue...
>> https://bugs.chromium.org/p/pdfium/issues/detail?id=826
>>
>> cheers -ben
>>
>>
>> P.S. Can anyone comment on calling into a static library via FFI?
>>
>>
>>
>> On Wed, Oct 11, 2017 at 2:05 PM, Ben Coman <b...@openinworld.com> wrote:
>>
>>>
>>>
>>> On Wed, Oct 11, 2017 at 2:03 PM, Ben Coman <b...@openinworld.com> wrote:
>>>
>>>>
>>>> > On Tue, Oct 10, 2017 at 8:58 PM, Manuel Leuenberger
>>>> > <leuenber...@inf.unibe.ch> wrote:
>>>> > > Hi,
>>>> > >
>>>> > > I want to view a PDF within Pharo. I found that Athens has a PDF
>>>> canvas, but I have no idea how to use it. Is there a way to view a PDF
>>>> within Pharo, so that I can scroll, zoom, click links etc. in the PDF?
>>>> > >
>>>> > > Cheers,
>>>> > > Manuel
>>>>
>>>>
>>>> On Wed, Oct 11, 2017 at 3:04 AM, Stephane Ducasse <
>>>> stepharo.s...@gmail.com> wrote:
>>>> >
>>>> > Hi manuel
>>>> >
>>>> > So far I do not know if we have this is Pharo.
>>>> > I imagine that we would have to build a renderer once we will have the
>>>> > PDF reader from Christian library.
>>>> >
>>>> > Stef
>>>>
>>>>
>>> [Edit: Update license link]
>>>
>>>
>>>> A renderer will have great synergy with PDFTalk, but I think a proof of
>>>> concept can be done independently.
>>>> I've been poking at this topic for a while looking for options.
>>>> Coincidentally a couple of days I discovered the PDFium library.
>>>> I haven't had time yet to give it a run, but it seems a good candidate
>>>> since...
>>>> * Its a successful commercial product by Foxit built into Chrome
>>>> converted to open source with Google's backing for use in Chromium
>>>>        https://www.foxitsoftware.com/company/press.php?id=305
>>>> * Its license is BSD style
>>>>        *https://github.com/hfiguiere/pdfium/blob/master/LICENSE
>>>> <https://github.com/hfiguiere/pdfium/blob/master/LICENSE>*
>>>> * Although written in C++ it has a C interface
>>>>       https://github.com/hfiguiere/pdfium/blob/master/public/fpdfview.h
>>>>       * Search here on  " Function: "  to skim through
>>>>       * Proof of concept seems to only need these key functions...
>>>>           * void    FPDF_RenderPageBitmap( FPDF_BITMAP bitmap,FPDF_PAGE
>>>> page, ... )
>>>>           * FPDF_BITMAP    FPDFBitmap_Create( int width, int height,
>>>> int alpha);
>>>>           * FPDF_PAGE   FPDF_LoadPage   ( FPDF_DOCUMENT document, int
>>>> page_index )
>>>>           * FPDF_DOCUMENT   FPDF_LoadMemDocument   ( const void*
>>>> data_buf ... )
>>>>           * void    FPDF_InitLibrary ()
>>>> * Has a concise getting started for POC...
>>>>       https://github.com/hfiguiere/pdfium/blob/master/docs/getting
>>>> -started.md
>>>> * Maybe useful fork with V8 disabled by default
>>>>       https://github.com/klokantech/pdfium
>>>> * Master repo here
>>>>       https://pdfium.googlesource.com/pdfium/
>>>>
>>>> So Pharo might load a PDF file into a ByteArray, pass that to
>>>> FPDF_LoadMemDocument() & FPDF_LoadPage(),
>>>> then get a bitmap back from FPDFBitmap_Create() &
>>>> FPDF_RenderPageBitmap() and display the result in a Pharo window.
>>>>
>>>> The rest of this week I'm working 12 hour days on a mine site.  I could
>>>> try it out once I'm home, but in the meantime is anyone else keen to try
>>>> it?
>>>>
>>>> cheers -ben
>>>>
>>>
>>>
>>
>
>
> --
> Pablo Tesone.
> teso...@gmail.com
>

Reply via email to