Friday, December 31, 2010

SAP: Generate Barcodes with a web service to use in Excel.....demo

Ok I am in the middle of a post to the SAP SDN site covering my recent activity with the Barcode Writer in Pure Postscript and SAP. Its not complete yet and I will see when I submit it...

This Excel demo will not be in the SDN post however how its done in SAP will be covered.
Anyway its not complicated and its still in demo stages as I still want to cover a bit more in the conversion from postscript to the image used in SAP/Excel.

Any comments welcome and any ideas about postscript to gif/bmp/jpg conversion also appreciated!

The video shows how to get the barcode into excel depending on cell values. I then change the scale in the backend BSP to increase the size of the barcode, the video was done with camstudio and directly uploaded to YouTube. No soundtrack on this video as its only a demo. Also sorry to shout but you will need to view it in FULL SCREEN - the icon bottom right of the video.

I will be posting more later but off for a holiday so will pick it all up later. Happy New Year.

Sunday, December 19, 2010

SAP: Configure CutePDF writer to permanently include Barcode Writer in Pure Postscript

CutePDF's part in Barcodes in SAP with the Barcode writer in Pure Postscript.

Previously I had blogged about 26 barcodes on one page with scripts based around Redmon, Microsoft services for Unix and Ghostscript.

Well Cutepdf allows the PDF call to be configured in a setup.ini file, so I can bypass Redmon and Microsoft services for Unix in the following way.

The install directory for CutePDF on my XP system  (my ghostscript version is 8.64)

C:\Program Files\Acro Software\CutePDF Writer

Here create a setup.ini file with the following contents
Command="C:\Program Files\gs\gs8.64\bin\gswin32c.exe"
Arguments=-q -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile="%1" "C:\Program Files\Acro Software\CutePDF Writer\" -
(as its blogger again with formatting code sections, the Arguments parameter is ONE line and ends with - character)

The arguments line includes the postscript so this file needs to be placed in the same directory. This does mean that every call to the cutepdf printer would merge with every printout.

Here is a screen shot of my setup.

I have not tested all parts only the ABAP list and sapscript. My previous experience of trying to merge postscript files was not so successful. However, so far it works every time.

Saturday, December 18, 2010

SAP: 26 different barcodes on a page with 1 ABAP report for FREE

So why have 26 different barcodes on one page with one ABAP report?

It's basically to demonstrate another way to use the Barcode Writer in Pure Postscript with SAP. Check out the BWIPP to see all the barcodes it supports.

My previous blogs have demonstrated integrating the BWIPP code for one barcode into a device type. This link demonstrates the approach using QR codes. Check out my SDN blog covering the technical detail.

However the method I will cover here requires some simple scripting to integrate the BWIPP into the SAP output stream for further processing at the desktop/printer. The following screen shot is the final result.

Windows XP Desktop Method - PDF

Steps involved
1) Download the BWIPP here
2) SAP Device types/output device and ABAP code 
3) Ghostscript ( I used version 8.64 for this demo)
4) Redmon (it can be found on the general ghostscript link above aswell)
5) Microsoft Service for Unix*
6) Final step run the ABAP code.

*As I used Solaris to develop the scripts on a Unix system I use the Unix based commands to integrate the BWIPP on windows. After reading the detail you may be able to help me out and suggest another method, I would like to hear about any other suggestions.

Extract the zipfile and the file should be placed in the ghostscript bin directory that is covered later.

2) SAP Device type
The SAP Device type this time only sets up the postscript code to call the barcode. Therefore the insertion of the at the desktop/printer is essential.

SAP Device Type here ZBWIPP  (Filename = ZBWIPP.PRI)
SAP Output Device ZBWIPP_ALL (Filename = ZBWIPP_ALL)

Download all 3 files in a zip file here

Follow the QRcode guide but import the above files into SAP at the appropriate place.

The Output device will be ZBWIPP_ALL
The device type will be ZBWIPP
and the ABAP code is called ZBWIPP_PRINT
### 17-Jan-2011 update
### Due to a change in the barcode writer in pure postscript then the ZBWIPP device type
### needs to be updated. Read about the BWIPP change in the link to the BWIPP mailing list
So the following printer controls need to be changed ZBW26 ZBW27 and ZBW28
text for the 3 barcodes below starting from ZBW26
zbst\n/zzbc (databaromni) def\nbct sqrd\nzben\n
zbst\n/zzbc (databarexpanded) def\nbct sqrd\nzben\n
zbst\n/zzbc (databarlimited) def\nbct sqrd\nzben\n

