This document shows how to integrate a signature pad device with  WebDynpro ABAP HTML Islands (731 SP5).

Signature Pad vendor website : https://www.topazsystems.com/

Prerequisites:

Install the browser plugin for the signature pad device as per instructions on the web site. I got it for my device here.

It comes with a DemoOCX application which can help you get a sample ‘.SIG’ file to test your Web Dynpro App.

Read on HTML Islands at this blog post.

The solution:


We will build a page with a rectangular window where the signature would appear as the user signs on the Signature Pad tablet using the tablet pen.

This rectangular area is where the Device’s browser plugin will be loaded.

Hitting the ‘Sign’ button will trigger Javascript code which will ready the device to accept the signature.

The ‘Done’ button will again trigger Javascript code  which will read the signature into a bitmap hexadecimal string and pass it on to the back end server via the HTMLEVENT call back functionality. At the back end, the hex image data would be saved as a BDS document (SE78). It will also make the signature available for download on the frontend PC.

The ‘Import’ button was added for testing purposes and would typically not form part of the production solution. It imports a sample signature file into the signature window.

Development:

Step 1

Set up the view in the WDA component as shown

Associate an HTMLSCRIPT element with the Javascript mySign.js we will shortly build and load to the MIME repository as follows

The HTMLEVENT node will be called by Javascript with the bitmap data in hexadecimal string format.

Following is the setup of buttons:

Button ID Action
BUT_SIGN SIGN
BUT_IMP IMPORT
BUT_DONE DONE

Step 2

Add code in WDDOMODIFYVIEW to add custom HTML code for the rectangular box and to load the browser plugin.

Here we will programatically update the staticHtml property of the HTMLISLAND node to add the rectangular box.

The html code was obtained from the vendor website : demo link.

The tag loads the browser plugin . Sigplus1  will become the object name with which we will control the device in our Javascript code. We will see this in the next step.

Note the call to Javascript function ‘setCallback()’. This merely passes an object  to Javascript which can be used later to call the HTMLEVENT ‘Done’.

WDDOMODIFYVIEW
METHOD wddomodifyview .
     DATA lv_html TYPE string.
     IF first_time = abap_true.

*   


*   
*   
*   

*   
*   
*   
*   
*   
*   

     DATA html_writer TYPE REF TO if_wd_html_writer.
     html_writer = cl_wd_html_writer=>new_writer( ).
     html_writer->start_element( ‘div’ ).
     html_writer->add_attribute( name = ‘id’ VALUE  = ‘myHTMLIsland’).
     html_writer->start_element( ‘table’ ).
     html_writer->add_attribute( name = ‘border’ VALUE  = ‘1’).
     html_writer->add_attribute( name = ‘cellpadding’ VALUE  = ‘0’).
     html_writer->add_attribute( name = ‘width’ VALUE  = ‘390’).
     html_writer->start_element( ‘tr’ ).
     html_writer->start_element( ‘td’ ).
     html_writer->add_attribute( name = ‘height’ VALUE  = ‘145’).
     html_writer->add_attribute( name = ‘width’ VALUE  = ‘385’).

