Всем привет!
Сегодня я расскажу о том, как довольно легко сделать выгрузку файла из Web Dynpro приложения.
Предположим, что вы создали программу, которая выгружает документ Word или Excel в SAP GUI. Для выгрузки вы использовали инструмент ZWWW. Через некоторое время к вам поступает требование от бизнеса реализовать возможность выгрузки этих документов через личный кабинет руководителя. Личный кабинет построен на некогда популярной технологии Web Dynpro (сократим до WD).
Общая часть.
Для выгрузки из WD приложения создадим в нашем отчете новую подпрограмму execute_from_web.
FORM execute_from_web USING iv_pernr TYPE pernr_d iv_date TYPE datum iv_format TYPE char1. DATA: lv_filenm_pdf TYPE fpname. p_pernr = iv_pernr. p_date = iv_date. p_format = iv_format. * Заполняем выходную структуру gs_outstruc и преобразовываем ее в таблицу gtd_values PERFORM get_data. CASE iv_format. WHEN 1. PERFORM print_file USING gc_invoice_word. " имя шаблона Word в smw0 WHEN 2. PERFORM print_file USING gc_payment_order_excel. " имя шаблона Excel в smw0 WHEN 3. PERFORM call_pdf USING gc_payment_order_pdf. " имя Pdf-формуляра в sfp . WHEN OTHERS. ENDCASE. ENDFORM.
Эту подпрограмму будем вызывать в методе-обработчике событий WD приложения (будет рассмотрен ниже).
Инструмент ZWWW умеет выгружать документ через web. Поэтому, в данном случае, нам нет необходимости тем или иным способом получать xstring чтобы выгрузить файл. Это есть хорошо.
FORM print_file USING uv_form_name TYPE wwwdatatab-objid. CALL FUNCTION 'ZWWW_OPENFORM' EXPORTING form_name = uv_form_name protect = '' TABLES it_values = gtd_values EXCEPTIONS printcancel = 1 OTHERS = 2. IF sy-subrc <> 0. MESSAGE ID 'ZHR_TEST' TYPE 'E' NUMBER 001. ENDIF. " sy-subrc <> 0. 'ZWWW_OPENFORM' ENDFORM. " print_file.
Таблица gtd_values в моем случае была заполнена в подпрограмме get_data.
PDF.
Для получение pdf-файла создадим форму call_pdf.
FORM call_pdf USING uv_filenm TYPE fpname. DATA: lv_fname TYPE funcname, ls_outputparams TYPE sfpoutputparams, ls_formoutput TYPE fpformoutput, lo_cx_fp_api TYPE REF TO cx_fp_api, lv_msg TYPE string. CHECK gs_outstruc IS NOT INITIAL. TRY. CALL FUNCTION 'FP_FUNCTION_MODULE_NAME' EXPORTING i_name = uv_filenm IMPORTING e_funcname = lv_fname. CATCH cx_fp_api_internal cx_fp_api_repository cx_fp_api_usage INTO lo_cx_fp_api. lv_msg = lo_cx_fp_api->get_text( ). MESSAGE lv_msg TYPE wctpm_msgtyp-error. ENDTRY. * Обратите внимание! ls_outputparams-nodialog = 'X'. ls_outputparams-getpdf = 'X'. CALL FUNCTION 'FP_JOB_OPEN' CHANGING ie_outputparams = ls_outputparams EXCEPTIONS usage_error = 1 system_error = 2 internal_error = 3 OTHERS = 4. CHECK sy-subrc = 0. CALL FUNCTION lv_fname EXPORTING is_data = gs_outstruc IMPORTING /1bcdwb/formoutput = ls_formoutput EXCEPTIONS usage_error = 1 system_error = 2 internal_error = 3 OTHERS = 4. CHECK sy-subrc = 0. CALL FUNCTION 'FP_JOB_CLOSE' EXCEPTIONS usage_error = 1 system_error = 2 internal_error = 3 OTHERS = 4. CHECK sy-subrc = 0. cl_wd_runtime_services=>attach_file_to_response( i_filename = |{ uv_filenm }_{ sy-timlo }.pdf'| i_content = ls_formoutput-pdf i_mime_type = 'application/pdf' ) ##NO_TEXT. ENDFORM. " call_pdf.
Самое интересное.
В методе do_operations на событии «PRINT» вызываем подпрограмму печати документа execute_from_web, созданную нами выше.
METHOD if_hrasr00gen_service~do_operations. DATA: lo_fpm TYPE REF TO cl_fpm, lv_event TYPE fpm_event_id, lv_pernr TYPE pernr_d, lv_date TYPE dats, lv_format TYPE char1. * Получаем параметры из полей в браузере lv_pernr = ctd_service_dataset[ fieldname = 'PERNR' ]-fieldvalue. lv_date = ctd_service_dataset[ fieldname = 'DATE' ]-fieldvalue. lv_format = ctd_service_dataset[ fieldname = 'FORMAT' ]-fieldvalue. "Формат файла(1-word,2-excel,3-pdf) * Получаем событие lo_fpm ?= cl_fpm=>get_instance( ). IF lo_fpm IS BOUND. lv_event = lo_fpm->mo_current_event->mv_event_id. CASE lv_event. WHEN 'PRINT'. PERFORM execute_from_web IN PROGRAM zhr_test USING lv_pernr lv_date lv_format. ENDCASE. ENDIF. ENDMETHOD.
Результат:
Ниже приведен скриншот выгрузки файла pdf.
Для Word и Excel файлов результат такой же.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Я решал задачу распаковки текста из stream-ов, запакованных с помощью FlateDecode. Выкладываю код.
Если не заработает, присылайте пример в pdf, попробую посмотреть
CLASS lcl_pdf_parser DEFINITION DEFERRED.
CLASS lcl_pdf_concat_line DEFINITION.
PUBLIC SECTION.
» Текстовый элемент, загруженный из PDF
TYPES: BEGIN OF t_text_element,
num_element TYPE I,
num_page TYPE I,
X TYPE I,
Y TYPE I,
font(20) TYPE C,
font_size TYPE I,
text TYPE STRING,
textUcase TYPE STRING,
src_file_line TYPE I,
END OF t_text_element.
TYPES: tt_text_element TYPE TABLE OF t_text_element.
METHODS: constructor IMPORTING
pi_elements TYPE tt_text_element
pi_line_num TYPE I.
METHODS: get_text EXPORTING
pe_text TYPE STRING,
get_text_condensed EXPORTING
pe_text TYPE STRING,
get_line_num EXPORTING
pe_line_num TYPE I,
get_Y EXPORTING
pe_Y TYPE I.
PRIVATE SECTION.
TYPES: BEGIN OF t_concat_element,
num_page TYPE I,
start_pos TYPE I,
end_pos TYPE I,
start_pos_condensed TYPE I,
end_pos_condensed TYPE I,
element TYPE t_text_element,
END OF t_concat_element.
DATA: m_concat_text TYPE STRING,
m_concat_text_condensed TYPE STRING,
m_concat_elements TYPE TABLE OF t_concat_element,
m_line_num TYPE I,
m_Y TYPE I.
ENDCLASS.
CLASS lcl_pdf_concat_line IMPLEMENTATION.
METHOD constructor.
DATA: lit_elements TYPE TABLE OF t_text_element,
lwa_element TYPE t_text_element,
lwa_concat_element TYPE t_concat_element,
lh_text_condensed TYPE STRING,
lh_len TYPE I,
lh_len_c TYPE I,
lh_len_all TYPE I,
lh_len_c_all TYPE I.
m_line_num = pi_line_num.
CHECK pi_elements[] IS NOT INITIAL.
» Сортируем элементы так, чтобы элементы с меньшим X шли раньше, но в остальном порядок
» не меняя
m_Y = 99999.
lit_elements[] = pi_elements[].
SORT lit_elements BY X num_element.
«LOOP AT pi_elements INTO lwa_element.
LOOP AT lit_elements INTO lwa_element.
lh_text_condensed = lwa_element-text.
CONDENSE lh_text_condensed NO-GAPS.
lwa_concat_element-num_page = lwa_element-num_page.
lwa_concat_element-start_pos = lh_len_all.
lwa_concat_element-end_pos = lwa_concat_element-start_pos + strlen( lwa_element-text ) — 1.
lwa_concat_element-start_pos_condensed = lh_len_c_all.
lwa_concat_element-end_pos_condensed = lh_len_c_all + strlen( lh_text_condensed ) — 1.
lwa_concat_element-element = lwa_element.
APPEND lwa_concat_element TO m_concat_elements.
CONCATENATE m_concat_text lwa_element-text INTO m_concat_text.
CONCATENATE m_concat_text_condensed lh_text_condensed INTO m_concat_text_condensed.
IF lwa_element-Y < m_Y.
m_Y = lwa_element-Y.
ENDIF.
lh_len_all = lh_len_all + strlen( lwa_element-text ).
lh_len_c_all = lh_len_c_all + strlen( lh_text_condensed ).
ENDLOOP.
ENDMETHOD. » constructor
METHOD get_text.
pe_text = m_concat_text.
ENDMETHOD.
METHOD get_text_condensed.
pe_text = m_concat_text_condensed.
ENDMETHOD.
METHOD get_line_num.
pe_line_num = m_line_num.
ENDMETHOD.
» Возвращает Y-координату объекта
METHOD get_Y.
pe_Y = m_Y.
ENDMETHOD. » get_Y
ENDCLASS.
* Класс для парсинга PDF (разделение и структурирование его текстовых элементов) и
* удобной работы с данными элементами
CLASS lcl_pdf_parser DEFINITION.
PUBLIC SECTION.
TYPES: lcl_pdf_concat_line_tab TYPE TABLE OF REF TO lcl_pdf_concat_line.
CLASS-METHODS: try_read_number IMPORTING
pi_number TYPE ANY
CHANGING
pc_number TYPE ANY
EXCEPTIONS
INVALID_FORMAT.
METHODS: load_pdf_from_server IMPORTING
pi_filename TYPE C
EXCEPTIONS
ERROR_IN_LOADING
ERROR_IN_PARSING,
load_pdf_from_gui IMPORTING
pi_filename TYPE C
EXCEPTIONS
ERROR_IN_LOADING
ERROR_IN_PARSING,
load_pdf_from_itab IMPORTING
pi_it_filedata TYPE STANDARD TABLE
EXCEPTIONS
ERROR_IN_PARSING,
is_loaded EXPORTING
pe_loaded TYPE C,
get_num_pages EXPORTING
pe_num_pages TYPE I,
get_all_elements EXPORTING
pe_elements TYPE lcl_pdf_concat_line=>tt_text_element,
» Методы для текстовых элементов как есть
find_text IMPORTING
pi_num_page TYPE I DEFAULT 1
pi_text TYPE C
pi_match_case TYPE C DEFAULT SPACE
EXPORTING
pe_elements TYPE lcl_pdf_concat_line=>tt_text_element,
find_text_by_mask IMPORTING
pi_num_page TYPE I DEFAULT 1
pi_text TYPE C
pi_match_case TYPE C DEFAULT SPACE
EXPORTING
pe_elements TYPE lcl_pdf_concat_line=>tt_text_element,
find_text_below IMPORTING
pi_element TYPE lcl_pdf_concat_line=>t_text_element
pi_accuracy TYPE I
EXPORTING
pe_elements TYPE lcl_pdf_concat_line=>tt_text_element,
find_text_right IMPORTING
pi_element TYPE lcl_pdf_concat_line=>t_text_element
pi_accuracy TYPE I
EXPORTING
pe_elements TYPE lcl_pdf_concat_line=>tt_text_element,
find_text_in_box IMPORTING
pi_num_page TYPE I
pi_left TYPE I
pi_top TYPE I
pi_right TYPE I
pi_bottom TYPE I
EXPORTING
pe_elements TYPE lcl_pdf_concat_line=>tt_text_element,
» Методы для конкатенированного текста
find_text_concat IMPORTING
pi_num_page TYPE I
pi_text TYPE C
pi_match_case TYPE C DEFAULT SPACE
pi_condensed TYPE C DEFAULT SPACE
EXPORTING
pe_concat_lines TYPE lcl_pdf_concat_line_tab,
find_lines_in_range IMPORTING
pi_num_page TYPE I
pi_top TYPE I
pi_bottom TYPE I
EXPORTING
pe_concat_lines TYPE lcl_pdf_concat_line_tab,
find_next_concat_line IMPORTING
pi_concat_line TYPE REF TO lcl_pdf_concat_line
pi_ignore_page TYPE C DEFAULT SPACE
EXPORTING
pe_concat_line_next TYPE REF TO lcl_pdf_concat_line.
PRIVATE SECTION.
CONSTANTS: mc_endstreamx(9) TYPE X VALUE ‘656E6473747265616D’. » Слово endstream в 16-ричном виде для удобного поиска в xstring
TYPES: BEGIN OF t_concat_text,
line_num TYPE I,
num_page TYPE I,
Y TYPE I,
text TYPE STRING,
text_cond TYPE STRING,
text_u TYPE STRING,
text_cond_u TYPE STRING,
END OF t_concat_text.
DATA: mt_filelines TYPE TABLE OF STRING,
m_contentx TYPE XSTRING,
mt_elements TYPE TABLE OF lcl_pdf_concat_line=>t_text_element,
mt_line_ends TYPE match_result_tab,
m_num_pages TYPE I,
m_concat_lines TYPE TABLE OF REF TO lcl_pdf_concat_line,
m_concat_texts TYPE TABLE OF t_concat_text.
METHODS: load_from_content,
parse,
get_lines_as_xstring IMPORTING
pi_start_line TYPE I
pi_end_line TYPE I
EXPORTING
pe_xlines TYPE XSTRING,
build_concat_lines.
ENDCLASS.
CLASS lcl_pdf_parser IMPLEMENTATION.
» Загружает файл PDF из папки на сервере
METHOD load_pdf_from_server.
CLEAR m_contentx.
» Загружаем
OPEN DATASET pi_filename FOR INPUT IN BINARY MODE.
IF sy-subrc <> 0.
«PERFORM log_msg USING » » ‘ZCAT’ c_error c_important ‘402’ pi_filename » » ».
RAISE ERROR_IN_LOADING.
ENDIF.
READ DATASET pi_filename INTO m_contentx.
CLOSE DATASET pi_filename.
» Загружаем из m_xcontent во внутреннюю таблицу, распаковывая FlateDecode-куски
CALL METHOD load_from_content( ).
IF mt_filelines[] IS INITIAL.
CLEAR m_contentx.
RAISE ERROR_IN_PARSING.
ENDIF.
» Парсим
CALL METHOD parse( ).
IF mt_elements[] IS INITIAL.
REFRESH mt_filelines[].
RAISE ERROR_IN_PARSING.
ENDIF.
ENDMETHOD. » METHOD load_pdf_from_server.
» Загружает файл PDF в GUI
METHOD load_pdf_from_gui.
TYPES: BEGIN OF lt_xline,
xline(3000) TYPE X,
END OF lt_xline.
DATA: lit_lines TYPE TABLE OF lt_xline,
lwa_line TYPE lt_xline,
lh_filename TYPE STRING.
» Загружаем
REFRESH mt_filelines[].
CLEAR m_contentx.
lh_filename = pi_filename.
CALL FUNCTION ‘GUI_UPLOAD’
EXPORTING
filename = lh_filename
filetype = ‘BIN’
TABLES
«data_tab = mt_filelines[]
data_tab = lit_lines[]
EXCEPTIONS
file_open_error = 1
file_read_error = 2
no_batch = 3
gui_refuse_filetransfer = 4
invalid_type = 5
no_authority = 6
unknown_error = 7
bad_data_format = 8
header_not_allowed = 9
separator_not_allowed = 10
header_too_long = 11
unknown_dp_error = 12
access_denied = 13
dp_out_of_memory = 14
disk_full = 15
dp_timeout = 16
OTHERS = 17.
IF sy-subrc <> 0.
RAISE ERROR_IN_LOADING.
ENDIF.
LOOP AT lit_lines INTO lwa_line.
CONCATENATE m_contentx lwa_line-xline INTO m_contentx IN BYTE MODE.
ENDLOOP.
» Загружаем из m_xcontent во внутреннюю таблицу, распаковывая FlateDecode-куски
CALL METHOD load_from_content( ).
IF mt_filelines[] IS INITIAL.
CLEAR m_contentx.
RAISE ERROR_IN_PARSING.
ENDIF.
» Парсим
CALL METHOD parse( ).
» Test
«CALL METHOD build_concat_lines( ).
IF mt_elements[] IS INITIAL.
REFRESH mt_filelines[].
RAISE ERROR_IN_PARSING.
ENDIF.
ENDMETHOD. » METHOD load_pdf_from_gui.
» Загружает файл PDF, предварительно загруженный во внутреннюю таблицу
METHOD load_pdf_from_itab.
REFRESH mt_filelines[].
mt_filelines[] = pi_it_filedata[].
IF mt_filelines[] IS INITIAL.
RAISE ERROR_IN_PARSING.
ENDIF.
» Парсим
CALL METHOD parse( ).
IF mt_elements[] IS INITIAL.
REFRESH mt_filelines[].
RAISE ERROR_IN_PARSING.
ENDIF.
ENDMETHOD. » load_pdf_from_itab
» После того, как файл в бинарном виде загружен в переменную m_contentx, данный метод
» разбирает его на строки и если нужно распаговывает куски, запакованные с помощью FlateDecode
» Все строки записываются во внутреннюю таблицу, где все запакованные куски уже распакованы, то есть уже как текст
METHOD load_from_content.
TYPES: BEGIN OF lt_flateDecode_stream,
start_line TYPE I,
end_line TYPE I,
end_offset TYPE I, » Количество символов до конца строки, где заканчивается stream
END OF lt_flateDecode_stream.
DATA: lit_str TYPE TABLE OF STRING,
lwa_result TYPE match_result,
lwa_result_last TYPE match_result,
lit_flDecode TYPE TABLE OF lt_flateDecode_stream,
lwa_flDecode TYPE lt_flateDecode_stream,
lit_filelines_tmp TYPE TABLE OF STRING,
lit_lines TYPE TABLE OF STRING,
lit_line_ends TYPE match_result_tab,
lh_str TYPE STRING,
lh_line TYPE STRING,
lh_xstring TYPE XSTRING,
lh_xstring_unp TYPE XSTRING,
lh_in_obj(1) TYPE C,
lh_in_stream(1) TYPE C,
lh_in_gg(1) TYPE C,
lh_flateDecode(1) TYPE C,
lh_last_end TYPE I,
lh_len TYPE I,
lh_len1 TYPE I,
lh_line_num TYPE I,
lh_stream_start_line TYPE I,
lh_last_end_line TYPE I.
DATA: c_conv TYPE REF TO cl_abap_conv_in_ce,
c_zip TYPE REF TO cl_abap_gzip.
REFRESH mt_filelines[].
» Разделяем нас троки, разделители могут быть любые, причем разные в пределах одного
» файла
«FIND ALL OCCURRENCES OF m_sepx IN m_contentx IN BYTE MODE RESULTS mt_line_ends.
lh_xstring = ‘0D0A’.
FIND ALL OCCURRENCES OF lh_xstring IN m_contentx IN BYTE MODE RESULTS mt_line_ends.
lh_xstring = ‘0D’.
FIND ALL OCCURRENCES OF lh_xstring IN m_contentx IN BYTE MODE RESULTS lit_line_ends.
APPEND LINES OF lit_line_ends TO mt_line_ends.
lh_xstring = ‘0A’.
FIND ALL OCCURRENCES OF lh_xstring IN m_contentx IN BYTE MODE RESULTS lit_line_ends.
APPEND LINES OF lit_line_ends TO mt_line_ends.
SORT mt_line_ends BY offset length DESCENDING.
» Сначала убираем лишние точки — например, если разделитель ODOA, то мы также найдем
» отдельно OD и отдельно OA, но эти точки лишние и их нужно убрать
LOOP AT mt_line_ends INTO lwa_result.
IF lwa_result-length = 2.
lh_last_end = lwa_result-offset.
ELSEIF lwa_result-length = 1.
lh_len = lwa_result-offset — lh_last_end.
IF lh_len <= 1.
DELETE mt_line_ends.
ENDIF.
ENDIF.
ENDLOOP.
CHECK mt_line_ends[] IS NOT INITIAL.
» Конвертируем в текст, разделенный по строкам
READ TABLE mt_line_ends INDEX 1 INTO lwa_result.
lh_last_end = 0 — lwa_result-length.
lwa_result_last = lwa_result.
LOOP AT mt_line_ends INTO lwa_result.
«lh_last_end = lwa_result_last-offset + lwa_result_last-length.
lh_last_end = lh_last_end + lwa_result_last-length.
lh_len = lwa_result-offset — lh_last_end. » — lwa_result-length.
«lh_last_end = lh_last_end + lwa_result-length.
lh_xstring = m_contentx+lh_last_end(lh_len).
c_conv = cl_abap_conv_in_ce=>create( input = lh_xstring
replacement = space
encoding = ‘1504’ ).
c_conv->read( EXPORTING
n = lh_len
IMPORTING
data = lh_line
len = lh_len1 ).
APPEND lh_line TO mt_filelines[].
lh_last_end = lwa_result-offset.
lwa_result_last = lwa_result.
ENDLOOP.
» Проверяем, что это действительно PDF — это должно быть написано в начале файла
READ TABLE mt_filelines INDEX 1 INTO lh_line.
IF lh_line(4) <> ‘%PDF’.
REFRESH mt_filelines[].
RETURN.
ENDIF.
» Ищем куски, запакованные с помощью FlateDecode (по сути выполняем легкий парсинг, настоящий парсинг будет в процедуре parse)
LOOP AT mt_filelines INTO lh_line.
lh_line_num = sy-tabix.
CONDENSE lh_line.
SPLIT lh_line AT SPACE INTO TABLE lit_str.
» Если мы не внутри объекта, отслеживаем начало объекта
IF lh_in_obj <> ‘X’.
IF LINES( lit_str ) >= 3.
READ TABLE lit_str INDEX 3 INTO lh_str.
IF lh_str = ‘obj’.
lh_in_obj = ‘X’.
ENDIF.
ENDIF.
ENDIF.
» Отслеживаем начало блока с параметрами <<….. >>
IF strlen( lh_line ) >= 2
AND lh_in_obj = ‘X’
AND lh_in_gg IS INITIAL.
IF lh_line(2) = ‘<<‘.
lh_in_gg = ‘X’.
ENDIF.
ENDIF.
» Если нашли в параметрах FlateDecode, значит следующий stream будет закодирован
IF lh_in_obj = ‘X’ AND lh_in_gg = ‘X’ AND lh_line CP ‘*/FlateDecode*’.
lh_flateDecode = ‘X’.
ENDIF.
» Отслеживаем конец блока с параметрами <<…… >>
IF lh_in_obj = ‘X’ AND lh_in_gg = ‘X’ AND lh_line CP ‘*>>’.
CLEAR lh_in_gg.
ENDIF.
IF strlen( lh_line ) >= 2.
IF lh_line(2) = ‘<<‘ AND lh_line CP ‘*/FlateDecode*’.
lh_flateDecode = ‘X’.
ENDIF.
ENDIF.
» Если мы не внутри stream, отслеживаем его начало
IF lh_in_obj = ‘X’ AND lh_in_stream <> ‘X’ AND lh_line CP ‘*stream’.
lh_in_stream = ‘X’.
lh_stream_start_line = lh_line_num.
ENDIF.
» Если мы внутри stream, отслеживаем ее окончание
IF lh_in_obj = ‘X’ AND lh_in_stream = ‘X’.
CLEAR lh_xstring.
CLEAR lwa_result.
» Если в строке надпись endstream — тогда точно
IF lh_line CP ‘*endstream’.
CLEAR lh_in_stream.
ELSE.
» В бинарной строке может так не найтись, пытаемся в шестнадцатеричном виде
CALL METHOD get_lines_as_xstring( EXPORTING
pi_start_line = lh_line_num
pi_end_line = lh_line_num
IMPORTING
pe_xlines = lh_xstring ).
FIND FIRST OCCURRENCE OF mc_endstreamx IN lh_xstring IN BYTE MODE RESULTS lwa_result.
IF sy-subrc = 0.
CLEAR lh_in_stream.
ENDIF.
ENDIF.
» Если кончился stream и это был FlateDecode — запоминаем все байты stream-а
IF lh_in_stream IS INITIAL AND lh_flateDecode = ‘X’.
IF lh_xstring IS INITIAL.
CALL METHOD get_lines_as_xstring( EXPORTING
pi_start_line = lh_line_num
pi_end_line = lh_line_num
IMPORTING
pe_xlines = lh_xstring ).
ENDIF.
IF lwa_result IS INITIAL.
FIND FIRST OCCURRENCE OF mc_endstreamx IN lh_xstring IN BYTE MODE RESULTS lwa_result.
ENDIF.
CLEAR lwa_flDecode.
lwa_flDecode-start_line = lh_stream_start_line + 1. » Stream начинается со следующей строки после слова stream
IF lwa_result-offset = 0.
lwa_flDecode-end_line = lh_line_num — 1.
lwa_flDecode-end_offset = 0. » До конца строки
ELSE.
lwa_flDecode-end_line = lh_line_num.
lwa_flDecode-end_offset = xstrlen( lh_xstring ) — lwa_result-offset. » + 1.
ENDIF.
APPEND lwa_flDecode TO lit_flDecode.
CLEAR lh_flateDecode.
ENDIF.
ENDIF.
» Если мы внутри объекта, отслеживаем окончание объекта
IF lh_in_obj = ‘X’ AND lh_in_stream <> ‘X’
AND lh_line CP ‘*endobj’.
CLEAR lh_in_obj.
CLEAR lh_flateDecode.
ENDIF.
ENDLOOP.
» Если не нашли stream-ы, запакованные flateDecode, больше ничего не делаем
CHECK lit_flDecode[] IS NOT INITIAL.
CREATE OBJECT c_zip.
lh_last_end_line = 1.
LOOP AT lit_flDecode INTO lwa_flDecode.
» Все строки от предыдущего куска flateDecode до текущего просто копируем
lh_line_num = lwa_flDecode-start_line — 1.
IF lh_line_num < 1.
lh_line_num = 1.
ENDIF.
LOOP AT mt_filelines INTO lh_line
FROM lh_last_end_line TO lh_line_num.
APPEND lh_line TO lit_filelines_tmp.
ENDLOOP.
» Извлекаем кусок файла в виде xstream, являющийся запакованной областью stream-а, причем первые 2 байта не берем, они лишние, реально
» zip начинается с 3-го байта
CALL METHOD get_lines_as_xstring( EXPORTING
pi_start_line = lwa_flDecode-start_line
pi_end_line = lwa_flDecode-end_line
IMPORTING
pe_xlines = lh_xstring ).
lh_len = xstrlen( lh_xstring ) — lwa_flDecode-end_offset — 2.
IF lh_len > 0.
lh_xstring = lh_xstring+2(lh_len).
» Разархивируем
CLEAR lh_xstring_unp.
TRY.
* c_zip->decompress_text( EXPORTING
* gzip_in = lh_xstring
* IMPORTING
* text_out = lh_str
* text_out_len = lh_len1 ).
c_zip->decompress_binary( EXPORTING
gzip_in = lh_xstring
IMPORTING
raw_out = lh_xstring_unp
raw_out_len = lh_len1 ).
CATCH CX_SY_COMPRESSION_ERROR.
CLEAR lh_xstring_unp.
CATCH CX_SY_CONVERSION_CODEPAGE.
CLEAR lh_xstring_unp.
ENDTRY.
IF lh_xstring_unp IS NOT INITIAL.
lh_len = lh_len1.
c_conv = cl_abap_conv_in_ce=>create( input = lh_xstring_unp
replacement = space
encoding = ‘1504’ ).
c_conv->read( EXPORTING
n = lh_len
IMPORTING
data = lh_str
len = lh_len1 ).
» Разделяем строку на отдельные строки, учитывая что разделители могут быть разные
lh_line = ‘#~$’.
DO.
FIND FIRST OCCURRENCE OF lh_line IN lh_str.
IF sy-subrc = 0.
CONCATENATE lh_line lh_line INTO lh_line.
ELSE.
EXIT.
ENDIF.
ENDDO.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN lh_str WITH lh_line.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf(1) IN lh_str WITH lh_line.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+1(1) IN lh_str WITH lh_line.
SPLIT lh_str AT lh_line INTO TABLE lit_lines.
* REFRESH lit_lines2[].
* LOOP AT lit_lines INTO lh_line.
* SPLIT
* ENDLOOP.
» Записываем распакованные строки на месте запакованных
LOOP AT lit_lines INTO lh_line.
APPEND lh_line TO lit_filelines_tmp.
ENDLOOP.
» Добавляем строку со словом endstream, чтобы сохранить корректную структуру файла
IF lwa_flDecode-end_offset IS NOT INITIAL.
lh_line = ‘endstream’.
APPEND lh_line TO lit_filelines_tmp.
ENDIF.
ELSE.
» Если произошла ошибка при распаковывании, просто записываем все строки как есть
LOOP AT mt_filelines INTO lh_line
FROM lwa_flDecode-start_line TO lwa_flDecode-end_line.
APPEND lh_line TO lit_filelines_tmp.
ENDLOOP.
ENDIF.
ENDIF.
lh_last_end_line = lwa_flDecode-end_line + 1.
ENDLOOP.
» Записываем все строки после последнего элемента
lh_line_num = LINES( mt_filelines ).
LOOP AT mt_filelines INTO lh_line
FROM lh_last_end_line TO lh_line_num.
APPEND lh_line TO lit_filelines_tmp.
ENDLOOP.
mt_filelines[] = lit_filelines_tmp[].
ENDMETHOD. » load_from_content
» Выполняет парсинг загруженного PDF
METHOD parse.
» Подгонка — выписал примерные размеры шрифта в зависимости от размера
TYPES: BEGIN OF t_fonthsize,
font_size TYPE I,
glyth_width(15) TYPE P DECIMALS 3,
END OF t_fonthsize.
DATA: lit_str TYPE TABLE OF STRING,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element,
lit_result TYPE match_result_tab,
lwa_result TYPE match_result,
lwa_result_next TYPE match_result,
lit_fonthsize TYPE TABLE OF t_fonthsize,
lwa_fonthsize TYPE t_fonthsize,
lh_str TYPE STRING,
lh_line TYPE STRING,
lh_in_obj(1) TYPE C,
lh_in_stream(1) TYPE C,
lh_in_text(1) TYPE C,
lh_font TYPE STRING,
lh_font_size TYPE I,
lh_X TYPE I,
lh_Y TYPE I,
lh_len TYPE I,
lh_lines TYPE I,
lh_num TYPE I,
lh_tabix LIKE sy-tabix,
lh_space_str TYPE STRING,
lh_text_flag(1) TYPE C,
lh_line_num TYPE I,
lh_min_page TYPE I,
lh_max_page TYPE I,
lh_correct(1) TYPE C.
CHECK mt_filelines[] IS NOT INITIAL.
REFRESH mt_elements[].
» Проверяем, что это действительно PDF — это должно быть написано в начале файла
READ TABLE mt_filelines INDEX 1 INTO lh_line.
IF lh_line(4) <> ‘%PDF’.
RETURN.
ENDIF.
» Готовим таблицу зависимостей ширины символа от шрифта
lwa_fonthsize-font_size = 10.
lwa_fonthsize-glyth_width = ‘5.45’.
APPEND lwa_fonthsize TO lit_fonthsize.
lwa_fonthsize-font_size = 9.
lwa_fonthsize-glyth_width = ‘4.8’.
APPEND lwa_fonthsize TO lit_fonthsize.
lwa_fonthsize-font_size = 8.
lwa_fonthsize-glyth_width = ‘3.8’.
APPEND lwa_fonthsize TO lit_fonthsize.
lwa_fonthsize-font_size = 7.
lwa_fonthsize-glyth_width = ‘3.43’.
APPEND lwa_fonthsize TO lit_fonthsize.
lwa_fonthsize-font_size = 6.
lwa_fonthsize-glyth_width = ‘3.2’.
APPEND lwa_fonthsize TO lit_fonthsize.
lwa_fonthsize-font_size = 5.
lwa_fonthsize-glyth_width = ‘2.67’.
APPEND lwa_fonthsize TO lit_fonthsize.
m_num_pages = 1.
LOOP AT mt_filelines INTO lh_line.
lh_line_num = sy-tabix.
CONDENSE lh_line.
SPLIT lh_line AT SPACE INTO TABLE lit_str.
» Если мы не внутри блока текста, отслеживаем его начало
IF lh_in_obj = ‘X’ AND lh_in_stream = ‘X’ AND lh_in_text <> ‘X’
AND lh_line CP ‘*BT’.
lh_in_text = ‘X’.
CLEAR: lh_font, lh_X, lh_Y.
ENDIF.
» Если мы не внутри stream, отслеживаем его начало
IF lh_in_obj = ‘X’ AND lh_in_stream <> ‘X’ AND lh_line CP ‘*stream’.
lh_in_stream = ‘X’.
ENDIF.
» Если мы не внутри объекта, отслеживаем начало объекта
IF lh_in_obj <> ‘X’.
IF LINES( lit_str ) >= 3.
READ TABLE lit_str INDEX 3 INTO lh_str.
IF lh_str = ‘obj’.
lh_in_obj = ‘X’.
ENDIF.
ENDIF.
ENDIF.
» Отслеживаем начало новой страницы
IF strlen( lh_line ) >= 2.
IF lh_in_obj = ‘X’
AND lh_line CP ‘*/Page*’
AND lh_line CP ‘*/Type*’
AND lh_line NP ‘*/Pages*’.
m_num_pages = m_num_pages + 1.
CLEAR: lh_X, lh_Y.
ENDIF.
ENDIF.
» Отслеживаем тип строки текста по последним 2 символам и считываем
IF lh_in_obj = ‘X’ AND lh_in_stream = ‘X’ AND lh_in_text = ‘X’.
lh_str = lh_line.
lh_len = strlen( lh_str ).
IF lh_len >= 2.
IF lh_len > 2.
lh_len = lh_len — 2.
SHIFT lh_str BY lh_len PLACES LEFT.
ENDIF.
CASE lh_str.
WHEN ‘Tf’. » Шрифт [ /F410130 8 Tf
READ TABLE lit_str INDEX 1 INTO lh_font.
IF LINES( lit_str ) >= 2.
READ TABLE lit_str INDEX 2 INTO lh_str.
CALL METHOD try_read_number EXPORTING
pi_number = lh_str
CHANGING
pc_number = lh_num
EXCEPTIONS
INVALID_FORMAT = 1.
IF sy-subrc = 0.
lh_font_size = lh_num.
ENDIF.
ENDIF.
WHEN ‘Tm’. » Абсолютное позиционирование 0.99941 0 0 1 85.0795 774.561 Tm (в конце идут X и Y)
lh_lines = LINES( lit_str ).
» Y
lh_lines = lh_lines — 1.
IF lh_lines > 0.
READ TABLE lit_str INDEX lh_lines INTO lh_str.
CALL METHOD try_read_number EXPORTING
pi_number = lh_str
CHANGING
pc_number = lh_num
EXCEPTIONS
INVALID_FORMAT = 1.
IF sy-subrc = 0.
lh_Y = lh_num.
ENDIF.
ENDIF.
» X
lh_lines = lh_lines — 1.
IF lh_lines > 0.
READ TABLE lit_str INDEX lh_lines INTO lh_str.
CALL METHOD try_read_number EXPORTING
pi_number = lh_str
CHANGING
pc_number = lh_num
EXCEPTIONS
INVALID_FORMAT = 1.
IF sy-subrc = 0.
lh_X = lh_num.
ENDIF.
ENDIF.
WHEN ‘Td’. » Позиционирование относительно текущих координат [ -499 63 Td
» X
READ TABLE lit_str INDEX 1 INTO lh_str.
CALL METHOD try_read_number EXPORTING
pi_number = lh_str
CHANGING
pc_number = lh_num
EXCEPTIONS
INVALID_FORMAT = 1.
IF sy-subrc = 0.
lh_X = lh_X + lh_num.
ENDIF.
» Y
READ TABLE lit_str INDEX 2 INTO lh_str.
CALL METHOD try_read_number EXPORTING
pi_number = lh_str
CHANGING
pc_number = lh_num
EXCEPTIONS
INVALID_FORMAT = 1.
IF sy-subrc = 0.
lh_Y = lh_Y + lh_num.
ENDIF.
WHEN ‘Tj’. » Текст [ (AGCO Parts Division) Tj
lh_str = lh_line.
SHIFT lh_str BY 1 PLACES LEFT.
lh_len = strlen( lh_str ).
lh_len = lh_len — 4.
lh_str = lh_str(lh_len).
» Добавляем текстовый элемент
lwa_element-num_page = m_num_pages.
lwa_element-src_file_line = lh_line_num.
lwa_element-X = lh_X.
lwa_element-Y = lh_Y.
lwa_element-font = lh_font.
lwa_element-font_size = lh_font_size.
lwa_element-text = lh_str.
lwa_element-textUcase = lwa_element-text.
TRANSLATE lwa_element-textUcase TO UPPER CASE.
APPEND lwa_element TO mt_elements.
WHEN ‘TJ’. » Другой вид текста [(t)-2.16558(e)3.74(s)-1.22997(t)-2.1653( )]TJ » Это слово test
CLEAR lwa_element-text.
lwa_element-num_page = m_num_pages.
lwa_element-src_file_line = lh_line_num.
lwa_element-X = lh_X.
lwa_element-Y = lh_Y.
lwa_element-font = lh_font.
lwa_element-font_size = lh_font_size.
lh_str = lh_line.
SHIFT lh_str BY 1 PLACES LEFT.
lh_len = strlen( lh_str ).
lh_len = lh_len — 2.
lh_str = lh_str(lh_len).
SHIFT lh_str RIGHT DELETING TRAILING SPACE.
SHIFT lh_str RIGHT DELETING TRAILING ‘]’.
FIND ALL OCCURRENCES OF ‘(‘ IN lh_str RESULTS lit_result.
LOOP AT lit_result INTO lwa_result.
lh_tabix = sy-tabix.
lh_num = lwa_result-offset + 1.
IF lh_tabix < LINES( lit_result ).
lh_tabix = lh_tabix + 1.
READ TABLE lit_result INDEX lh_tabix INTO lwa_result_next.
lh_tabix = lh_tabix — 1.
ELSE.
CLEAR lwa_result_next.
ENDIF.
» Читаем весь текст в скобках, там может быть одна реже несколько букв
lh_text_flag = ‘X’.
CLEAR lh_space_str.
DO.
IF lh_num >= strlen( lh_str ).
EXIT.
ENDIF.
IF lwa_result_next-offset IS NOT INITIAL.
IF lh_num >= lwa_result_next-offset.
EXIT.
ENDIF.
ENDIF.
IF lh_str+lh_num(1) = ‘)’.
CLEAR lh_text_flag.
lh_num = lh_num + 1.
CONTINUE.
ENDIF.
IF lh_text_flag = ‘X’.
CONCATENATE lwa_element-text lh_str+lh_num(1) INTO lwa_element-text RESPECTING BLANKS.
ELSE.
CONCATENATE lh_space_str lh_str+lh_num(1) INTO lh_space_str.
ENDIF.
lh_num = lh_num + 1.
ENDDO.
» Смотрим, удалось ли нам прочитать смещение
IF lh_space_str IS NOT INITIAL.
CLEAR lh_num.
CALL METHOD try_read_number EXPORTING
pi_number = lh_space_str
CHANGING
pc_number = lh_num
EXCEPTIONS
INVALID_FORMAT = 1.
ENDIF.
IF lh_num IS NOT INITIAL.
lh_num = 0 — lh_num / 52. » Движение вправо соответствует отрицательному числу
» Если считаем, что отступ довольно большой, отделяем текстовый элемент
IF lh_num > 7.
lwa_element-textUcase = lwa_element-text.
TRANSLATE lwa_element-textUcase TO UPPER CASE.
APPEND lwa_element TO mt_elements.
CLEAR lwa_element-text.
READ TABLE lit_fonthsize INTO lwa_fonthsize WITH KEY font_size = lh_font_size.
IF sy-subrc <> 0.
lwa_fonthsize-glyth_width = 4.
ENDIF.
» Отступаем на количество уже имеющихся символов в прошлом элементе + отступ
lwa_element-X = lwa_element-X + strlen( lwa_element-text ) * lwa_fonthsize-glyth_width + lh_num.
lwa_element-num_page = m_num_pages.
lwa_element-src_file_line = lh_line_num.
lwa_element-Y = lh_Y.
lwa_element-font = lh_font.
lwa_element-font_size = lh_font_size.
ENDIF.
ENDIF.
ENDLOOP.
lwa_element-textUcase = lwa_element-text.
TRANSLATE lwa_element-textUcase TO UPPER CASE.
APPEND lwa_element TO mt_elements.
ENDCASE.
ENDIF.
ENDIF.
» Если мы внутри блока текста, то отслеживаем его окончание
IF lh_in_obj = ‘X’ AND lh_in_stream = ‘X’ AND lh_in_text = ‘X’
AND lh_line = ‘ET’.
CLEAR lh_in_text.
ENDIF.
» Если мы внутри stream, отслеживаем ее окончание
IF lh_in_obj = ‘X’ AND lh_in_stream = ‘X’ AND lh_in_text <> ‘X’
AND lh_line CP ‘*endstream’.
CLEAR lh_in_stream.
ENDIF.
» Если мы внутри объекта, отслеживаем окончание объекта
IF lh_in_obj = ‘X’ AND lh_in_stream <> ‘X’ AND lh_in_text <> ‘X’
AND lh_line CP ‘*endobj’.
CLEAR lh_in_obj.
ENDIF.
ENDLOOP.
LOOP AT mt_elements INTO lwa_element.
lwa_element-num_element = sy-tabix.
MODIFY mt_elements FROM lwa_element.
ENDLOOP.
» Сортируем, чтобы все текстовые надписи шли сверху вниз и слева направо
SORT mt_elements BY num_page y DESCENDING x num_element.
READ TABLE mt_elements INDEX 1 INTO lwa_element.
lh_min_page = lwa_element-num_page.
lh_lines = LINES( mt_elements ).
READ TABLE mt_elements INDEX lh_lines INTO lwa_element.
lh_max_page = lwa_element-num_page.
m_num_pages = m_num_pages — 1.
» Корректировка номеров страниц, иногда номера сдвигаются на 1 вверх
IF lh_max_page > m_num_pages AND lh_min_page > 1.
lh_num = 1.
ELSE.
lh_num = 0.
ENDIF.
LOOP AT mt_elements INTO lwa_element.
lwa_element-num_element = sy-tabix.
lwa_element-num_page = lwa_element-num_page — lh_num.
MODIFY mt_elements FROM lwa_element.
ENDLOOP.
IF mt_elements[] IS INITIAL.
m_num_pages = 0.
ENDIF.
ENDMETHOD. » METHOD parse
» Возвращает одну или несколько строк в бинарном виде как XSTRING
» Начальный и конечный символ переноса строки не возвращается, однако если он возвращает несколько строк,
» то в середине символы переноса строки не удаляются
METHOD get_lines_as_xstring.
DATA: lwa_result TYPE match_result,
lh_offset TYPE I,
lh_length TYPE I,
lh_index TYPE I.
CLEAR pe_xlines.
» На всякий случай проверка, что параметры адекватные
IF pi_start_line <= 0 OR pi_end_line > LINES( mt_filelines ) OR pi_start_line > pi_end_line.
RETURN.
ENDIF.
IF pi_start_line > 1.
lh_index = pi_start_line — 1.
READ TABLE mt_line_ends INDEX lh_index INTO lwa_result.
lh_offset = lwa_result-offset + lwa_result-length.
ELSE.
lh_offset = 0.
ENDIF.
IF pi_end_line < LINES( mt_filelines ).
READ TABLE mt_line_ends INDEX pi_end_line INTO lwa_result.
lh_length = lwa_result-offset — lh_offset.
ELSE.
lh_length = xstrlen( m_contentx ) — lh_offset + 1.
ENDIF.
pe_xlines = m_contentx+lh_offset(lh_length).
ENDMETHOD.
» Читает число из строки, если неверный формат, то генерит exception
METHOD try_read_number.
DATA: lh_number TYPE STRING.
lh_number = pi_number.
REPLACE ‘,’ IN lh_number WITH ‘.’.
CATCH SYSTEM-EXCEPTIONS
CONVERSION_ERRORS = 1.
pc_number = lh_number.
ENDCATCH.
IF sy-subrc <> 0.
RAISE INVALID_FORMAT.
ENDIF.
ENDMETHOD. » try_read_number
» Возвращает X если PDF загружен и пусто в противном случае
METHOD is_loaded.
IF mt_elements[] IS NOT INITIAL.
pe_loaded = ‘X’.
ELSE.
CLEAR pe_loaded.
ENDIF.
ENDMETHOD. » is_loaded
» Возвращает количество страниц в документе
METHOD get_num_pages.
pe_num_pages = m_num_pages.
ENDMETHOD. » get_num_pages
» Возвращает список всех элементов, отсортированный по страницам, сверху вниз и
» слева направо
METHOD get_all_elements.
pe_elements = mt_elements.
ENDMETHOD. » get_all_elements
» Возвращает элементы, содержащие определенный текст
» pi_num_page — номер страницы, если 0, то искать на всех страницах;
» pi_text — искомый текст;
» pi_match_case — учитывать ли большие-маленькие буквы или искать невзирая на них;
» pe_elements — возвращает список найденных текстовых элементов или пустую таблицу,
» если такой текст не найден.
METHOD find_text.
DATA: lr_page TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-num_page,
lwa_r_page LIKE LINE OF lr_page,
lr_text TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-text,
lwa_r_text LIKE LINE OF lr_text,
lr_textUcase TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-textUcase,
lwa_r_textUcase LIKE LINE OF lr_textUcase,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element,
lh_text TYPE STRING,
lh_index TYPE I.
» Для того, чтобы перебирать только элементы нужной страницы, используется
» отсортированность таблицы mt_elements по номеру страницы
REFRESH pe_elements[].
IF pi_num_page IS NOT INITIAL.
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_num_page.
APPEND lwa_r_page TO lr_page.
READ TABLE mt_elements WITH KEY num_page = pi_num_page TRANSPORTING NO FIELDS.
lh_index = sy-tabix.
ELSE.
lh_index = 1.
ENDIF.
IF pi_text IS NOT INITIAL.
IF pi_match_case = ‘X’.
lwa_r_text-option = ‘EQ’.
lwa_r_text-sign = ‘I’.
lwa_r_text-low = pi_text.
APPEND lwa_r_text TO lr_text.
ELSE.
lh_text = pi_text.
TRANSLATE lh_text TO UPPER CASE.
lwa_r_textUcase-option = ‘EQ’.
lwa_r_textUcase-sign = ‘I’.
lwa_r_textUcase-low = lh_text.
APPEND lwa_r_textUcase TO lr_textUcase.
ENDIF.
ENDIF.
LOOP AT mt_elements INTO lwa_element
FROM lh_index.
«WHERE «num_page IN lr_page
» text IN lr_text
» AND textUcase IN lr_textUcase.
CHECK lwa_element-text IN lr_text
AND lwa_element-textUcase IN lr_textUcase.
IF lwa_element-num_page IN lr_page.
APPEND lwa_element TO pe_elements.
ELSE.
EXIT.
ENDIF.
ENDLOOP.
ENDMETHOD. » find_text
» Возвращает элементы, содержащие определенный текст, который ищется по маске
» pi_num_page — номер страницы, если 0, то искать на всех страницах;
» pi_text — искомый текст или маска для команды CP;
» pi_match_case — учитывать ли большие-маленькие буквы или искать невзирая на них;
» pe_elements — возвращает список найденных текстовых элементов или пустую таблицу,
» если такой текст не найден.
METHOD find_text_by_mask.
DATA: lr_page TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-num_page,
lwa_r_page LIKE LINE OF lr_page,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element,
lh_text TYPE STRING,
lh_index TYPE I.
lh_text = pi_text.
IF pi_match_case IS NOT INITIAL.
TRANSLATE lh_text TO UPPER CASE.
ENDIF.
» Для того, чтобы перебирать только элементы нужной страницы, используется
» отсортированность таблицы mt_elements по номеру страницы
REFRESH pe_elements[].
IF pi_num_page IS NOT INITIAL.
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_num_page.
APPEND lwa_r_page TO lr_page.
READ TABLE mt_elements WITH KEY num_page = pi_num_page TRANSPORTING NO FIELDS.
lh_index = sy-tabix.
ELSE.
lh_index = 1.
ENDIF.
LOOP AT mt_elements INTO lwa_element
FROM lh_index.
IF lwa_element-num_page NOT IN lr_page.
EXIT.
ENDIF.
IF pi_match_case IS NOT INITIAL
AND lwa_element-textUcase CP lh_text.
APPEND lwa_element TO pe_elements.
ELSEIF pi_match_case IS INITIAL
AND lwa_element-text CP lh_text.
APPEND lwa_element TO pe_elements.
ENDIF.
ENDLOOP.
ENDMETHOD. » find_text_by_mask
» Возвращает элементы, находящиеся под данным элементом, сравнивается левый верхний угол
» элемента с левыми верхними углами других элементов на той же странице.
» pi_element — текстовый элемент, под которым нужно искать;
» pi_accuracy — диапазон поиска влево и вправо от координаты X левого верхнего угла
» элемента при сравнении с Х-координатой других элементов;
» pe_elements — найденные элементы.
METHOD find_text_below.
DATA: lr_page TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-num_page,
lwa_r_page LIKE LINE OF lr_page,
lr_X TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-X,
lwa_r_X LIKE LINE OF lr_X,
lr_Y TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-Y,
lwa_r_Y LIKE LINE OF lr_Y,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element.
REFRESH pe_elements[].
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_element-num_page.
APPEND lwa_r_page TO lr_page.
lwa_r_X-option = ‘BT’.
lwa_r_X-sign = ‘I’.
lwa_r_X-low = pi_element-X — pi_accuracy.
lwa_r_X-high = pi_element-X + pi_accuracy.
APPEND lwa_r_X TO lr_X.
lwa_r_Y-option = ‘LT’.
lwa_r_Y-sign = ‘I’.
lwa_r_Y-low = pi_element-Y.
APPEND lwa_r_Y TO lr_Y.
LOOP AT mt_elements INTO lwa_element
FROM pi_element-num_element
WHERE num_page IN lr_page
AND X IN lr_X
AND Y IN lr_Y.
APPEND lwa_element TO pe_elements.
ENDLOOP.
ENDMETHOD. » find_text_below
» Возвращает элементы, находящиеся справа от данного элемента,
» сравнивается левый верхний угол элемента с левыми верхними углами других
» элементов на той же странице.
» pi_element — текстовый элемент, справа от которого нужно искать;
» pi_accuracy — диапазон поиска вниз и вверх от координаты Y левого верхнего угла
» элемента при сравнении с Y-координатой других элементов;
» pe_elements — найденные элементы.
METHOD find_text_right.
DATA: lr_page TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-num_page,
lwa_r_page LIKE LINE OF lr_page,
lr_X TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-X,
lwa_r_X LIKE LINE OF lr_X,
lr_Y TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-Y,
lwa_r_Y LIKE LINE OF lr_Y,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element.
REFRESH pe_elements[].
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_element-num_page.
APPEND lwa_r_page TO lr_page.
lwa_r_X-option = ‘GT’.
lwa_r_X-sign = ‘I’.
lwa_r_X-low = pi_element-X.
APPEND lwa_r_X TO lr_X.
lwa_r_Y-option = ‘BT’.
lwa_r_Y-sign = ‘I’.
lwa_r_Y-low = pi_element-Y — pi_accuracy.
lwa_r_Y-high = pi_element-Y + pi_accuracy.
APPEND lwa_r_Y TO lr_Y.
LOOP AT mt_elements INTO lwa_element
WHERE num_page IN lr_page
AND X IN lr_X
AND Y IN lr_Y.
APPEND lwa_element TO pe_elements.
ENDLOOP.
ENDMETHOD. » find_text_right
» Возвращает элементы, находящиеся внутри прямоугольника на данной странице
METHOD find_text_in_box.
DATA: lr_page TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-num_page,
lwa_r_page LIKE LINE OF lr_page,
lr_X TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-X,
lwa_r_X LIKE LINE OF lr_X,
lr_Y TYPE RANGE OF lcl_pdf_concat_line=>t_text_element-Y,
lwa_r_Y LIKE LINE OF lr_Y,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element,
lh_left TYPE I,
lh_right TYPE I,
lh_top TYPE I,
lh_bottom TYPE I,
lh_num TYPE I.
REFRESH pe_elements[].
lh_left = pi_left.
lh_top = pi_top.
lh_right = pi_right.
lh_bottom = pi_bottom.
IF lh_left > lh_right.
lh_num = lh_left.
lh_left = lh_right.
lh_right = lh_num.
ENDIF.
IF lh_top > lh_bottom.
lh_num = lh_bottom.
lh_bottom = lh_top.
lh_top = lh_num.
ENDIF.
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_num_page.
APPEND lwa_r_page TO lr_page.
lwa_r_X-option = ‘BT’.
lwa_r_X-sign = ‘I’.
lwa_r_X-low = lh_left.
lwa_r_X-high = lh_right.
APPEND lwa_r_X TO lr_X.
lwa_r_Y-option = ‘BT’.
lwa_r_Y-sign = ‘I’.
lwa_r_Y-low = lh_top.
lwa_r_Y-high = lh_bottom.
APPEND lwa_r_Y TO lr_Y.
LOOP AT mt_elements INTO lwa_element
WHERE num_page IN lr_page
AND X IN lr_X
AND Y IN lr_Y.
APPEND lwa_element TO pe_elements.
ENDLOOP.
ENDMETHOD. » find_text_in_box
» Формирует структуры для поиска в целых строках PDF — полезны для поиска
» в файлах неожиданной структуры, например из FineReader
METHOD build_concat_lines.
DATA: lit_elements TYPE TABLE OF lcl_pdf_concat_line=>t_text_element,
lwa_element TYPE lcl_pdf_concat_line=>t_text_element,
lwa_element_last TYPE lcl_pdf_concat_line=>t_text_element,
lwa_concat_text TYPE t_concat_text,
lc_concat_line TYPE REF TO lcl_pdf_concat_line,
lh_num TYPE I,
lh_concat_line_num TYPE I.
REFRESH: m_concat_lines[], m_concat_texts[].
LOOP AT mt_elements INTO lwa_element.
lh_num = abs( lwa_element-Y — lwa_element_last-Y ).
» Если элементы на одной странице примерно на одной высоте,
IF lwa_element-num_page = lwa_element_last-num_page
AND lh_num <= 3.
APPEND lwa_element TO lit_elements.
ELSE.
IF lit_elements[] IS NOT INITIAL.
lh_concat_line_num = lh_concat_line_num + 1.
CREATE OBJECT lc_concat_line EXPORTING
pi_elements = lit_elements
pi_line_num = lh_concat_line_num.
lwa_concat_text-line_num = lh_concat_line_num.
lwa_concat_text-num_page = lwa_element_last-num_page.
lwa_concat_text-Y = lwa_element_last-Y.
lc_concat_line->get_text( IMPORTING pe_text = lwa_concat_text-text ).
lwa_concat_text-text_u = lwa_concat_text-text.
TRANSLATE lwa_concat_text-text_u TO UPPER CASE.
lc_concat_line->get_text_condensed( IMPORTING pe_text = lwa_concat_text-text_cond ).
lwa_concat_text-text_cond_u = lwa_concat_text-text_cond.
TRANSLATE lwa_concat_text-text_cond_u TO UPPER CASE.
APPEND lc_concat_line TO m_concat_lines.
APPEND lwa_concat_text TO m_concat_texts.
REFRESH lit_elements[].
ENDIF.
APPEND lwa_element TO lit_elements[].
ENDIF.
lwa_element_last = lwa_element.
ENDLOOP.
ENDMETHOD. » build_concat_lines
» Находит текст по маске в конкатенированной строке PDF (все текстовые элементы,
» примерно совпадающие по высоте, считаются одной строкой и объединяются в текст)
«
» Удобно для файло с заранее неизвестной и меняющейся структурой, например для
» PDF из Fine Reader-а
«
» Параметры:
» pi_num_page — номер страницы
» pi_text — искомый текст, может содержать маску (ищется по CP)
» pi_match_case — учитывать ли регистр
» pi_condensed — искать ли в тексте без пробелов или с пробелами
» pe_concat_lines — возвращает найденные строки PDF.
METHOD find_text_concat.
DATA: lr_page TYPE RANGE OF I,
lwa_r_page LIKE LINE OF lr_page,
lwa_concat_text TYPE t_concat_text,
lc_concat_line TYPE REF TO lcl_pdf_concat_line,
lh_text TYPE STRING,
lh_text2 TYPE STRING,
lh_index TYPE I,
lh_line_num TYPE I.
REFRESH pe_concat_lines[].
IF m_concat_texts[] IS INITIAL
OR m_concat_lines[] IS INITIAL.
CALL METHOD build_concat_lines( ).
ENDIF.
lh_text = pi_text.
IF pi_match_case IS INITIAL.
TRANSLATE lh_text TO UPPER CASE.
ENDIF.
IF pi_condensed IS NOT INITIAL.
CONDENSE lh_text NO-GAPS.
ENDIF.
IF pi_num_page IS NOT INITIAL.
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_num_page.
APPEND lwa_r_page TO lr_page.
READ TABLE m_concat_texts WITH KEY num_page = pi_num_page TRANSPORTING NO FIELDS BINARY SEARCH.
lh_index = sy-tabix.
ELSE.
lh_index = 1.
ENDIF.
LOOP AT m_concat_texts INTO lwa_concat_text
FROM lh_index.
lh_line_num = sy-tabix.
IF lwa_concat_text-num_page NOT IN lr_page.
EXIT.
ENDIF.
IF pi_match_case IS NOT INITIAL.
IF pi_condensed IS NOT INITIAL.
lh_text2 = lwa_concat_text-text_cond.
ELSE.
lh_text2 = lwa_concat_text-text.
ENDIF.
ELSE.
IF pi_condensed IS NOT INITIAL.
lh_text2 = lwa_concat_text-text_cond_u.
ELSE.
lh_text2 = lwa_concat_text-text_u.
ENDIF.
ENDIF.
IF lh_text2 CP lh_text.
READ TABLE m_concat_lines INDEX lh_line_num INTO lc_concat_line.
APPEND lc_concat_line TO pe_concat_lines.
ENDIF.
ENDLOOP.
ENDMETHOD. » find_text_concat
» Возвращает все конкатенированные строки PDF на определенной странице между координатами
» top и bottom
METHOD find_lines_in_range.
DATA: lr_page TYPE RANGE OF I,
lwa_r_page LIKE LINE OF lr_page,
lr_Y TYPE RANGE OF I,
lwa_r_Y LIKE LINE OF lr_Y,
lc_concat_line TYPE REF TO lcl_pdf_concat_line,
lwa_concat_text TYPE t_concat_text,
lh_index TYPE I,
lh_line_num TYPE I,
lh_top TYPE I,
lh_bottom TYPE I,
lh_num TYPE I.
REFRESH pe_concat_lines[].
IF m_concat_texts[] IS INITIAL
OR m_concat_lines[] IS INITIAL.
CALL METHOD build_concat_lines( ).
ENDIF.
lh_top = pi_top.
lh_bottom = pi_bottom.
IF lh_bottom > lh_top.
lh_num = lh_bottom.
lh_bottom = lh_top.
lh_top = lh_num.
ENDIF.
IF pi_num_page IS NOT INITIAL.
lwa_r_page-option = ‘EQ’.
lwa_r_page-sign = ‘I’.
lwa_r_page-low = pi_num_page.
APPEND lwa_r_page TO lr_page.
READ TABLE m_concat_texts WITH KEY num_page = pi_num_page TRANSPORTING NO FIELDS BINARY SEARCH.
lh_index = sy-tabix.
ELSE.
lh_index = 1.
ENDIF.
lwa_r_Y-option = ‘BT’.
lwa_r_Y-sign = ‘I’.
lwa_r_Y-low = lh_bottom.
lwa_r_Y-high = lh_top.
APPEND lwa_r_Y TO lr_Y.
LOOP AT m_concat_texts INTO lwa_concat_text
FROM lh_index
WHERE Y IN lr_Y
AND num_page IN lr_page.
lh_line_num = sy-tabix.
READ TABLE m_concat_lines INDEX lh_line_num INTO lc_concat_line.
APPEND lc_concat_line TO pe_concat_lines.
ENDLOOP.
ENDMETHOD. » find_lines_in_range
» Возвращает следующую конкатенированную строку, если следующей строки нет, то
» неприсвоенный объект
» pi_ignore_page — искать ли только на той же странице или можно переходить и на
» следующую
METHOD find_next_concat_line.
DATA: lc_concat_line TYPE REF TO lcl_pdf_concat_line,
lwa_concat_text TYPE t_concat_text,
lwa_concat_text_next TYPE t_concat_text,
lh_line_num TYPE I,
lh_line_num_next TYPE I.
IF pe_concat_line_next IS BOUND.
FREE pe_concat_line_next.
ENDIF.
IF pi_concat_line IS NOT BOUND.
RETURN.
ENDIF.
CALL METHOD pi_concat_line->get_line_num( IMPORTING pe_line_num = lh_line_num ).
lh_line_num_next = lh_line_num + 1.
IF lh_line_num_next > LINES( m_concat_lines ).
RETURN.
ENDIF.
READ TABLE m_concat_lines INDEX lh_line_num_next INTO lc_concat_line.
IF pi_ignore_page IS INITIAL.
READ TABLE m_concat_texts INDEX lh_line_num INTO lwa_concat_text.
READ TABLE m_concat_texts INDEX lh_line_num_next INTO lwa_concat_text_next.
IF lwa_concat_text_next-num_page <> lwa_concat_text-num_page.
RETURN.
ENDIF.
ENDIF.
pe_concat_line_next = lc_concat_line.
ENDMETHOD. » find_next_concat_line
ENDCLASS.
Related searches
- fm to convert pdf into word in abap
- sap adobe convert pdf to word
- sap abap convert pdf to tiff
- sap abap convert dbf to pdf
- sap abap convert pdf to text
- sap abap convert pdf to graphics
Sap Abap Convert Pdf Spool To Word
at Software Informer
Office Convert Pdf to Word for Doc lets you convert PDF files to Word documents.
Office Convert Pdf to Word for … converting PDF documents to MS Word … supports converting PDF documents
Pdf to Word Soft, Inc.
279
Shareware
The program is designed to convert Pdf file to Word (doc).
Pdf to Word Soft, Inc.
126
Shareware
It converts Word (Doc) and Excel (Xls) from Pdf files.
More Sap Abap Convert Pdf Spool To Word
Sap Abap Convert Pdf Spool To Word in introduction
Convertpdftoword.net
323
Shareware
A tool which function is to convert PDF documents into MS Word (DOC) files.
3
SharpNight
1,915
Shareware
Convert PDF documents to formats compatible with Microsoft Word.
Convert Pdf to Word,Inc.
16
Shareware
Convert Pdf to Word is a professional conversion tool.
124
Hellopdf Inc.
112,710
Freeware
This application allows you to convert your PDF files to word doc for free.
Tweak PDF
449
Shareware
Tweak PDF To Word allows you to convert any PDF file to DOC format.
25
Nemo PDF
3,736
Freeware
Nemo PDF To Word helps you convert any PDF file to Word format.
Additional titles, containing sap abap convert pdf spool to word
99
AAAPDF, Inc
7
PDF to Word Batch Converter, convert PDF to Word DOC RTF.
10
BravoPDF Co., Ltd.
17
Freeware
Bravo Free PDF to Word Converter allows you to convert PDF to Word documents.
1
UniPDF.com
Freeware
100% Free PDF to Word converter software to convert PDF to Word in batch mode.
5
Dawningsoft Inc
45
PDF Conversion Series — PDF2Word can help you to convert pdf to word.
3DPageFlip Software Co., Ltd.
1
Freeware
It is a 4-in-1 PDF converter to convert PDF to Word, Flash, PowerPoint, Images.
1
PDF Helper
432
Shareware
PDF to DOC is used to convert PDF to Word (.doc) or WordPad (.rtf) documents.
75
MicroPDF, Inc.
20
Shareware
Convert PDF to Word (PDF to DOC) with high quality.
11
PDFtoX Co., Ltd.
22
Freeware
One-stop PDF converter to convert PDF to Word, Excel, HTML & many image formats.
80
PDFBat Corporation.
4
Shareware
Fast and easily convert PDF to Word (PDF to DOC) with high quality.
25
PDFFab Software, Inc.
4
Shareware
Freely convert PDF to Word (PDF to DOC) with excellent quality.
How to Convert PDF to Word, Excel, Images — How to Rotate, Cut & Merge PDF Files, and Convert JPG to PDF — PDFZilla Tutorial
Convert PDF to Word, Free Online PDF to Word Converter _ Foxit Software
1
GoogleChrome
4
Сконвертируйте ваши pdf-файлы в doc онлайн и бесплатно
Перетащите файлы сюда. 100 MB максимальный размер файла или Регистрация
Конвертировать в PDF
Портативный формат документов
PDF ― это формат электронных документов, разработанный Adobe Systems с использованием некоторых функций языка PostScript. Официальная программа для просмотра документов в этом формате ― это Adobe Reader. Чаще всего PDF-файл представляет собой сочетание текста с растровой и векторной графикой, текстовыми формами, скриптами, написанными на JavaScript, а также иными элементами.
Конвертер DOC
doc
Документ Microsoft Word
DOC ― это расширение файлов для документов текстового редактора. Оно связано преимущественно с приложением Microsoft Word. Файлы DOC также могут содержать графики, таблицы, видео, изображения, звуки и диаграммы. Этот формат поддерживается почти всеми операционными системами.
Как сконвертировать PDF в DOC
Шаг 1
Загрузите pdf-файл(ы)
Выберите файлы с компьютера, Google Диска, Dropbox, по ссылке или перетащив их на страницу.
Шаг 2
Выберите «в doc»
Выберите doc или любой другой формат, который вам нужен (более 200 поддерживаемых форматов)
Шаг 3
Загрузите ваш doc-файл
Позвольте файлу сконвертироваться и вы сразу сможете скачать ваш doc-файл
Рейтинг PDF в DOC
4.5 (637,606 голосов)
Вам необходимо сконвертировать и скачать любой файл, чтобы оценить конвертацию!
Convert PDF to Word document (.docx, .doc)
Loading PDF Editor, Please Wait …
What is PDF to Word ?
PDF to word is a free online tool to convert PDF to word documents (.docx, .doc). If you are looking for PDF to docx, PDF to doc, or pdf2word, then this is your tool. With PDF to word online tool, you can quickly and easily convert PDF files into msword documents.
How to PDF to Word ?
This video will show in detail how to PDF to word.
This site uses cookies to ensure best user experience. By using the site, you consent to our Cookie, Privacy, Terms