3) Ghostscript is required to process the postscript file and create the PDF. The rest of the scripts will be placed in the bin directory of the ghostscript install.

4) REDMON is required for XP to create a printer in XP that SAPLPD can use. The scripts run with REDMON will integrate the BWIPP into the SAP output stream and call ghostscript to produce the final PDF.

This is the guide for a virtual postscript printer that I modified in the following way

Its IMPORTANT again to match the SAP printer name with the desktop printer. The name has to be the following "qrcodeport" (obviously if you know what your doing you can change it and you can see the qrcode origins of all of this :)

Basically the call to the printer is not made, so only one REDMON printer port is setup and the script called is PBWIPP.BAT as shown here

Script for REDMON


cat - > "C:\Program Files\gs\gs8.64\bin\"
cd "C:\Program Files\gs\gs8.64\bin\"

5) Microsoft Services for UNIX.
Now as my background is in UNIX then I used UNIX scripts for the Windows install. If you think there could be a better way then I would be happy to hear about any suggestions.
* I have found another way that bypasses both Redmon and Microsoft Service for Unix here. needs to exist in the bin directory, its best to remove the very first line.

Script should be placed again in the ghostscript bin directory.

export PATH=$PATH:/dev/fs/C/"Program Files"/gs/gs8.64/bin/:/dev/fs/C/"Program Files"/gs/gs8.64/lib/

cd /dev/fs/C/"Program Files"/gs/gs8.64/bin

#move the SAP postscript input to one side
cat $1 >$$

#insert Postscript
sed '/INSERTBARCODE/ r' <$$ >     $$
mv $$ $$

gswin32c.exe -q -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=ghost$$.pdf  $$

runwin32  start acrord32.exe "c:\program files\gs\gs8.64\bin\ghost$$.pdf"

rm -f $$
rm -f

6) Final step run the ABAP code.
From transaction se38 run the ABAP code created earlier.
Its IMPORTANT to select the following options for page format X_65_80 and print immediately.

and the final PDF should appear in the bin directory.

NOW as it is all based on device type print controls then all the above can be used in SMARTFORMS or SAPSCRIPT.
As per the following youtube video but there is no need to change printers if the above method is used...

Printer Control Barcode Postscript code
ZBW02 qrcode
ZBW03 datamatrix
ZBW04 azteccode
ZBW05 maxicode
ZBW06 auspost
ZBW07 code11
ZBW08 code128
ZBW09 code2of5
ZBW10 code39
ZBW11 code93
ZBW12 ean13
ZBW13 ean8
ZBW14 interleaved2of5
ZBW15 isbn
ZBW16 japanpost
ZBW17 kix
ZBW18 msi
ZBW19 onecode
ZBW20 pdf417
ZBW21 pharmacode
ZBW22 plessey
ZBW23 postnet
ZBW24 rationalizedCodabar
ZBW25 royalmail
ZBW26 rss14
ZBW27 rssexpanded
ZBW28 rsslimited
ZBW29 upca
ZBW30 upce
ZBW31 leitcode
ZBW32 hibccode128
ZBW33 hibccode39
ZOP01 /bcopt (parse) def\n
ZOP02 /bcopt (raw) def\n
ZOP03 /bcopt (includetext) def\n
ZOP04 /bcopt (includecheck includetext) def\n
ZOP05 /bcopt (format=truncated) def\n
ZOP06 /bcopt (format=stacked) def\n

Sunday, December 12, 2010

Free: Countries of the world in a Polygon KML file

Countries of the world KML file, download for free and it can be use for any purpose, the file is a KML polygon file of  the countries in the world in the Natural Earth datasets.

Download : WorldPoly file

I generated the file with SAP ABAP which reads the Natural Earth country shapefile in my geoserver in the clouds. More about this later.

The country ISO codes were used to colour by region  from the UN site here

*The Natural Earth Dataset has French Guiana  with the ISO code for France. The ABAP code reads the ISO code to determine the colour of the polygon. More thematic mapping to come.

Looks  like this in Google Earth

and looks like this in arcgis explorer

RAW Version

I used geoserver to produce the KML shown above.

A blog about my adventures into GEO/KML and SAP can be found on the SDN site here.

The raw file is shown in Google maps below and can be downloaded here

The main difference between the world poly file and the raw file is in the XML markup and colours found in the KML.

