Search code examples
htmlbindingpascalwkhtmltopdfwkhtmltoimage

unable to save png with the c-bindings of wkhtmltoimage (Pascal)


i need to convert websites to transparent images in my actual pascal-project. Therefore i've translated the c-bindings of wkhtmltoimage to pascal (FPC / Lazarus IDE). Here is the translation:

// Copyright 2017 Thorsten Zahn
//   translation of wkhtmltox-0.12.4/include/wkhtmltox/image.h - 
//   Copyright 2010, 2011 wkhtmltopdf authors
//
// pas_libwkhtmltoimage is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pas_libwkhtmltoimage is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

unit pas_libwkhtmltoimage;
interface

uses
  {$IFDEF UNIX}dynlibs,{$ENDIF}
  SysUtils, Dialogs;

procedure init_wkhtmltoimage();
procedure init_wkhtmltoimage(install_file: string);

type
  PInteger = ^Integer;

  wkhtmltoimage_global_settings = record end;
  Pwkhtmltoimage_global_settings = ^wkhtmltoimage_global_settings;

  wkhtmltoimage_converter = record end;
  Pwkhtmltoimage_converter = ^wkhtmltoimage_converter;

  wkhtmltoimage_str_callback  = procedure (converter:Pwkhtmltoimage_converter; const str:PChar  ) cdecl;
  wkhtmltoimage_int_callback  = procedure (converter:Pwkhtmltoimage_converter; const val:Integer) cdecl;
  wkhtmltoimage_void_callback = procedure (converter:Pwkhtmltoimage_converter                   ) cdecl;

var
  wkhtmltoimage_init                         : function (use_graphics: Integer)                                                           : Integer                       ; cdecl;
  wkhtmltoimage_deinit                       : function ()                                                                                : Integer                       ; cdecl;
  wkhtmltoimage_extended_qt                  : function ()                                                                                : Integer                       ; cdecl;
  wkhtmltoimage_version                      : function ()                                                                                : PChar                         ; cdecl;
  wkhtmltoimage_create_global_settings       : function ()                                                                                : Pwkhtmltoimage_global_settings; cdecl;
  wkhtmltoimage_set_global_setting           : function (settings: Pwkhtmltoimage_global_settings; name: PChar; value: PChar)             : Integer                       ; cdecl;
  wkhtmltoimage_get_global_setting           : function (settings: Pwkhtmltoimage_global_settings; name: PChar; value: PChar; vs: Integer): Integer                       ; cdecl;
  wkhtmltoimage_create_converter             : function (settings: Pwkhtmltoimage_global_settings; data: PChar)                           : Pwkhtmltoimage_converter      ; cdecl;
  wkhtmltoimage_destroy_converter            : procedure(converter: Pwkhtmltoimage_converter)                                                                             ; cdecl;
  wkhtmltoimage_set_warning_callback         : procedure(converter: Pwkhtmltoimage_converter; cb: wkhtmltoimage_str_callback)                                             ; cdecl;
  wkhtmltoimage_set_error_callback           : procedure(converter: Pwkhtmltoimage_converter; cb: wkhtmltoimage_str_callback)                                             ; cdecl;
  wkhtmltoimage_set_phase_changed_callback   : procedure(converter: Pwkhtmltoimage_converter; cb: wkhtmltoimage_void_callback)                                            ; cdecl;
  wkhtmltoimage_set_progress_changed_callback: procedure(converter: Pwkhtmltoimage_converter; cb: wkhtmltoimage_int_callback)                                             ; cdecl;
  wkhtmltoimage_set_finished_callback        : procedure(converter: Pwkhtmltoimage_converter; cb: wkhtmltoimage_int_callback)                                             ; cdecl;
  wkhtmltoimage_convert                      : function (converter: Pwkhtmltoimage_converter)                                             : Integer                       ; cdecl;
  wkhtmltoimage_current_phase                : function (converter: Pwkhtmltoimage_converter)                                             : Integer                       ; cdecl;
  wkhtmltoimage_phase_count                  : function (converter: Pwkhtmltoimage_converter)                                             : Integer                       ; cdecl;
  wkhtmltoimage_phase_description            : function (converter: Pwkhtmltoimage_converter; phase: Integer)                             : PChar                         ; cdecl;
  wkhtmltoimage_progress_string              : function (converter: Pwkhtmltoimage_converter)                                             : PChar                         ; cdecl;
  wkhtmltoimage_http_error_code              : function (converter: Pwkhtmltoimage_converter)                                             : Integer                       ; cdecl;
  wkhtmltoimage_get_output                   : function (converter: Pwkhtmltoimage_converter; _para2: PPbyte)                             : Integer                       ; cdecl;


implementation

var
  lib_handle : THandle;


procedure handle_error(error: string);
begin
  ShowMessage(error);
end;


function lib_get_proc_addr(var addr: Pointer; const name : PAnsiChar) : Boolean;
begin
  {$IFDEF UNIX}
  addr := GetProcedureAddress(lib_handle, name);
  {$ENDIF}
  {$IFDEF MSWINDOWS}
  addr := GetProcAddress(libvlc_handle, name);
  {$ENDIF}
  result := (addr <> NIL);
  if not result then
  begin
    handle_error('Procedure "' + name + '" not found!');
  end;
end;


