Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Translate using variable via pattern

hagit
Active Participant
0 Likes
7,580

Hello experts

I use CONVERT_ABAPSPOOLJOB_2_PDF in order to convert ABAP spool to PDF. After that I Transfer the 132-long strings to 255-long strings with the translate command.

When writing:

TRANSLATE ls_pdf_output USING ' ~'.

Then when opening the pdf Sometimes it is OK but sometimes I receive an error message 'CANNOT EXTRACT THE EMBEDDED FONT…'

When writing:

DATA: lv_translate_str TYPE string VALUE ' ~'

TRANSLATE ls_pdf_output USING lv_translate_str.

Then when opening the pdf, until now It was always ok.

Thanks in advance

Hagit

FORM convert_spool_to_pdf
USING pv_job_id TYPE tsp01-rqident
CHANGING pt_mess_att TYPE esy_tt_solisti1
.

CONSTANTS: lc_no(1) TYPE c VALUE ' '
,lc_device(4) TYPE c VALUE 'LOCL'
.

DATA: lt_pdf_output TYPE TABLE OF tline
,lv_buffer TYPE string
,ls_mess_att TYPE solisti1 "like line of pt_mess_att
.

CALL FUNCTION 'CONVERT_ABAPSPOOLJOB_2_PDF'
EXPORTING
src_spoolid = pv_job_id
no_dialog = lc_no
dst_device = lc_device
* IMPORTING
* pdf_bytecount =
TABLES
pdf = lt_pdf_output
EXCEPTIONS
err_no_abap_spooljob = 1
err_no_spooljob = 2
err_no_permission = 3
err_conv_not_possible = 4
err_bad_destdevice = 5
user_cancelled = 6
err_spoolerror = 7
err_temseerror = 8
err_btcjob_open_failed = 9
err_btcjob_submit_failed = 10
err_btcjob_close_failed = 11
OTHERS = 12.
IF sy-subrc <> 0.
RAISE no_conv2pdf.
ELSE.
DATA: lv_translate_str TYPE string VALUE ' ~'
,lv_translate_back_str TYPE string VALUE '~ '
.

* Transfer the 132-long strings to 255-long strings
LOOP AT lt_pdf_output INTO DATA(ls_pdf_output).
* TRANSLATE ls_pdf_output USING ' ~'.
TRANSLATE ls_pdf_output USING lv_translate_str.
CONCATENATE lv_buffer ls_pdf_output INTO lv_buffer.
ENDLOOP.

* TRANSLATE lv_buffer USING '~ '.
TRANSLATE lv_buffer USING lv_translate_back_str.

DO.
ls_mess_att = lv_buffer.
APPEND ls_mess_att TO pt_mess_att.
SHIFT lv_buffer LEFT BY 255 PLACES.
IF lv_buffer IS INITIAL.
EXIT.
ENDIF.
ENDDO.
ENDIF.


ENDFORM. "convert_spool_to_pdf
1 ACCEPTED SOLUTION
Read only

Sandra_Rossi
Active Contributor
6,696
DATA lv_translate_back_str TYPE string VALUE '~ '.
TRANSLATE lv_buffer USING lv_translate_back_str.

is different from

TRANSLATE lv_buffer USING '~ '.

