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

Signature Pad vendor website : http://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:

Solution2.jpg

COUPDEGRACE.jpg

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

MAIN VIEW.jpg

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

HTML_SCRIPT.jpg

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

HTMLEVENT2.jpg

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 <object> 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.

*    <div ID=’myHTMLIsland’>
*    <table border=’1′ cellpadding=’0′ width=’390′>
*    <tr>
*    <td height=’145′ width=’385′>
*    <object classid=”clsid:69A40DA3-4D42-11D0-86B0-0000C025864A” height=”140″ width=”380″ id=”SigPlus1″ name=”SigPlus1″>
*    <param name=”_Version” value=”131095″></param>
*    <param name=”_ExtentX” value=”4842″></param>
*    <param name=”_ExtentY” value=”1323″></param>
*    <param name=”_StockProps” value=”0″></param>
*    </object><td></tr><table></div>

     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
   EXCEPTIONS
     format_not_supported     = 1
     no_bmp_file              = 2
     bmperr_invalid_format    = 3
     bmperr_no_colortable     = 4
     bmperr_unsup_compression = 5
     bmperr_corrupt_rle_data  = 6
     OTHERS                   = 7.
   IF sysubrc <> 0.
     PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
           p_name
           p_id
           p_btype.
     MESSAGE ID symsgid TYPE symsgty NUMBER symsgno
     WITH symsgv1 symsgv2 symsgv3 symsgv4
     RAISING conversion_failed.
   ENDIF.

* Save bitmap in BDS
   CREATE object l_bds_object.

   wa_bds_componentsdoc_count  = ‘1’.
   wa_bds_componentscomp_count = ‘1’.
   wa_bds_componentsmimetype   = c_bds_mimetype.
   wa_bds_componentscomp_size  = l_bds_bytecount.
   APPEND wa_bds_components TO l_bds_components.

   IF p_docid IS INITIAL.          ” graphic is new

     wa_bds_signaturedoc_count = ‘1’.
     APPEND wa_bds_signature TO l_bds_signature.

     CALL METHOD l_bds_object->create_with_table
     EXPORTING
       classname  = c_bds_classname
       classtype  = c_bds_classtype
       components = l_bds_components
       content    = l_bds_content
     CHANGING
       signature  = l_bds_signature
       object_key = l_object_key
     EXCEPTIONS
       OTHERS     = 1.
     IF sysubrc <> 0.
       PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
             p_name
             p_id
             p_btype.
       MESSAGE e285 WITH p_name  ‘BDS’.
     ENDIF.
     READ TABLE l_bds_signature INDEX 1 INTO wa_bds_signature
     TRANSPORTING doc_id.
     IF sysubrc = 0.
       p_docid = wa_bds_signaturedoc_id.
     ELSE.
       PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
             p_name
             p_id
             p_btype.
       MESSAGE e285 WITH p_name ‘BDS’.
     ENDIF.

   ELSE.                ” graphic already exists
********* read object_key for faster access *****
     CLEAR l_object_key.
     SELECT SINGLE * FROM stxbitmaps INTO wa_stxbitmaps
     WHERE tdobject = p_object
     AND tdid     = p_id
     AND tdname   = p_name
     AND tdbtype  = p_btype.
     SELECT SINGLE tabname FROM bds_locl INTO l_tab
     WHERE classname = c_bds_classname
     AND classtype = c_bds_classtype.
     IF sysubrc = 0.
       SELECT SINGLE object_key FROM (l_tab) INTO l_object_key
       WHERE loio_id = wa_stxbitmapsdocid+10(32)
       AND classname = c_bds_classname
       AND classtype = c_bds_classtype.
     ENDIF.