procedure init_wkhtmltoimage();
begin
  if (lib_handle <> 0) then exit;

  init_wkhtmltoimage('<path to lib>/libwkhtmltox.so.0.12.4');
end;

procedure init_wkhtmltoimage(install_file: string);
begin
  if (lib_handle <> 0) then exit;

  //load lib
  {$IFDEF SUPPORTS_UNICODE}
  lib_handle := LoadLibrary(PWideChar(install_file));
  {$ELSE}
  lib_handle := LoadLibrary(PAnsiChar(install_file));
  {$ENDIF}

  //error?
  if (lib_handle = 0) then
    begin
      handle_error(
        'Library not found ' + install_file + ', ' +
        {$IFDEF UNIX}
        'GetLastError() = ' + IntToStr(GetLastOSError())
        {$ENDIF}
        {$IFDEF MSWINDOWS}
        'GetLastError() = ' + IntToStr(GetLastError())
        {$ENDIF}
      );
      exit;
    end;

  //get_proc_addr
  if not lib_get_proc_addr(pointer(wkhtmltoimage_init                         ), 'wkhtmltoimage_init'                         ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_deinit                       ), 'wkhtmltoimage_deinit'                       ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_extended_qt                  ), 'wkhtmltoimage_extended_qt'                  ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_version                      ), 'wkhtmltoimage_version'                      ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_create_global_settings       ), 'wkhtmltoimage_create_global_settings'       ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_set_global_setting           ), 'wkhtmltoimage_set_global_setting'           ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_get_global_setting           ), 'wkhtmltoimage_get_global_setting'           ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_create_converter             ), 'wkhtmltoimage_create_converter'             ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_destroy_converter            ), 'wkhtmltoimage_destroy_converter'            ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_set_warning_callback         ), 'wkhtmltoimage_set_warning_callback'         ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_set_error_callback           ), 'wkhtmltoimage_set_error_callback'           ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_set_phase_changed_callback   ), 'wkhtmltoimage_set_phase_changed_callback'   ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_set_progress_changed_callback), 'wkhtmltoimage_set_progress_changed_callback') then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_set_finished_callback        ), 'wkhtmltoimage_set_finished_callback'        ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_convert                      ), 'wkhtmltoimage_convert'                      ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_current_phase                ), 'wkhtmltoimage_current_phase'                ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_phase_count                  ), 'wkhtmltoimage_phase_count'                  ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_phase_description            ), 'wkhtmltoimage_phase_description'            ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_progress_string              ), 'wkhtmltoimage_progress_string'              ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_http_error_code              ), 'wkhtmltoimage_http_error_code'              ) then exit;
  if not lib_get_proc_addr(pointer(wkhtmltoimage_get_output                   ), 'wkhtmltoimage_get_output'                   ) then exit;
end;

end.

I'm using libwkhtmltox.so.0.12.4. First i've tried to create an bmp-image with code like this:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, testlib;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

//(callback procedures removed in this example)

procedure TForm1.Button1Click(Sender: TObject);
var
  gs: Pwkhtmltoimage_global_settings;
  c:  Pwkhtmltoimage_converter;
  data: PByte;
  len: Integer;

  stream: TMemoryStream;
  i: Integer;
begin
  init_wkhtmltoimage();

  wkhtmltoimage_init(Integer(false));

  gs := wkhtmltoimage_create_global_settings();
  wkhtmltoimage_set_global_setting(gs, 'in' , 'http://www.google.com/');
  //wkhtmltoimage_set_global_setting(gs, 'fmt', 'jpeg');
  wkhtmltoimage_set_global_setting(gs, 'fmt', 'bmp');
  //wkhtmltoimage_set_global_setting(gs, 'fmt', 'svg');

  c := wkhtmltoimage_create_converter(gs, nil);

  //(callback procedures removed in this example)
  //wkhtmltoimage_set_progress_changed_callback(c, @progress_changed);
  //wkhtmltoimage_set_phase_changed_callback   (c, @phase_changed);
  //wkhtmltoimage_set_error_callback           (c, @error);
  //wkhtmltoimage_set_warning_callback         (c, @warning);

  if not Boolean(wkhtmltoimage_convert(c)) then
    begin
      ShowMessage('Conversion failed!');
      exit;
    end;

  len := wkhtmltoimage_get_output(c, @data);

  stream := TMemoryStream.Create();
  for i:=0 to len-1 do
      stream.Write((data+i)^, 1);

  stream.Position:=0;
  Image1.Picture.LoadFromStream(stream);
  stream.SaveToFile('/home/thorsten/Test.png');

  stream.Free;

  wkhtmltoimage_destroy_converter(c);
  wkhtmltoimage_deinit();
end;

end.

This works fine. The formats jpeg and svg are also working (for using svg the display in Image1 has to be quoted out). With svg the transparent background option also works (wkhtmltoimage_set_global_setting(gs, 'transparent', 'true');). But if i try png (wkhtmltoimage_set_global_setting(gs, 'fmt', 'png');) i recive the error Could not save image (by callback).

What might be the problem? Does this problem exist in c-code, too?

Thanks

I've tested the console-tool (installed from Ubuntu repositories, version 0.12.2.4-1), too. This tool works. But if i would use this tool i have to save temporary files.


Solution

  • It seams to be an issue of version 0.12.4. With the (old) version 0.12.3 it works fine. The new version 0.13.0 of the library can't be loaded (debian- and ubuntu-version).