The RAW kml file is produced by geoserver containing the ISO codes of the countries. My ABAP program generated the polygon colours based on UN data for the world poly KML file.

Google maps will stop supporting external KML in February 2015

So I have taken a static screen shot to show the differences between the two KML files below.

Saturday, December 11, 2010

SAP: cURLing a BSP through GuiXT

Following on from my post about cURLing a google static map then I did follow up with a yahoo based method.

The reasons to try another way to get a map onto a SAP screen was to test out BSP, REST based Yahoo service and to learn more about SAP.

Why Yahoo and not Google? In my opnion Google does have better maps particularly Japan, however reading "terms of use" and at one time it appeared that Yahoo would allow free use. I have not studied the terms of use in detail recently however its not as free as I would like! However I completed the Yahoo based way.

cURLing through a proxy
cURL does allow you to follow redirection (-L option) however I hit a proxy issue where the local SAP server was accessible with a direct connection but the yahoo service required a proxy connection. This is were I failed to get cURL to work.

So I found my work around

Setup the BSP to cache the yahoo image in SAP, to allow direct cURL download.

BSP to Use Yahoo's Static Map API

I created a BSP in se80 called ZJZIP and eventually ended up with these page attributes for the main map.htm page.

Error Handling

The google static map example I posted earlier does not allow much error checking for the image. As this example is a BSP I checked the Yahoo API xml for any errors. The simple transformation used, which appears later, returns either the URL for the image or an error code. Therefore I added an error.gif to the MIME section of the BSP.

The layout of the BSP would appear in se80 as follows.

So onto the Event Handler OnInitilization code

navigation->set_parameter( 'postcode' ).
navigation->set_parameter( 'height' ).
navigation->set_parameter( 'width' ).
navigation->set_parameter( 'zoom' ).
navigation->set_parameter( 'out' ).
if postcode is initial.
  postcode = 'b904su'.
if height is initial.
  height = '200'.
if width is initial.
  width = '200'.
if zoom is initial.
  zoom = '5'.
if out is initial.
  out = 'gif'.
DATA: pict_url type string,
      error_msg type string.
DATA err_url type string.
      urlstub TYPE STRING,
      urlstub1 type string,
      urlstub2 type string,
      urlstub3 type string,
      urlstub4 type string,
      urlstub5 type string,
      http_client TYPE REF TO IF_HTTP_CLIENT,
      return_code TYPE I,
       p_filnam type string,
      content TYPE STRING.
urlstub = ''.
urlstub1 = '&image_type='.
urlstub2 = '&image_height='.
urlstub3 = '&image_width='.
urlstub4 = '&zoom='.
urlstub5 = '&zip='.
concatenate urlstub urlstub1 out urlstub2 height urlstub3 width urlstub4 zoom urlstub5 postcode into urlget.
  EXPORTING url = urlget
  proxy_host = 'PROXY.SERVER.ADDRESS'
  proxy_service = 'PROXY_PORT'
  IMPORTING client = http_client ).
http_client->send( ).
http_client->receive( ).
http_client->response->get_status( IMPORTING code = return_code ).
content = http_client->response->get_cdata( ).
http_client->close( ).
data: xml_string type xstring.
DATA: gs_rif_ex     TYPE REF TO cx_root,
      gs_var_text   TYPE string.
        SOURCE XML  content
        RESULT ROOT = pict_url
              EROOT = error_msg.
  CATCH cx_root INTO gs_rif_ex.
    gs_var_text = gs_rif_ex->get_text( ).
    MESSAGE gs_var_text TYPE 'E'.
if proxy <> 'y'.
if pict_url is initial.
  d_pc = 'ERROR: could not process address'.
err_url = 'http://F.Q.D.N.HERE:8000/sap/bc/bsp/zjzip/error.gif'.
  navigation->goto_page( err_url ).
  DATA URL1 type string.
  url1 =   pict_url.
  d_pc = pict_url.
data:   file_length    TYPE  STRING,
  file_mime_type TYPE  STRING,
  file_name      TYPE  STRING,
  file_content   TYPE  XSTRING,
  display_type   TYPE  STRING.
  EXPORTING url = d_pc
  proxy_host = 'PROXY.SERVER.ADDRESS'
  proxy_service = 'PROXY_PORT'
  IMPORTING client = http_client ).