*   Load the browser plugin.
     html_writer->start_element( ‘object’ ).
     html_writer->add_attribute( name = ‘classid’ VALUE  = ‘clsid:69A40DA3-4D42-11D0-86B0-0000C025864A’).
     html_writer->add_attribute( name = ‘height’ VALUE  = ‘140’).
     html_writer->add_attribute( name = ‘width’ VALUE  = ‘380’).
     html_writer->add_attribute( name = ‘id’ VALUE  = SigPlus1).
     html_writer->add_attribute( name = ‘name’ VALUE  = SigPlus1).

     html_writer->start_element( ‘param’ ).
     html_writer->add_attribute( name = ‘name’ VALUE  = ‘_Version’).
     html_writer->add_attribute( name = ‘value’ VALUE  = ‘131095’).
     html_writer->end_element( ‘param’ ).

     html_writer->start_element( ‘param’ ).
     html_writer->add_attribute( name = ‘name’ VALUE  = ‘_ExtentX’).
     html_writer->add_attribute( name = ‘value’ VALUE  = ‘4842’).
     html_writer->end_element( ‘param’ ).

     html_writer->start_element( ‘param’ ).
     html_writer->add_attribute( name = ‘name’ VALUE  = ‘_ExtentY’).
     html_writer->add_attribute( name = ‘value’ VALUE  = ‘1323’).
     html_writer->end_element( ‘param’ ).

     html_writer->start_element( ‘param’ ).
     html_writer->add_attribute( name = ‘name’ VALUE  = ‘_StockProps’).
     html_writer->add_attribute( name = ‘value’ VALUE  = ‘0’).
     html_writer->end_element( ‘param’ ).

     html_writer->end_element( ‘object’ ).
     html_writer->end_element( ‘td’ ).
     html_writer->end_element( ‘tr’ ).
     html_writer->end_element( ‘table’ ).

     html_writer->end_element( ‘div’ ).

     lv_html = html_writer->get_html( ).
     wd_this->m_html_island ?= view->get_element( ‘HTML_ISLAND’ ).
     wd_this->m_html_island->set_static_html( VALUE = lv_html ).

*   Set the callback variable to enable Javascript to call DONECB.
     DATA l_call TYPE REF TO if_wd_html_script_call.
     l_call = cl_wd_html_script_call=>new_call( ). ” Create a new script call
     l_call->function( setCallback ).
     l_call->add_callback_api( ).
     wd_this->m_html_island->add_script_call( l_call ).
     ENDIF.
     ENDMETHOD.

Step 3

Build a Javascript to control the device as follows

Documentation on various properties and methods from the browser plugin can be found here.

mySign.js

var callbackhndl;

function setCallback(callback) {

   callbackhndl = callback;

}

function onSign() {

     SigPlus1.ClearTablet();

    SigPlus1.TabletState = 1;

}

function onImport() {

    var Filename = ‘C:\sign\Sign.sig’;

    SigPlus1.ImportSigFile(Filename);

}

function onDone(){

          if (SigPlus1.NumberOfTabletPoints === 0) {

            alert(“Please sign to continue”);

        } else {

            SigPlus1.TabletState = 0;

            SigPlus1.EncryptionMode = 0;

            SigPlus1.SigCompressionMode = 0;

            var sigString = SigPlus1.SigString;

            SigPlus1.ImageFileFormat = 0;

            SigPlus1.ImageXSize = 380;

            SigPlus1.ImageYSize = 140;

            SigPlus1.ImagePenWidth = 12;

            SigPlus1.JustifyMode = 5;

            SigPlus1.BitMapBufferWrite();

            var bmpByte = SigPlus1.BitMapBufferByte(0);

            var bmpTemp;

            var bmpString = bmpByte.toString(16);

           var hexzero = ‘0’;

            Size = SigPlus1.BitMapBufferSize();

            for (var i = 1; i < Size; i++) {

                bmpByte = SigPlus1.BitMapBufferByte(i);

                bmpTemp = bmpByte.toString(16);

                if ( bmpTemp.length === 1) {

                     bmpTemp = hexzero.concat( bmpTemp);

                }

                bmpString = bmpString.concat(bmpTemp.toUpperCase());

            }

            SigPlus1.BitMapBufferClose();

            SigPlus1.TabletState = 0;

            callbackhndl .fireEvent(‘Done’, bmpString);

        }

}

Step 4

The penultimate step is to make calls to Javascript when the buttons are clicked.

ONACTIONSIGN
METHOD ONACTIONSIGN .
* Call Javascript function onSign()
   DATA l_call TYPE REF TO if_wd_html_script_call.
   l_call = cl_wd_html_script_call=>new_call( ). ” Create a new script call
   l_call->function( onSign ).
   wd_this->m_html_island->add_script_call( l_call ).
   ENDMETHOD.
ONACTIONIMPORT
method ONACTIONIMPORT .
* Call Javascript function onImport()
   DATA l_call TYPE REF TO if_wd_html_script_call.
   l_call = cl_wd_html_script_call=>new_call( ). ” Create a new script call
   l_call->function( onImport ).
   wd_this->m_html_island->add_script_call( l_call ).