because, as explained in the ABAP documentation of TRANSLATE:

  • "Trailing blanks in data objects text and mask are respected for data objects": in the second case, the trailing blank is there, so all ~ of lv_buffer are replaced with spaces.
  • "If mask contains an odd number of characters, the last character is ignored": in the DATA statement of the first case, the trailing space of the value '~ ' (which is of type C and length 2, because it's defined using straight/regular quotes) is ignored and the string is finally made of only one character (tilde ~), consequently TRANSLATE will not replace ~ because it's ignored as it's the last character of the mask with an odd number of characters (1).

Solution: to make the two forms equivalent, define the two characters as a STRING of 2 characters, by using back quotes, the trailing space will be kept during the assignment:

DATA lv_translate_back_str TYPE string VALUE `~ `.

PS: what I said is not related to PDF, it's intrinsic to ABAP. Concerning CONCATENATE, you may use the addition RESPECTING BLANKS instead of this TRANSLATE trick to keep blanks which is very dangerous because the PDF may contain tildes before use of TRANSLATE, and guess what happens...

18 REPLIES 18
Read only

Sandra_Rossi
Active Contributor
6,697
DATA lv_translate_back_str TYPE string VALUE '~ '.
TRANSLATE lv_buffer USING lv_translate_back_str.

is different from

TRANSLATE lv_buffer USING '~ '.

because, as explained in the ABAP documentation of TRANSLATE:

  • "Trailing blanks in data objects text and mask are respected for data objects": in the second case, the trailing blank is there, so all ~ of lv_buffer are replaced with spaces.
  • "If mask contains an odd number of characters, the last character is ignored": in the DATA statement of the first case, the trailing space of the value '~ ' (which is of type C and length 2, because it's defined using straight/regular quotes) is ignored and the string is finally made of only one character (tilde ~), consequently TRANSLATE will not replace ~ because it's ignored as it's the last character of the mask with an odd number of characters (1).

Solution: to make the two forms equivalent, define the two characters as a STRING of 2 characters, by using back quotes, the trailing space will be kept during the assignment:

DATA lv_translate_back_str TYPE string VALUE `~ `.

PS: what I said is not related to PDF, it's intrinsic to ABAP. Concerning CONCATENATE, you may use the addition RESPECTING BLANKS instead of this TRANSLATE trick to keep blanks which is very dangerous because the PDF may contain tildes before use of TRANSLATE, and guess what happens...

Read only

hagit
Active Participant
0 Likes
6,696

sandra.rossi ,

Thanks for your perfect explanation.

In all the examples which I found in the web, translate was used.

Is the previous code equivalent to the code below?

IF sy-subrc <> 0.
RAISE no_conv2pdf.
ELSE.
* DATA: lv_translate_str TYPE string VALUE ' ~'
*           ,lv_translate_back_str TYPE string VALUE `~ `
** ,lv_translate_back_str TYPE string VALUE '~ ' .
* Transfer the 132-long strings to 255-long strings
LOOP AT lt_pdf_output INTO DATA(ls_pdf_output).
** TRANSLATE ls_pdf_output USING ' ~'.
* TRANSLATE ls_pdf_output USING lv_translate_str.
* CONCATENATE lv_buffer ls_pdf_output INTO lv_buffer.
CONCATENATE lv_buffer ls_pdf_output INTO lv_buffer RESPECTING BLANKS.
ENDLOOP.
** TRANSLATE lv_buffer USING '~ '.
* TRANSLATE lv_buffer USING lv_translate_back_str.
DO.
 ls_mess_att = lv_buffer.
APPEND ls_mess_att TO pt_mess_att.
SHIFT lv_buffer LEFT BY 255 PLACES.
IF lv_buffer IS INITIAL.
EXIT.
ENDIF.
ENDDO.
ENDIF.

Thanks

Hagit

Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

Please use button COMMENT. The button ANSWER is for proposing a solution.

Yes, you're correct.

Your code:

LOOP AT lt_pdf_output INTO DATA(ls_pdf_output).
  TRANSLATE ls_pdf_output USING ' ~'.
  CONCATENATE lv_buffer ls_pdf_output INTO lv_buffer.
ENDLOOP.
TRANSLATE lv_buffer USING '~ '.

is equivalent to:

LOOP AT lt_pdf_output INTO DATA(ls_pdf_output).
  CONCATENATE lv_buffer ls_pdf_output INTO lv_buffer RESPECTING BLANKS.
ENDLOOP.

and is equivalent to:

CONCATENATE LINES OF lt_pdf_output INTO lv_buffer RESPECTING BLANKS.

By the way, if I'm not wrong, your final code can be changed to:

pt_mess_att = cl_bcs_convert=>string_to_soli( lv_buffer ).

PS: LINES OF and RESPECTING BLANKS appeared in ABAP 7.0, in 2005.

Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

And most importantly, you must absolutely use the parameter pdf_bytecount to trim the extra bytes.

The problem of your code is that you only deal with characters, you must cast the characters into bytes, then you can trim the extra bytes.

In the end, your code attaches the PDF to "somewhere", and that must be done with bytes, NOT with characters. If you do it with characters, you will probably have problems.

Read only

hagit
Active Participant
0 Likes
6,696
  1. Thanks for your answer, which is not just an answer, but also improves the code
  2. Is CONCATENATE LINES OF ... faster than a loop?
  3. How should I use the returning parameter PDF_BYTECOUNT?
Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

2. As a rule-of-thumb, any one-statement is faster than the equivalent ABAP code in several lines

3. Use PDF_BYTECOUNT as I explained. But I can't give additional clues as you don't explain what you do with the PDF (formal parameter pt_mess_att) in the end.

Read only

hagit
Active Participant
0 Likes
6,696

3. At the end I send the pdf as an attachment in the mail.

FORM send_file_as_email_attachment TABLES it_message
it_attachUSING p_email
pv_mail_subject
p_format
p_filename
p_attdescription
p_sender_address
p_sender_addres_typeCHANGING p_reciever.

DATA: ld_mtitle LIKE sodocchgi1-obj_descr,
ld_email LIKE somlreci1-receiver,
ld_format TYPE so_obj_tp,
ld_attdescription TYPE so_obj_nam,
ld_attfilename TYPE so_obj_des,
ld_sender_address LIKE soextreci1-receiver,
ld_sender_address_type LIKE soextreci1-adr_typ,
ld_receiver LIKE sy-subrc.
DATA: t_packing_list LIKE sopcklsti1 OCCURS 0 WITH HEADER LINE,
t_contents LIKE solisti1 OCCURS 0 WITH HEADER LINE,
t_receivers LIKE somlreci1 OCCURS 0 WITH HEADER LINE,
t_attachment LIKE solisti1 OCCURS 0 WITH HEADER LINE,
t_object_header LIKE solisti1 OCCURS 0 WITH HEADER LINE,
w_cnt TYPE i,
w_sent_all(1) TYPE c,
w_doc_data LIKE sodocchgi1.


ld_email = p_email.
ld_mtitle = pv_mail_subject.
ld_format = p_format.
ld_attdescription = p_attdescription.
ld_attfilename = p_filename.
ld_sender_address = p_sender_address.
ld_sender_address_type = p_sender_addres_type.

* Fill the document data.
w_doc_data-doc_size = 1.
* Populate the subject/generic message attributes
w_doc_data-obj_langu = sy-langu.
w_doc_data-obj_name = 'SAPRPT'.
w_doc_data-obj_descr = ld_mtitle .
w_doc_data-sensitivty = 'F'.
* Fill the document data and get size of attachmentCLEAR w_doc_data.READ TABLE it_attach INDEX w_cnt.
w_doc_data-doc_size =( w_cnt - 1 ) * 255 + strlen( it_attach ).
w_doc_data-obj_langu = sy-langu.
w_doc_data-obj_name = 'SAPRPT'.
w_doc_data-obj_descr = ld_mtitle.
w_doc_data-sensitivty = 'F'.CLEAR t_attachment.REFRESH t_attachment.
t_attachment[] = it_attach[].
* Describe the body of the messageCLEAR t_packing_list.REFRESH t_packing_list.
t_packing_list-transf_bin = space.
t_packing_list-head_start = 1.
t_packing_list-head_num = 0.
t_packing_list-body_start = 1.DESCRIBE TABLE it_message LINES t_packing_list-body_num.
t_packing_list-doc_type = 'RAW'.APPEND t_packing_list.
* Create attachment notification
t_packing_list-transf_bin = 'X'.
t_packing_list-head_start = 1.
t_packing_list-head_num = 1.
t_packing_list-body_start = 1.
DESCRIBE TABLE t_attachment LINES t_packing_list-body_num.
t_packing_list-doc_type = ld_format.
t_packing_list-obj_descr = ld_attdescription.
t_packing_list-obj_name = ld_attfilename.
t_packing_list-doc_size = t_packing_list-body_num * 255.APPEND t_packing_list.
* Add the recipients email addressCLEAR t_receivers.REFRESH t_receivers.
t_receivers-receiver = ld_email.
t_receivers-rec_type = 'U'.
t_receivers-com_type = 'INT'.
t_receivers-notif_del = 'X'.
t_receivers-notif_ndel = 'X'.APPEND t_receivers.
CALL FUNCTION 'SO_DOCUMENT_SEND_API1'EXPORTING
document_data = w_doc_data
put_in_outbox = 'X'
sender_address = ld_sender_address
sender_address_type = ld_sender_address_type
commit_work = 'X'IMPORTING
sent_to_all = w_sent_allTABLES
packing_list = t_packing_list
contents_bin = t_attachment
contents_txt = it_message
receivers = t_receiversEXCEPTIONS
too_many_receivers = 1
document_not_sent = 2
document_type_not_exist = 3
operation_no_authorization = 4
parameter_error = 5
x_error = 6
enqueue_error = 7OTHERS = 8.IF sy-subrc <> 0.RAISE document_send_api1.ENDIF.
* Populate zreceiver return codeLOOP AT t_receivers.
ld_receiver = t_receivers-retrn_code.ENDLOOP.ENDFORM. "send_file_as_email_attachment

4. I have 3 PDF's file in various size. But the value of lv_pdf_bytecount parameter is always 79879. Can you explain in more detail how can I use this parameter?

Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

SO_DOCUMENT_SEND_API1 is obsolete, but as you already use it, and it works most of the time, maybe you prefer just to do this change:

Replace:

t_packing_list-doc_size = t_packing_list-body_num * 255.

with:

t_packing_list-doc_size = pdf_bytecount.

NB: maybe in your current case it's 79879 bytes, but it can't be always the same size as the PDF contents will vary.

Read only

hagit
Active Participant
0 Likes
6,696

1. SO_DOCUMENT_SEND_API1 is obsolete- What is new?

2. When looking at job log overview I see different sizes. But in debugging the value is always 79879

Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

1. Use CL_BCS (not very new by the way, must be since 2001)

2. You must have a bug in your program. Are you sure you pass the right spool number to CONVERT_ABAPSPOOLJOB_2_PDF at each loop? Do you store correctly the value of PDF_BYTECOUNT for each spool?

Read only

hagit
Active Participant
0 Likes
6,696

2. In debug mode (by jdbg in SM37) the value of pv_job_id is always 2602 and lv_bytecount is always 79879. It is very strange because the PDF files are different, which suggests that spool id is different in every call to 'CONVERT_ABAPSPOOLJOB_2_PDF'

Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

That explains why.

Did you find out why you called convert_spool_to_pdf three times with the same spool ID as argument?

Read only

hagit
Active Participant
0 Likes
6,696

It is strange. In the debug it shows the same spool id , but it can not be the same spool id because the 3 PDF files are different.

Read only

hagit
Active Participant
0 Likes
6,696

a.txt

As you can see in the attached file:

1. The main loop calls c_alv_and_mail_it

2. c_alv_and_mail_it creates the ALV and calls alv2pdf_and_mail_it

3. alv2pdf_and_mail_it calls FUNCTION 'ZALV2PDF_AND_MAIL_IT

4. in FUNCTION 'ZALV2PDF_AND_MAIL_IT - if it is batch

4.1 Calls get_job_details, which returns jobcount, jobname, stepcount by calling FUNCTION 'GET_JOB_RUNTIME_INFO'

4.2 Calls get_batch_job_id_in_spool, which returns the spool id by selecting from

tbtcp

4.3 Calls convert_spool_to_pdf, which calls CONVERT_ABAPSPOOLJOB_2_PDF with the parameter spool id

Read only

hagit
Active Participant
0 Likes
6,696

Hi Sandra,

The main issue 'Translate using variable via pattern' was solved, so I want to reward points. How do I reward?

Hagit
Read only

Sandra_Rossi
Active Contributor
0 Likes
6,696

Thanks for the feedback. If you want to "reward" me, continue following the Rules of Engagement of SAP Community. Upvote the answers that help or downvote those which don't help, choose the "Best Answer" (button "Accept", as currently done), close the question with the right reason. Thank you!

Read only

hagit
Active Participant
0 Likes
6,696

I looked at Rules of Engagement but did not find any reference how to reward points.

Can you explain in more details what should I do in order to reward points? In some links I saw that a star should appears next to the answer in order to reward. But I do not see any star

Read only

hagit
Active Participant
0 Likes
6,696

What do you mean by "Upvote the answers that help or downvote those which don't help" Do you mean just click on the arrow (yellow)? The maximum that I can give is 2. Is this what you mean? And after that I just have to close the thread?