http_client->send( ).
http_client->receive( ).
http_client->response->get_status( IMPORTING code = return_code ).
bit = http_client->response->get_data( ).
http_client->close( ).
postcode = XSTRLEN( bit ).
IF  XSTRLEN( bit ) > 0.
  DATA: cached_response TYPE REF TO if_http_response.
  CREATE OBJECT cached_response TYPE CL_HTTP_RESPONSE EXPORTING add_c_msg = 1.
  cached_response->set_data( bit ).
   cached_response->set_header_field( name  = if_http_header_fields=>content_type
                                       value = 'image/gif' ).
    cached_response->set_status( code = 200 reason = 'OK' ).
    cached_response->server_cache_expire_rel( expires_rel = 180 ).
    DATA: guid TYPE guid_32.
    CONCATENATE runtime->application_url '/' guid '.gif' INTO display_url.
    cl_http_server=>server_cache_upload( url      = display_url
                                         response = cached_response ).
response->redirect( display_url ).
display_url = runtime->application_url.

Use transaction xlst_tool for the...(not so)
Simple Transformations

<?sap.transform simple?>
<tt:transform xmlns:tt="" xmlns:xsi="" >
  <tt:root name="ROOT"/>
  <tt:root name="EROOT"/>
        <tt:value ref="ROOT"/>
          <Message><tt:value ref="EROOT"/></Message>

Testing it.....

Refer to the post cURLing a google static map

The following changes would be required for the BSP controlled Yahoo image.

Change the jpg format to gif

Add the option -L to allow redirection and the F.Q.D.N is the SAP server fully qualified domain name. The PORT needs to be changed to the appropriate value.

c:\guixt\curlbin\curl -L http://F.Q.D.N.:PORT/sap/bc/bsp/sap/zjzip/map.htm? -d "postcode=%1,%2"  -d width=200 -d height=200 -d zoom=5   -G >c:\GuiXT\img\%1.gif

The END Result.

More to come on the geocode side of things.....

Wednesday, December 8, 2010

Visualising Wikipedia data with Tableau, sparql and dbpedia

Geocodes and thematic mapping in SAP will be blogged later. However here as a starting point is a very quick summary of thematic mapping Japan's population by prefecture in Tableau.

Sparqling DBpedia for Japan's Population Statistics.

Check out sparql on wikipedia
Check out dbpedia on wikipedia

So DBpedia has a sparql endpoint that allowed me to extract the total population and density with the following query.

**15/03/2013 Tableau informed me that my "vizzes" will be on my own profile page very soon. So I thought I would revisit my experiment with querying Wikipedia data with SPARQL and presenting the results with tableau.

I found that I needed to change the SPARQL query as follows.

PREFIX dcterms: <>

PREFIX skos: <>

PREFIX geo: <>

PREFIX dbpedia2: <>

SELECT ?prefecture ?lat ?long ?pop ?popt ?den ?denp


?prefecture dcterms:subject <> .

?prefecture geo:lat ?lat .

?prefecture geo:long ?long.

OPTIONAL { ?prefecture dbpedia2:population ?pop }

OPTIONAL { ?prefecture dbpedia2:populationTotal ?popt }

OPTIONAL { ?prefecture dbpedia2:density ?den }

OPTIONAL { ?prefecture dbpedia2:populationDensityKm ?denp }

FILTER (xsd:double(?lat)).

FILTER (xsd:double(?long)).


*original query in 2010 below will now fail to select any data.

PREFIX skos: <>

PREFIX geo: <>

PREFIX dbpedia2: <>

SELECT ?prefecture ?lat ?long ?pop ?popt ?den ?denp


?prefecture skos:subject <> .

?prefecture geo:lat ?lat .

?prefecture geo:long ?long.

OPTIONAL { ?prefecture dbpedia2:population ?pop }

OPTIONAL { ?prefecture dbpedia2:populationTotal ?popt }

OPTIONAL { ?prefecture dbpedia2:density ?den }

OPTIONAL { ?prefecture dbpedia2:populationDensityKm ?denp }

FILTER (xsd:double(?lat)).

FILTER (xsd:double(?long)).


*2013 edit
Enter the first query above in DBpedia Virtuoso SPARQL Query From

The data needs to be tidied up (and I still have to update the prefecture names!) due to some changes of data names in the property section.

Using the SHOW ME! button in Tableau 

OK, so Tableau public is free and I can embed the data in this blog. I registered for an account cut and pasted my data above after a tidy up in Excel (you can download the data I used in the presentation). Then I hit the Show Me! button and the final presentation is here. So simple.......maybe.

Google +