
-- see http://technology.amis.nl/blog/8650/as_pdf-generating-a-pdf-document-with-some-plsql

begin
  pdf_builder_pkg.init;
  pdf_builder_pkg.write( 'Minimal usage' );
  pdf_builder_pkg.save_pdf;
end;
/

begin
  pdf_builder_pkg.init;
  pdf_builder_pkg.write( 'Some text with a newline-character included at this "
" place.' );
  pdf_builder_pkg.write( 'Normally text written with pdf_builder_pkg.write() is appended after the previous text. But the text wraps automaticly to a new line.' );
  pdf_builder_pkg.write( 'But you can place your text at any place', -1, 700 );
  pdf_builder_pkg.write( 'you want', 100, 650 );
  pdf_builder_pkg.write( 'You can even align it, left, right, or centered', p_y => 600, p_alignment => 'right' );
  pdf_builder_pkg.save_pdf;
end;
/

begin
  pdf_builder_pkg.init;
  pdf_builder_pkg.write( 'The mini version of AS_PDF is restricted to the 14 standard PDF-fonts and the WINDOWS-1252 encoding.' );
  pdf_builder_pkg.set_font( 'helvetica' );
  pdf_builder_pkg.write( 'helvetica, normal: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, 700 );
  pdf_builder_pkg.set_font( 'helvetica', 'I' );
  pdf_builder_pkg.write( 'helvetica, italic: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'helvetica', 'b' );
  pdf_builder_pkg.write( 'helvetica, bold: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'helvetica', 'BI' );
  pdf_builder_pkg.write( 'helvetica, bold italic: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'times' );
  pdf_builder_pkg.write( 'times, normal: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, 625 );
  pdf_builder_pkg.set_font( 'times', 'I' );
  pdf_builder_pkg.write( 'times, italic: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'times', 'b' );
  pdf_builder_pkg.write( 'times, bold: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'times', 'BI' );
  pdf_builder_pkg.write( 'times, bold italic: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'courier' );
  pdf_builder_pkg.write( 'courier, normal: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, 550 );
  pdf_builder_pkg.set_font( 'courier', 'I' );
  pdf_builder_pkg.write( 'courier, italic: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'courier', 'b' );
  pdf_builder_pkg.write( 'courier, bold: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'courier', 'BI' );
  pdf_builder_pkg.write( 'courier, bold italic: ' || 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );

  pdf_builder_pkg.set_font( 'courier' );
  pdf_builder_pkg.write( 'symbol:', -1, 475 );
  pdf_builder_pkg.set_font( 'symbol' );
  pdf_builder_pkg.write( 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );
  pdf_builder_pkg.set_font( 'courier' );
  pdf_builder_pkg.write( 'zapfdingbats:', -1, -1 );
  pdf_builder_pkg.set_font( 'zapfdingbats' );
  pdf_builder_pkg.write( 'The quick brown fox jumps over the lazy dog. 1234567890', -1, -1 );

  pdf_builder_pkg.set_font( 'times', 'N', 20 );
  pdf_builder_pkg.write( 'times, normal with fontsize 20pt', -1, 400 );
  pdf_builder_pkg.set_font( 'times', 'N', 6 );
  pdf_builder_pkg.write( 'times, normal with fontsize 5pt', -1, -1 );
  pdf_builder_pkg.save_pdf;
end;
/

begin
  pdf_builder_pkg.init;
  for i in 1 .. 10
  loop
    pdf_builder_pkg.horizontal_line( 30, 700 - i * 15, 100, i );
  end loop;
  for i in 1 .. 10
  loop
    pdf_builder_pkg.vertical_line( 150 + i * 15, 700, 100, i );
  end loop;
  for i in 0 .. 255
  loop
    pdf_builder_pkg.horizontal_line( 330, 700 - i, 100, p_line_color =>  to_char( i, 'fm0x' ) || to_char( i, 'fm0x' ) || to_char( i, 'fm0x' ) );
  end loop;
  pdf_builder_pkg.save_pdf;
end;
/

declare
  t_logo varchar2(32767) :=
'/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkS' ||
'Ew8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJ' ||
'CQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy' ||
'MjIyMjIyMjIyMjIyMjL/wAARCABqAJYDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEA' ||
'AAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh' ||
'MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6' ||
'Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZ' ||
'mqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx' ||
'8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREA' ||
'AgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV' ||
'YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp' ||
'anN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPE' ||
'xcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3' ||
'+iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoorifiX4pk' ||
'8PaCILR9t9eExxsOqL/E315AHuaUmkrs1oUZVqipw3ZU8X/FCz0KeSw02Jb2+Thy' ||
'WxHGfQkdT7D8686ufih4suGJW/jgXssUC8fnk1ydvbz3lzHb28bzTyttRF5LMa7H' ||
'Uvh+3hvRI9T1+7kUPIsf2ezUMykgnlmIHbtXI5znqtj66ng8DhFGFRJyffVv5Fnw' ||
'r8QfEEvinTodR1N5rSaYRyIyIAd3A5A9SK7X4qeINV0Gz019LvGtmlkcOVVTkADH' ||
'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';
begin
  pdf_builder_pkg.init;
  pdf_builder_pkg.put_image( to_blob( utl_encode.base64_decode( utl_raw.cast_to_raw( t_logo ) ) )
                       , - ( pdf_builder_pkg.get_settings().page_width
                           + pdf_builder_pkg.get_settings().margin_left
                           - pdf_builder_pkg.get_settings().margin_right
                           ) / 2
                       , pdf_builder_pkg.get_settings().page_height - 260
                       );
  pdf_builder_pkg.write( 'jpg and png images are supported.' );
  pdf_builder_pkg.write( 'And because PDF 1.3 (thats the format I use) doesn''t support alpha channels, neither does pdf_builder_pkg.', -1, -1 );
  pdf_builder_pkg.save_pdf;
end;
/


declare
  t_rc sys_refcursor;
  procedure refcursor2pdf( p_rc sys_refcursor )
  is
    t_xml xmltype;
    type tp_node_rec is record
      ( name varchar2(1000)
      , str_size number
      );
    type tp_nodes is table of tp_node_rec index by pls_integer;
    nodes tp_nodes;
    t_x number;
    t_y number;
    t_set number;
    t_padding number := 5.4;
    t_total_width number;
 begin
    pdf_builder_pkg.init;
    t_set := pdf_builder_pkg.get_settings().page_width
           + pdf_builder_pkg.get_settings().margin_left
           - pdf_builder_pkg.get_settings().margin_right;
    t_xml := xmltype( p_rc );
--
    select nds.name
         , greatest( max( pdf_builder_pkg.string_width( nds.val ) )
                   , pdf_builder_pkg.string_width( nds.name )
                   ) val
    bulk collect into nodes
    from ( select xmltype( xmltype.getclobval( nds.column_value ) ).getrootelement() name
                , xmltype.extract( nds.column_value, '* /text()' ).getclobval() val
           from table( xmlsequence( t_xml.extract( '/ROWSET/ROW/node()' ) ) ) nds
         ) nds
       , ( select rownum i
                , xmltype( xmltype.getclobval( frw.column_value ) ).getrootelement() name
           from table( xmlsequence( t_xml.extract( '/ROWSET/ROW[1]/node()' ) ) ) frw
         ) frw
    where frw.name = nds.name
    group by nds.name, frw.i
    order by frw.i;
--
    t_total_width := 0;
    for i in nodes.first .. nodes.last
    loop
      nodes( i ).str_size := nodes( i ).str_size + 2 * t_padding;
      t_total_width := t_total_width + nodes( i ).str_size;
    end loop;
--
    t_y := -12345;
    for r_rows in ( select rws.column_value cv
                    from table( xmlsequence( t_xml.extract( '/ROWSET/ROW' ) ) ) rws
                  )
    loop
      if t_y <= pdf_builder_pkg.get_settings().margin_bottom + t_padding / 2
      then
        if t_y != -12345
        then
          pdf_builder_pkg.new_page;
        end if;
        t_y := pdf_builder_pkg.get_settings().page_height
             - pdf_builder_pkg.get_settings().margin_top;
        t_x := ( t_set - t_total_width ) / 2;
        for i in nodes.first .. nodes.last
        loop
          pdf_builder_pkg.rect( t_x, t_y - t_padding / 2, nodes( i ).str_size, pdf_builder_pkg.get_settings().current_fontsizePt + t_padding, p_fill_color => '#9bafde' );
          pdf_builder_pkg.write( nodes( i ).name, t_x + t_padding, t_y );
          t_x := t_x + nodes( i ).str_size;
        end loop;
        t_y := t_y - pdf_builder_pkg.get_settings().current_fontsizePt - t_padding;
      end if;
      t_x := ( t_set - t_total_width ) / 2;
      for i in nodes.first .. nodes.last
      loop
        pdf_builder_pkg.rect( t_x, t_y - t_padding / 2, nodes( i ).str_size, pdf_builder_pkg.get_settings().current_fontsizePt + t_padding );
        if r_rows.cv.extract( '/ROW/' || nodes( i ).name ) is not null
        then
          pdf_builder_pkg.write( r_rows.cv.extract( '/ROW/' || nodes( i ).name || '/text()' ).getclobval(), t_x + t_padding, t_y );
        end if;
        t_x := t_x + nodes( i ).str_size;
      end loop;
      t_y := t_y - pdf_builder_pkg.get_settings().current_fontsizePt - t_padding;
    end loop;
    pdf_builder_pkg.save_pdf;
  end;
begin
  open t_rc for select 'x123' x, 'wat' w, 1 xxxx from dual
    union all select 'abc', 'x', 3 from dual
    union all select 'abc', '', 3 from dual
    union all select 'abcef', null, 5 from dual
    union all select 'HXFG', 'HGJ', 8 from dual
    union all select 'abc', 'x', rownum from dual connect by rownum < 50;
  refcursor2pdf( t_rc );
end;
/