endmethod.
ONACTIONDONE
method ONACTIONDONE .
* Call Javascript function onDone()
* onDone() will then callback WDA HTML_EVENT ONDONECB
   DATA l_call TYPE REF TO if_wd_html_script_call.
   l_call = cl_wd_html_script_call=>new_call( ). ” Create a new script call
   l_call->function( onDone ).
   wd_this->m_html_island->add_script_call( l_call ).
endmethod.

Step 5

Now when the Done button is clicked, the Javascript code

    callbackhndl .fireEvent(‘Done’, bmpString);

will trigger the HTMLEVENT node with name ‘Done’. This will in turn trigger the ONACTIONDONECB method at the back end.

The parameter bmpString is caught in the DATA parameter of method ONACTIONDONECB.

The final step is to add code to ONACTIONDONECB to convert this hexadecimal string to a bmp image on the BDS server.

ONACTIONDONECB

METHOD onactiondonecb .
*——————————————————————–*
*   Method Interface
*   WDEVENT  CL_WD_CUSTOM_EVENT
*   CONTEXT_ELEMENT  IF_WD_CONTEXT_ELEMENT
*   DATA  STRING
*   ID  STRING
*——————————————————————–*
     DATA lo_el_context TYPE REF TO if_wd_context_element.
     DATA ls_context TYPE wd_this->element_context.
     DATA lv_mybmp TYPE xstring.
     DATA : lv_name TYPE theadtdname,
           lv_docid TYPE  stxbitmapsdocid,
           lv_res TYPE  stxbitmapsresolution.

   IF DATA IS NOT INITIAL.

* get element via lead selection
     lo_el_context = wd_context->get_element( ).
 

    lv_mybmp = DATA.

* set single attribute
     lo_el_context->set_attribute(
     name ‘MYBMP’
     VALUE = lv_mybmp ).

     CONCATENATE ‘ZHEX-MACRO-SIGN’ syuzeit INTO lv_name.
     CALL FUNCTION ‘ZSAVE_BMP’
     EXPORTING
       iv_string         = lv_mybmp
       p_name            = lv_name
     CHANGING
       p_docid           = lv_docid
       p_resolution      = lv_res
     EXCEPTIONS
       error_occurred    = 1
       conversion_failed = 2
       OTHERS            = 3.
     IF sysubrc <> 0.

* report message
       CALL METHOD wd_this->go_msg_mngr->report_t100_message
       EXPORTING
         msgid = symsgid
         msgno = symsgno
         msgty = symsgty
         p1    = symsgv1
         p2    = symsgv2
         p3    = symsgv3
         p4    = symsgv4.

     ELSE.

*     report message
       CALL METHOD wd_this->go_msg_mngr->report_success
         EXPORTING
           message_text    = ‘Signature captured’
           .

     ENDIF.

     DATA filename1 TYPE string VALUE ‘sign.bmp’.

*   This code will ask user to download signature as bmp. See WDR_TEST_EVENTS for button.
     cl_wd_runtime_services=>attach_file_to_response(
     i_filename  = filename1
     i_content   = lv_mybmp
     i_mime_type = ‘image/bmp’
     i_in_new_window = abap_false
     i_inplace       = abap_false ).

   ENDIF.

ENDMETHOD.

Here is the code for FM ZSAVE_BMP which converts the hexadecimal into SE78 image.

