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:


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 <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 thead–tdname, lv_docid TYPE stxbitmaps–docid, lv_res TYPE stxbitmaps–resolution.
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’ sy–uzeit 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 sy–subrc <> 0.
* report message CALL METHOD wd_this->go_msg_mngr->report_t100_message EXPORTING msgid = sy–msgid msgno = sy–msgno msgty = sy–msgty p1 = sy–msgv1 p2 = sy–msgv2 p3 = sy–msgv3 p4 = sy–msgv4.
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 stxbitmaps–widthtw, l_height_tw TYPE stxbitmaps–heighttw, l_width_pix TYPE stxbitmaps–widthpix, l_height_pix TYPE stxbitmaps–heightpix. 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_bitmap–l = lv_string(64). ELSE. l_bitmap–l = 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 sy–subrc <> 0. PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object p_name p_id p_btype. MESSAGE ID sy–msgid TYPE sy–msgty NUMBER sy–msgno WITH sy–msgv1 sy–msgv2 sy–msgv3 sy–msgv4 RAISING conversion_failed. ENDIF.
* Save bitmap in BDS CREATE object l_bds_object.
wa_bds_components–doc_count = ‘1’. wa_bds_components–comp_count = ‘1’. wa_bds_components–mimetype = c_bds_mimetype. wa_bds_components–comp_size = l_bds_bytecount. APPEND wa_bds_components TO l_bds_components.
IF p_docid IS INITIAL. ” graphic is new
wa_bds_signature–doc_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 sy–subrc <> 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 sy–subrc = 0. p_docid = wa_bds_signature–doc_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 sy–subrc = 0. SELECT SINGLE object_key FROM (l_tab) INTO l_object_key WHERE loio_id = wa_stxbitmaps–docid+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 sy–subrc = 1. ” inconsistency STXBITMAPS – BDS; repeat check in wa_bds_signature–doc_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 sy–subrc <> 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 sy–subrc = 0. p_docid = wa_bds_signature–doc_id. ELSE. PERFORM dequeue_graphic(SAPLSTXBITMAPS) USING p_object p_name p_id p_btype. MESSAGE e285 WITH p_name ‘BDS’. ENDIF.
ELSEIF sy–subrc = 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_stxbitmaps–tdname = p_name. wa_stxbitmaps–tdobject = p_object. wa_stxbitmaps–tdid = p_id. wa_stxbitmaps–tdbtype = p_btype. wa_stxbitmaps–docid = p_docid. wa_stxbitmaps–widthpix = l_width_pix. wa_stxbitmaps–heightpix = l_height_pix. wa_stxbitmaps–widthtw = l_width_tw. wa_stxbitmaps–heighttw = l_height_tw. wa_stxbitmaps–resolution = p_resolution. wa_stxbitmaps–resident = p_resident. wa_stxbitmaps–autoheight = p_autoheight. wa_stxbitmaps–bmcomp = p_bmcomp. INSERT INTO stxbitmaps values wa_stxbitmaps. IF sy–subrc <> 0. UPDATE stxbitmaps FROM wa_stxbitmaps. IF sy–subrc <> 0. MESSAGE e285 WITH p_name ‘STXBITMAPS’. ENDIF. ENDIF.
* Set description in BDS attributes wa_bds_properties–prop_name = ‘DESCRIPTION’. wa_bds_properties–prop_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. |
This is giving error:
Field "M_HTML_ISLAND" is unknown. It is neither in one of the specified
Any thoughts... thanks,
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
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
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