******** read object_key end ********************

     CALL METHOD l_bds_object->update_with_table
     EXPORTING
       classname  = c_bds_classname
       classtype  = c_bds_classtype
       object_key = l_object_key
       doc_id     = p_docid
       doc_ver_no = ‘1’
       doc_var_id = ‘1’
     CHANGING
       components = l_bds_components
       content    = l_bds_content
     EXCEPTIONS
       nothing_found = 1
       OTHERS        = 2.
     IF sysubrc = 1.   ” inconsistency STXBITMAPS – BDS; repeat check in
       wa_bds_signaturedoc_count = ‘1’.
       APPEND wa_bds_signature TO l_bds_signature.

       CALL METHOD l_bds_object->create_with_table
       EXPORTING
         classname  = c_bds_classname
         classtype  = c_bds_classtype
         components = l_bds_components
         content    = l_bds_content
       CHANGING
         signature  = l_bds_signature
         object_key = l_object_key
       EXCEPTIONS
         OTHERS     = 1.
       IF sysubrc <> 0.
         PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
               p_name
               p_id
               p_btype.
         MESSAGE e285 WITH p_name ‘BDS’.
       ENDIF.
       READ TABLE l_bds_signature INDEX 1 INTO wa_bds_signature
       TRANSPORTING doc_id.
       IF sysubrc = 0.
         p_docid = wa_bds_signaturedoc_id.
       ELSE.
         PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
               p_name
               p_id
               p_btype.
         MESSAGE e285 WITH p_name ‘BDS’.
       ENDIF.

   ELSEIF sysubrc = 2.
       PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
             p_name
             p_id
             p_btype.
       MESSAGE e285 WITH p_name ‘BDS’.
     ENDIF.

   ENDIF.

* Save bitmap header in STXBITPMAPS
   wa_stxbitmapstdname     = p_name.
   wa_stxbitmapstdobject   = p_object.
   wa_stxbitmapstdid       = p_id.
   wa_stxbitmapstdbtype    = p_btype.
   wa_stxbitmapsdocid      = p_docid.
   wa_stxbitmapswidthpix   = l_width_pix.
   wa_stxbitmapsheightpix  = l_height_pix.
   wa_stxbitmapswidthtw    = l_width_tw.
   wa_stxbitmapsheighttw   = l_height_tw.
   wa_stxbitmapsresolution = p_resolution.
   wa_stxbitmapsresident   = p_resident.
   wa_stxbitmapsautoheight = p_autoheight.
   wa_stxbitmapsbmcomp     = p_bmcomp.
   INSERT INTO stxbitmaps values wa_stxbitmaps.
   IF sysubrc <> 0.
     UPDATE stxbitmaps FROM wa_stxbitmaps.
     IF sysubrc <> 0.
       MESSAGE e285 WITH p_name ‘STXBITMAPS’.
     ENDIF.
   ENDIF.

* Set description in BDS attributes
   wa_bds_propertiesprop_name  = ‘DESCRIPTION’.
   wa_bds_propertiesprop_value = p_title.
   APPEND wa_bds_properties TO l_bds_properties.

   CALL METHOD l_bds_object->change_properties
   EXPORTING
     classname  = c_bds_classname
     classtype  = c_bds_classtype
     object_key = l_object_key
     doc_id     = p_docid
     doc_ver_no = ‘1’
     doc_var_id = ‘1’
   CHANGING
     properties = l_bds_properties
   EXCEPTIONS
     OTHERS         = 1.

   PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object
         p_name
         p_id
         p_btype.
 
ENDFUNCTION.

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Janagar Sundaramoorthy

    Hi Subramani,

    i am working on a similar kind of requirement , but our requirement is not to save bmp file in se78 .

    One query i have is by default what is the format ?

    is it ASCII /BINARY ?

    Because i am storing the xstring content in table and i am trying to retrieve that. but i am getting formatting error.

    Thanks for your time

    (0) 
  2. Janagar Sundaramoorthy

    Hi Subramani

    It was working fine for us. Suddenly the communication between webdynpro and signature pad is not working. Let me know what would be the issue. Can you able to help me.

    Regards

    S.Janagar

    (0) 
    1. Janagar Sundaramoorthy

      The issue is solved, recently SAP has released some notes for Unified rendering issues for Java scripts events triggered in WDA through HTML islands , implemented it and it fixed the issue.

      Regards

      S.Janagar

      (0) 

Leave a Reply