本文用于简单介绍在SAP中使用ZPL语言进行打印的开发步骤,由于对ZPL语言并不是很熟悉,所以ZPL相关的部分并不会很深入,主要介绍在SAP端如何动态填充ZPL内容及预览、打印。
ZPL是斑马条码打印机工业型号用的编程语言。利用这些编程语言,编辑好一个打印的指令集,发送给条码打印机,条码打印机就会把ZPL所绘制的标签打印出来。
ZPL语言代码片段:
^XA
^FX Top section with logo, name and address.
^CF0,60
^FO50,50^GB100,100,100^FS
^FO75,75^FR^GB100,100,100^FS
^FO93,93^GB40,40,40^FS
^FO220,50^FDIntershipping, Inc.^FS
^CF0,30
^FO220,115^FD1000 Shipping Lane^FS
^FO220,155^FDShelbyville TN 38102^FS
^FO220,195^FDUnited States (USA)^FS
^FO50,250^GB700,3,3^FS
^FX Second section with recipient address and permit information.
^CFA,30
^FO50,300^FDJohn Doe^FS
^FO50,340^FD100 Main Street^FS
^FO50,380^FDSpringfield TN 39021^FS
^FO50,420^FDUnited States (USA)^FS
^CFA,15
^FO600,300^GB150,150,3^FS
^FO638,340^FDPermit^FS
^FO638,390^FD123456^FS
^FO50,500^GB700,3,3^FS
^FX Third section with bar code.
^BY5,2,270
^FO100,550^BC^FD12345678^FS
^FX Fourth section (the two boxes on the bottom).
^FO50,900^GB700,250,3^FS
^FO400,900^GB3,250,3^FS
^CF0,40
^FO100,960^FDCtr. X34B-1^FS
^FO100,1010^FDREF1 F00B47^FS
^FO100,1060^FDREF2 BL4H8^FS
^CF0,190
^FO470,955^FDCA^FS
^XZ
上面这段ZPL代码所输出的图形如下所示:
下面是ZPL预览的官方网站,通过该网站可以快速的根据ZPL代码,预览实际输出的条码样式
同时该网站也提供了标准的公有的API供外部调用:
其中postman的测试用例有四个,将测试的json文件下载出来导入postman后,即可自行测试执行效果,后续在SAP端实现ZPL预览的效果就是调用的该API来实现的:
关于ZPL的更多信息可以参考下面这篇博客,或者访问官方文档:
对于不熟悉ZPL语言的开发者,我们需要借助Zebra Desiner工具来生成ZPL代码。
下载地址:ZebraDesigner 3 Software Support & Downloads | Zebra
安装好Zebra Desiner之后,打开软件,新建标签,借助左侧的工具,我们可以快速的画出一个想要的标签模板:
点击上方的打印按钮:
勾选打印至文件按钮,再点击打印,即可将标签对应的ZPL语言代码下载至本地:?
将文本中的ZPL代码粘贴至在线预览网站,可以看到被解析为我们所绘制的标签图形
注:或许有其他更好的方式来实现在SAP中调用ZPL打印,本文方式仅是一种解决方案。
跟我们平时所做的smartforms,adobe forms打印相同,我们都需要通过变量来传参,所以我们要做的是,通过Zebra Designer调整好标签内容的样式及位置之后,将其中需要用变量替换的内容,用占位符来代替,然后通过ABAP代码来替换掉其中的占位符,再将替换后的内容进行打印或者预览即可,下面做一个demo来演示完整的开发步骤:
此处将原本的固定值2A01,2100替换为占位符?%PLANT%?和?%LOCATION%
注:条形码可以按照替换值的方式正常替换,但是二维码的大小会根据内容长短而变化,如果要保证二维码大小固定,应该只能通过补空格等方式来保证内容长度一致,即可保证二维码大小一致,实际上通过各种Desiner生成的二维码其实是可以固定大小的,即使内容长度不一致,原理大概是将二维码转成图片再通过Z64或者其他编码去加密生成的,SAP端尚不知道有什么好办法来实现这种效果。
使用SO10长本文来存储ZPL代码是一个不错的选择,为了区分属于自开发的内容,我们最好创建自定义的文本ID。
首先使用READ_TEXT读取上一步存储的ZPL代码,然后用?REPLACE ALL OCCURRENCE?关键字将占位符替换为根据实际业务取出来的值。
*&---------------------------------------------------------------------*
*& Form frm_get_zpl
*&---------------------------------------------------------------------*
*& Get ZPL code and replace the value
*&---------------------------------------------------------------------*
FORM frm_get_zpl .
DATA:
lt_tline TYPE text_line_tab,
lt_tline_ret TYPE text_line_tab,
lv_string TYPE string.
CALL FUNCTION 'READ_TEXT'
EXPORTING
* CLIENT = SY-MANDT
id = 'ZDEM'
language = sy-langu
name = 'ZDEMO_ZPL'
object = 'TEXT'
* ARCHIVE_HANDLE = 0
* LOCAL_CAT = ' '
* IMPORTING
* HEADER =
* OLD_LINE_COUNTER =
TABLES
lines = lt_tline
EXCEPTIONS
id = 1
language = 2
name = 3
not_found = 4
object = 5
reference_check = 6
wrong_access_to_archive = 7
OTHERS = 8.
IF sy-subrc <> 0.
* Implement suitable error handling here
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1
sy-msgv2
sy-msgv3
sy-msgv4.
RETURN.
ENDIF.
* Convert to string
CALL FUNCTION 'IDMX_DI_TLINE_INTO_STRING'
EXPORTING
it_tline = lt_tline
IMPORTING
ev_text_string = lv_string.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN lv_string WITH space.
REPLACE ALL OCCURRENCES OF '%PLANT%' IN lv_string WITH '2A01'.
REPLACE ALL OCCURRENCES OF '%LOCATION%' IN lv_string WITH '2100'.
gv_zpl_string = lv_string.
ENDFORM.
使用NEW-PAGE PRINT ON和NEW-PAGE PRINT OFF+WRITE来实现将ZPL代码输出至打印设备,打印结果可以在SP01中看到。
打印设备根据实际情况选择,如果需要SAP中配置Zebra打印机,可以参考下面的这篇博客。
*&---------------------------------------------------------------------*
*& Form frm_print_zpl
*&---------------------------------------------------------------------*
*& Print ZPL to SP01
*&---------------------------------------------------------------------*
FORM frm_print_zpl .
DATA:
lt_string TYPE STANDARD TABLE OF string,
lv_zpl_string TYPE string.
NEW-PAGE PRINT ON
DESTINATION 'PM42'
COPIES 1
LIST NAME space
LIST DATASET space
IMMEDIATELY 'X'
KEEP IN SPOOL 'X'
LINE-COUNT 60000
LINE-SIZE 1023
LAYOUT 'G_RAW'
NEW LIST IDENTIFICATION 'X'
SAP COVER PAGE space
NO DIALOG
NO-TITLE
NO-HEADING.
lv_zpl_string = gv_zpl_string.
REPLACE ALL OCCURRENCES OF '^FS' IN lv_zpl_string WITH |^FS{ cl_abap_char_utilities=>cr_lf }|.
SPLIT lv_zpl_string AT cl_abap_char_utilities=>cr_lf INTO TABLE lt_string.
LOOP AT lt_string INTO DATA(ls_string).
WRITE:ls_string.
NEW-LINE.
ENDLOOP.
NEW-PAGE PRINT OFF.
MESSAGE 'ZPL Printed' TYPE 'S'.
ENDFORM.
通常我们要知道ZPL的输出内容,需要将ZPL代码放在在线预览网站中才能知道效果,这样很不方便,所以我们可以调用他们提供的公有API,以下是调用测试代码:
*&---------------------------------------------------------------------*
*& Form frm_preview_zpl
*&---------------------------------------------------------------------*
*& Preview ZPL as PDF
*&---------------------------------------------------------------------*
FORM frm_preview_zpl .
DATA:
lv_request_data TYPE string,
lv_responsex TYPE xstring,
lo_http_client TYPE REF TO if_http_client,
lv_url TYPE string,
lv_response TYPE string,
lv_msgty TYPE c,
lv_msgtx TYPE string.
lv_url = 'http://api.labelary.com/v1/printers/8dpmm/labels/7x8/' .
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = lv_url
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* Implement suitable error handling here
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1
sy-msgv2
sy-msgv3
sy-msgv4.
EXIT.
ENDIF.
* Set header to get pdf
lo_http_client->request->set_header_field(
name = 'Accept'
value = 'application/pdf'
).
* Set content-type
lo_http_client->request->set_content_type(
content_type = 'application/x-www-form-urlencoded'
).
* Content of ZPL request data
lv_request_data = gv_zpl_string.
* Set request body
lo_http_client->request->set_cdata( data = lv_request_data ).
* Set request method
lo_http_client->request->set_method( 'POST' ).
* Send request
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
).
IF sy-subrc <> 0.
lo_http_client->get_last_error( IMPORTING message = lv_msgtx ).
MESSAGE lv_msgtx TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
* Receive response data
CALL METHOD lo_http_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.
IF sy-subrc <> 0 .
lo_http_client->get_last_error( IMPORTING message = lv_msgtx ).
MESSAGE lv_msgtx TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
* Get response body
lv_responsex = lo_http_client->response->get_data( ).
* Convert XSTRING to Binary
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_responsex
TABLES
binary_tab = gt_pdf_binary.
CALL SCREEN 9000.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_display_pdf
*&---------------------------------------------------------------------*
*& Show PDF
*&---------------------------------------------------------------------*
FORM frm_display_pdf .
* Create container object
CREATE OBJECT go_pdf_container
EXPORTING
container_name = 'PDF'.
* Creare pdf object
CREATE OBJECT go_pdf_object
EXPORTING
parent = go_pdf_container.
* Load PDF binary data
CALL METHOD go_pdf_object->load_data
EXPORTING
type = 'application'
subtype = 'pdf'
IMPORTING
assigned_url = gv_pdf_url
CHANGING
data_table = gt_pdf_binary
EXCEPTIONS
dp_invalid_parameter = 1
dp_error_general = 2
cntl_error = 3
html_syntax_notcorrect = 4
OTHERS = 5.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
RETURN.
ENDIF.
CALL METHOD go_pdf_object->show_data
EXPORTING
url = gv_pdf_url
in_place = abap_true.
ENDFORM.
输出效果:
SAP端显示PDF的实现可以参考Jerry老师的这篇文章:
如何在 SAPGUI 里显示上传到 ABAP 服务器的 PDF 文件_abap屏幕加载pdf文件-CSDN博客
^XA
~TA000
~JSN
^LT0
^MNW
^MTT
^PON
^PMN
^LH0,0
^JMA
^PR6,6
~SD15
^JUS
^LRN
^CI27
^PA0,1,1,0
^XZ
^XA
^MMT
^PW900
^LL600
^LS0
^FT119,162^A0N,42,43^FH\^CI28^FDHello ABAP^FS^CI27
^FT119,215^A0N,42,43^FH\^CI28^FDHello DeveloperMrMeng^FS^CI27
^BY2,3,61^FT119,308^BCN,,Y,N
^FH\^FD>;123456789012^FS
^FO382,247^GB454,239,2^FS
^FO385,300^GB452,0,2^FS
^FO607,250^GB0,237,2^FS
^FT160,482^BQN,2,5
^FH\^FDLA,123456789012^FS
^FT445,292^A0N,42,43^FH\^CI28^FDPlant^FS^CI27
^FT646,292^A0N,42,43^FH\^CI28^FDLocation^FS^CI27
^FT452,397^A0N,42,43^FH\^CI28^FD%PLANT%^FS^CI27
^FT684,397^A0N,42,43^FH\^CI28^FD%LOCATION%^FS^CI27
^LRY^FO717,101^GB120,0,120^FS^LRN
^LRY^FO691,74^GB120,0,120^FS^LRN
^PQ1,0,1,Y
^XZ
*&---------------------------------------------------------------------*
*& Report ZPRTEST_ZPL_DEMO
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zprtest_zpl_demo.
DATA:
gv_zpl_string TYPE string,
gt_pdf_binary TYPE STANDARD TABLE OF raw255,
gv_ok_code TYPE sy-ucomm,
go_pdf_object TYPE REF TO cl_gui_html_viewer,
go_pdf_container TYPE REF TO cl_gui_custom_container,
gv_pdf_url TYPE char255.
PARAMETERS:
p_print RADIOBUTTON GROUP gp1 DEFAULT 'X',
p_prev RADIOBUTTON GROUP gp1.
INITIALIZATION.
%_p_print_%_app_%-text = 'Print'.
%_p_prev_%_app_%-text = 'Preview'.
START-OF-SELECTION.
* Get ZPL code and replace value
PERFORM frm_get_zpl.
CASE abap_on.
WHEN p_print.
* Print ZPL to print spool
PERFORM frm_print_zpl.
WHEN p_prev.
* Preview ZPL as PDF
PERFORM frm_preview_zpl.
WHEN OTHERS.
ENDCASE.
*&---------------------------------------------------------------------*
*& Form frm_print_zpl
*&---------------------------------------------------------------------*
*& Print ZPL to SP01
*&---------------------------------------------------------------------*
FORM frm_print_zpl .
DATA:
lt_string TYPE STANDARD TABLE OF string,
lv_zpl_string TYPE string.
NEW-PAGE PRINT ON
DESTINATION 'PM42'
COPIES 1
LIST NAME space
LIST DATASET space
IMMEDIATELY 'X'
KEEP IN SPOOL 'X'
LINE-COUNT 60000
LINE-SIZE 1023
LAYOUT 'G_RAW'
NEW LIST IDENTIFICATION 'X'
SAP COVER PAGE space
NO DIALOG
NO-TITLE
NO-HEADING.
lv_zpl_string = gv_zpl_string.
REPLACE ALL OCCURRENCES OF '^FS' IN lv_zpl_string WITH |^FS{ cl_abap_char_utilities=>cr_lf }|.
SPLIT lv_zpl_string AT cl_abap_char_utilities=>cr_lf INTO TABLE lt_string.
LOOP AT lt_string INTO DATA(ls_string).
WRITE:ls_string.
NEW-LINE.
ENDLOOP.
NEW-PAGE PRINT OFF.
MESSAGE 'ZPL Printed' TYPE 'S'.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_preview_zpl
*&---------------------------------------------------------------------*
*& Preview ZPL as PDF
*&---------------------------------------------------------------------*
FORM frm_preview_zpl .
DATA:
lv_request_data TYPE string,
lv_responsex TYPE xstring,
lo_http_client TYPE REF TO if_http_client,
lv_url TYPE string,
lv_response TYPE string,
lv_msgty TYPE c,
lv_msgtx TYPE string.
lv_url = 'http://api.labelary.com/v1/printers/8dpmm/labels/7x8/' .
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = lv_url
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* Implement suitable error handling here
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1
sy-msgv2
sy-msgv3
sy-msgv4.
EXIT.
ENDIF.
* Set header to get pdf
lo_http_client->request->set_header_field(
name = 'Accept'
value = 'application/pdf'
).
* Set content-type
lo_http_client->request->set_content_type(
content_type = 'application/x-www-form-urlencoded'
).
* Content of ZPL request data
lv_request_data = gv_zpl_string.
* Set request body
lo_http_client->request->set_cdata( data = lv_request_data ).
* Set request method
lo_http_client->request->set_method( 'POST' ).
* Send request
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
).
IF sy-subrc <> 0.
lo_http_client->get_last_error( IMPORTING message = lv_msgtx ).
MESSAGE lv_msgtx TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
* Receive response data
CALL METHOD lo_http_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.
IF sy-subrc <> 0 .
lo_http_client->get_last_error( IMPORTING message = lv_msgtx ).
MESSAGE lv_msgtx TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
* Get response body
lv_responsex = lo_http_client->response->get_data( ).
* Convert XSTRING to Binary
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_responsex
TABLES
binary_tab = gt_pdf_binary.
CALL SCREEN 9000.
ENDFORM.
*&---------------------------------------------------------------------*
*& Module STATUS_9000 OUTPUT
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
MODULE status_9000 OUTPUT.
SET PF-STATUS 'STATUS_9000'.
PERFORM frm_display_pdf.
ENDMODULE.
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_9000 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_9000 INPUT.
gv_ok_code = sy-ucomm.
CASE gv_ok_code.
WHEN 'QUIT' OR 'BACK' OR 'EXIT'.
LEAVE PROGRAM.
WHEN OTHERS.
ENDCASE.
ENDMODULE.
*&---------------------------------------------------------------------*
*& Form frm_display_pdf
*&---------------------------------------------------------------------*
*& Show PDF
*&---------------------------------------------------------------------*
FORM frm_display_pdf .
* Create container object
CREATE OBJECT go_pdf_container
EXPORTING
container_name = 'PDF'.
* Creare pdf object
CREATE OBJECT go_pdf_object
EXPORTING
parent = go_pdf_container.
* Load PDF binary data
CALL METHOD go_pdf_object->load_data
EXPORTING
type = 'application'
subtype = 'pdf'
IMPORTING
assigned_url = gv_pdf_url
CHANGING
data_table = gt_pdf_binary
EXCEPTIONS
dp_invalid_parameter = 1
dp_error_general = 2
cntl_error = 3
html_syntax_notcorrect = 4
OTHERS = 5.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
RETURN.
ENDIF.
CALL METHOD go_pdf_object->show_data
EXPORTING
url = gv_pdf_url
in_place = abap_true.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form frm_get_zpl
*&---------------------------------------------------------------------*
*& Get ZPL code and replace the value
*&---------------------------------------------------------------------*
FORM frm_get_zpl .
DATA:
lt_tline TYPE text_line_tab,
lt_tline_ret TYPE text_line_tab,
lv_string TYPE string.
CALL FUNCTION 'READ_TEXT'
EXPORTING
* CLIENT = SY-MANDT
id = 'ZDEM'
language = sy-langu
name = 'ZDEMO_ZPL'
object = 'TEXT'
* ARCHIVE_HANDLE = 0
* LOCAL_CAT = ' '
* IMPORTING
* HEADER =
* OLD_LINE_COUNTER =
TABLES
lines = lt_tline
EXCEPTIONS
id = 1
language = 2
name = 3
not_found = 4
object = 5
reference_check = 6
wrong_access_to_archive = 7
OTHERS = 8.
IF sy-subrc <> 0.
* Implement suitable error handling here
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1
sy-msgv2
sy-msgv3
sy-msgv4.
RETURN.
ENDIF.
* Convert to string
CALL FUNCTION 'IDMX_DI_TLINE_INTO_STRING'
EXPORTING
it_tline = lt_tline
IMPORTING
ev_text_string = lv_string.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN lv_string WITH space.
REPLACE ALL OCCURRENCES OF '%PLANT%' IN lv_string WITH '2A01'.
REPLACE ALL OCCURRENCES OF '%LOCATION%' IN lv_string WITH '2100'.
gv_zpl_string = lv_string.
ENDFORM.
以上。