Header 1
FUNCTION zsave_bmp.
*”———————————————————————-
*”*”Local Interface:
*”  IMPORTING
*”     REFERENCE(IV_STRING) TYPE  XSTRING OPTIONAL
*”     REFERENCE(P_FILENAME) TYPE  RLGRAP-FILENAME OPTIONAL
*”     REFERENCE(P_NAME) TYPE  STXBITMAPS-TDNAME OPTIONAL
*”     REFERENCE(P_OBJECT) TYPE  STXBITMAPS-TDOBJECT DEFAULT ‘GRAPHICS’
*”     REFERENCE(P_ID) TYPE  STXBITMAPS-TDID DEFAULT ‘BMAP’
*”     REFERENCE(P_BTYPE) TYPE  STXBITMAPS-TDBTYPE DEFAULT ‘BCOL’
*”     REFERENCE(P_FORMAT) TYPE  C DEFAULT ‘BMP’
*”     REFERENCE(P_TITLE) TYPE  BAPISIGNAT-PROP_VALUE DEFAULT
*”       ‘SIGNATURE’
*”     REFERENCE(P_RESIDENT) TYPE  STXBITMAPS-RESIDENT OPTIONAL
*”     REFERENCE(P_AUTOHEIGHT) TYPE  STXBITMAPS-AUTOHEIGHT DEFAULT ‘X’
*”     REFERENCE(P_BMCOMP) TYPE  STXBITMAPS-BMCOMP DEFAULT ‘X’
*”  CHANGING
*”     REFERENCE(P_DOCID) TYPE  STXBITMAPS-DOCID
*”     REFERENCE(P_RESOLUTION) TYPE  STXBITMAPS-RESOLUTION
*”  EXCEPTIONS
*”      ERROR_OCCURRED
*”      CONVERSION_FAILED
*”———————————————————————-

   DATA: l_object_key TYPE sbdst_object_key.
   DATA: l_tab        TYPE ddobjname.
   DATA: BEGIN OF l_bitmap OCCURS 0,
     l(64) TYPE X,
   END OF l_bitmap.
   DATA: l_filename        TYPE string,
         l_bytecount       TYPE I,
         l_bds_bytecount   TYPE I,
         lv_siz            TYPE I,
         lv_string         TYPE xstring.
   DATA: l_color(1)        TYPE C,
         l_width_tw        TYPE stxbitmapswidthtw,
         l_height_tw       TYPE stxbitmapsheighttw,
         l_width_pix       TYPE stxbitmapswidthpix,
         l_height_pix      TYPE stxbitmapsheightpix.
   DATA: l_bds_object      TYPE REF TO cl_bds_document_set,
         l_bds_content     TYPE sbdst_content,
         l_bds_components  TYPE sbdst_components,
         wa_bds_components TYPE LINE OF sbdst_components,
         l_bds_signature   TYPE sbdst_signature,
         wa_bds_signature  TYPE LINE OF sbdst_signature,
         l_bds_properties  TYPE sbdst_properties,
         wa_bds_properties TYPE LINE OF sbdst_properties.
   DATA  wa_stxbitmaps TYPE stxbitmaps.

* Enqueue
   PERFORM enqueue_graphic(SAPLSTXBITMAPS)
   USING p_object
         p_name
         p_id
         p_btype.

   lv_string = iv_string.
   lv_siz = XSTRLEN( lv_string ).
   WHILE lv_siz > 0.
     IF lv_siz > 64.
       l_bitmapl = lv_string(64).
     ELSE.
       l_bitmapl = lv_string.
     ENDIF.
     APPEND l_bitmap.
     CLEAR l_bitmap.
     SHIFT lv_string BY 64 PLACES LEFT IN BYTE MODE.
     lv_siz = XSTRLEN( lv_string ).
   ENDWHILE.

   IF p_btype = c_bmon.
     l_color = abap_false.
   ELSE.
     l_color = abap_true.
   ENDIF.

* Bitmap conversion
   CALL FUNCTION ‘SAPSCRIPT_CONVERT_BITMAP_BDS’
   EXPORTING
     COLOR                    = l_color
     FORMAT                   = p_format
     resident                 = p_resident
     bitmap_bytecount         = l_bytecount
     compress_bitmap          = p_bmcomp
   IMPORTING
     width_tw                 = l_width_tw
     height_tw                = l_height_tw
     width_pix                = l_width_pix
     height_pix               = l_height_pix
     dpi                      = p_resolution
     bds_bytecount            = l_bds_bytecount
   TABLES
     bitmap_file              = l_bitmap
     bitmap_file_bds          = l_bds_content