Skip to Content

Introduction

Last week Alvaro Tejada (Blag) posted a The specified item was not found.. Well I got all caught up in the fun challenge and now here are the results for your downloading pleasure.

What Blag wanted to do was simply flip an existing Bitmap that he was reading out of the BDS (Business Document Store).  The problem that he was facing is that there is no easy method for doing this in ABAP. He tried just reversing the Byte Stream, but quickly found out that this corrupted the image.  A bitmap isn’t just stored as a simple data stream – it has header information and a complex structure that must be taken into consideration when doing any manipulations on it.

But many other languages have simple processes for working with Bitmaps – what was wrong with ABAP.  Well these other languages just have libraries that have already been created that abstract the actual process of working with the Bitmap.  These libraries directly expose attributes like the bitmap height and width, so that programmers don’t have to know the detailed structure of the Bitmap header.  They also usually have methods to allow for basic manipulation of the Bitmap.

To my best knowledge, no one in ABAP had created such a library.  So while it was perfectly possible to manipulate the Bitmap at a low level in ABAP, it was more tedious than necessarily because it didn’t have one of these helper libraries.  Historically ABAP has been all about processing business data, so it hasn’t been a big issue that you couldn’t flip bitmaps or convert them to grey scale.  But with ABAP being used increasingly for forms output and web pages, this is functionality that might be useful from time to time.  So I decided to take the rough solution that I built for Blag and turn it into a reusable bitmap class.

Bitmap Processing

Before we get into the actual solution of the ABAP Bitmap Library, I thought I would cover some basics of the processing that is going on within the library.  If you are interested in how Bitmaps are stored and processed then keep reading this section. If you really couldn’t care less and just want to get started using the library, then skip down to the next section (after all the purpose of creating this library was so people wouldn’t have to care how a bitmap works internally).

When I started looking into Blag’s problem, I had no real experience with how bitmaps are structured.  So I started my investigation via the internet.  I found lots of good articles on Bitmaps, but probably the best summary of information I found was on Wikipedia.

The linked Wikipedia article does an excellent job of describing the inner layout of the Bitmap – how you have a section for the header information and then a separate section for the data.  It also describes for each pixel is stored.  The color of the pixel (in 24 bits per pixel) is stored as three separate integers – one each for Red, Green, and Blue.  It is important to understand that you can’t just manipulate data within the Bitmap at the byte level, but instead the pixel level so you can keep from altering the RGB color as you move bytes around.

The second complexity is that bitmaps are not stored top to bottom within the data area.  Instead the first visible row of data on the screen is stored as the list “line” in the bitmap data area.  All the data is also stored together in a single stream. Therefore for easier processing you generally break the stream down by horizontal row. But because processing is easier if divisible by 4, null-bytes are added to the end of the line to pad the file.  All of these aspects are especially important when trying to rotate a bitmap.

The final complexity that I faced in my processing was that much of the data in the bitmap header was stored as either 2 or 4 byte DWORDs. This meant that I couldn’t just cast these byte values into ABAP Integers.  Instead I had to create small macros to change the byte order.

The ABAP Bitmap Library

OK, enough of the deep stuff.  Now it is time to see just how easy we can make working with Bitmaps in ABAP.  For that purpose I have created a Class called ZCL_ABAP_BITMAP.


As you can see there are plenty of methods in this class.  Let’s start with the Static methods.  You see the class is marked as Private Instantiation only, therefore the static methods are the only way to create an instance of the class.

Each of the static methods is a path to provide the bitmap source and return an instance of the class.  We have the basic create from bitmap methods like CREATE_FROM_BYTESTEAM (type XSTRING) and CREATE_FROM_BYTETABLE (type standard table of line 255 x). These are generic and support reading the bitmap content from outside the library – providing flexibility.

But I also wanted to make it easy to read the bitmap content from the most common locations. Therefore we have the CREATE_FROM_MIME_REPOSITORY, CREATE_FROM_BDS_GRAPHIC, and CREATE_FROM_FRONTEND_UPLOAD methods. These methods contain the necessarily logic to process images from their various sources.  But many of these sources also support graphic formats other than bitmaps.  Internally this class must process everything in bitmaps, but I wanted to support the conversion from other popular formats (like GIFs and JPEGs).  Luckily this functionality already is provided by the IGS and I just reused the existing class, CL_IGS_IMAGE_CONVERTER, to do the processing.

The method CREATE_FROM_EXT_FORMAT provides the logic to interact with the IGS and perform the conversion.  It supports conversions to/from JPEG, TIFF, PNG, GIF, and of course Bitmap. There is one common static method than can be used inside the class and by calling programs named CHECK_IGS_SETUP to test to see if the IGS is present, configured and of a late enough release level to support image conversion.  That way if there is any problem with the IGS setup, exceptions can be thrown gracefully and the alternative image types simply aren’t supported.

There are also similar methods for outputting the bitmap image – including outbound format conversion and Zip compression- GET_CONTENT_ZIP_BYTESTREAM, GET_CONTENT_BYTESTREAM, GET_CONTENT_EXT_FORMAT, and GET_CONTENT_BYTETABLE.

Next are the methods that help to display the bitmap in different environments.  First is the method DISPLAY_IN_SAPGUI.  This is designed for Classic Dynpro. You can pass in the hosting container element – or if you want the ZCL_ABAP_BITMAP to control the image, it can provide its own Dialog Container Control.  This was very helpful for debugging, because it makes it possible to test the class and display the results without any wrapper program.

The other display helper method is the PUSH_CONTENT_INTO_ICM_CACHE.  This places the content for the image into the ICM content cache for the specified amount of time and returns the unique URL to this cached object.  This is a great way to manipulate the image, and then display it in an image element using BSP or Web Dynpro ABAP without ever having to permanently store the image.

We have one method, GET_HEADER_INFORMATION, that reads the Bitmap header and returns all the most important information (like width, height, color depth, etc).

Finally we have the really fun methods: the transformations. These are the methods that directly manipulate the Bitmap Content.  The names of the methods do a rather good job of describing exactly what they do to the image: TRANSFORM_ROTATE_CLOCKWISE, TRANSFORM_ROTATE_COUNTER_CLOCK, TRANSFORM_FLIP, TRANSFORM_MIRROR, TRANSFORM_INVERSION, TRANSFORM_GREYSCALE.

Test Applications

No library would really be complete without some nice test and demo applications. For this purpose I built two different test suites.  The first is classic dynpro based.  The application lets you load images from the Frontend.  It displays the results using the DISPLAY_IN_SAPGUI method and has buttons to activate the Transformations.

Just to demonstrate how (hopefully) easy this class is to use, here is the source code of the classic dynpro test application:

REPORT zabap_bitmap_test.
DATA bitmap TYPE REF TO zcl_abap_bitmap.
DATA custom_container TYPE REF TO cl_gui_custom_container.
DATA okcode TYPE syucomm.
START-OF-SELECTION.
CALL SCREEN 100.
*&---------------------------------------------------------------------*
*& Module STATUS_0100 OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
SET PF-STATUS 'MAIN'.
SET TITLEBAR '100'.
IF custom_container IS INITIAL.
CREATE OBJECT custom_container
EXPORTING
container_name = 'CUSTOM_CONTAINER'.
ENDIF.
IF bitmap IS INITIAL.
TRY.
bitmap = zcl_abap_bitmap=>create_from_frontend_upload( ).
bitmap->display_in_sapgui(
i_container = custom_container ).
CATCH zcx_abap_bitmap .
ENDTRY.
ENDIF.
ENDMODULE. " STATUS_0100 OUTPUT
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_0100 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
TRY.
CASE okcode.
WHEN 'BACK' OR 'CANCEL' OR 'EXIT'.
LEAVE PROGRAM.
WHEN 'NEW'.
bitmap->free( ).
CLEAR bitmap.
WHEN 'CLOCK'.
bitmap->transform_rotate_clockwise( ).
bitmap->refresh_sapgui_display( ).
WHEN 'COUNTER'.
bitmap->transform_rotate_counter_clock( ).
bitmap->refresh_sapgui_display( ).
WHEN 'GRAY'.
bitmap->transform_greyscale( ).
bitmap->refresh_sapgui_display( ).
WHEN 'INVERSE'.
bitmap->transform_inversion( ).
bitmap->refresh_sapgui_display( ).
WHEN 'MIRROR'.
bitmap->transform_mirror( ).
bitmap->refresh_sapgui_display( ).
WHEN 'FLIP'.
bitmap->transform_flip( ).
bitmap->refresh_sapgui_display( ).
ENDCASE.
CATCH zcx_abap_bitmap .
CLEAR okcode.
ENDTRY.
CLEAR okcode.
ENDMODULE. " USER_COMMAND_0100 INPUT

But the more full featured test application is actually the Web Dynpro ABAP version.  It has all the same functionality to load existing images, display them, and perform transformations:

However it also has functionality to export the manipulated image in several formats (as well as zip compression):

Downloads

Now for the downloads.  I have broken them out into separate parts and pieces so people can grab just what they need.

(!!!Downloadlinks do not work anymore!!!) added by moderator

To report this post you need to login first.

23 Comments

You must be Logged on to comment or reply to a post.

  1. Alvaro Tejada Galindo
    Thomas:

    I was waiting for this magical moment -;) This class is just awesome! You really took my problem and take it to a whole new level! I feel happy to know that thanks to my humble blog you made an incredible tool! -:D I love that kind of collaboration that can be produced here on SDN…

    Can’t wait to test the class and hopefully add some methods -:P

    P.S: This will go to my SDN Blogs Vault… -:D

    Greetings,

    Blag.

    (0) 
  2. Dushyant Shetty
    This is just such an awesome show-of-strength for capabilities of ABAP, I am running out of adjectives…

    This is quite simply the kind of stuff that I love doing in a language, and I guess people who think it’s difficult to build libraries/APIs in ABAP will not say much after reading this!

    Dushyant Shetty

    (0) 
  3. Guido Brune
    Hello Thomas,

    thank you for sharing!

    Is also a possibility to execute OPenGL in SAP enviroment?

    Regards & Thanks & All the best & Nice weekend,

    Guido

    (0) 
    1. Thomas Jung Post author
      Well when I think OpenGL, I immedately think of hardware acellerated 3D.  Keep in mind that anything executing in ABAP will be server side based.  Although much like the Bitmap processing, I’m sure you could do 3d image processing at the pixel level in ABAP, but I’m not sure that would be very efficient because you certainly couldn’t access the video hardware.
      (0) 
    2. Anonymous
      Hi Guido,

      if you are still interested in this topic I can tell you that you can use OpenGL in the SAPGUI.
      I just created an AxtiveX control and could use it in a custom control. The interaction with the mouse is also supported.

      Regards
      Nemrude

      (0) 
  4. Alvaro Tejada Galindo
    Thomas:

    I test it yesterday on my NSP…It works like a charm -:D Now I got some idea to update the class -;) Sometime ago I developed an Visual Basic application with 32 filters…Just to adapt them to ABAP and to your class…Any update will go on SAPLink format of course…Hope I can make it -:P

    Greetings,

    Blag.

    (0) 
    1. Thomas Jung Post author
      Well I haven’t tested it on WebAS 6.20, but I don’t think there is anything that wouldn’t work on that release.  The only thing that might not be there would be the IGS functionality for Image Type Conversion. The actually manipulation of the Bitmap Byte data is pretty straight forward (bit and byte level moves).  I used some local class type definitions that might have to be converted to data dictionary types, but the core logic should be easy to adjust and run on 6.20.
      (0) 
  5. Dario Jiang
    it’s an amazing achievement so my question may be a little naive.

    i just wonder to know how can i upload the file i downloaded here(especially the class object) into sap and make it work

    additionally,i have ECC 5.0 and XI system at present

    thanks for your help

    (0) 
    1. Thomas Jung Post author
      Well there were two options of types of download files.  The first was the object via SAPlink.  SAPlink is an open source project that makes it easy to move ABAP development objects between systems. 

      SAPlink is not an SAP product.  It is a community project designed to help facilitate the exchange for ABAP development objects.  It exports and imports objects based upon XML.  Therefore it bypasses the Transport Mechanism.  It allows you to import most objects by simply running an ABAP program.  It imports all objects into $TMP and Inactive so that you can review them before activation.

      Here is a link where you read more about SAPlink:
      http://code.google.com/p/saplink/

      The last option in the list is a transport file.
      This is the same mechanism that you use today to move programs through your normal landscape.  This has the advantage that you can import all developments objects (unlike SAPlink that needs plugins to support different object types). The only downside is that developers generally won’t have access to perform the transport yourself.  You will have to go to your Basis Administrator and request that they import the transport file for you.

      The exception here is if you use the SDN Trial Version system.  In this case you have full control over using the transport mechanism.  There is even a blog on SDN that discusses how to setup and use the transport system in the Trial Version.
      ABAP Trial Version for Newbies: Part 9 ‘ Importing a transport into SP11/12 ‘

      (0) 
  6. Matthew Partington
    I was having problems with the Transport files as they wouldn’t compile after importing into an ECC5 system.

    With some help from Thomas (thanks again Thomas) I made the following changes;

    1. Changed the constructor to PUBLIC.
    2. Replaced both REGEX calls with SPLIT to get the type of file extension.

    (0) 
  7. Michael Fallenbüchel
    Hi Thomas,

    your class is just awesone! After working with it for a while now I’m just missing one little thing:

    Is it possible to change the color depth of a picture (f.e. from 24bit to 256 colors)?

    (0) 
    1. Thomas Jung Post author
      I didn’t program in color depth change. Only the features you seen in the screen shots – inverstion, flip, rotate, greyscale.  The image type conversion comes from the IGS. I would imagine that color depth would be possible, although somewhat difficult.  It would be simliar to greyscale conversion – but you would need to find an formula on the internet about how to do color depth reduction.  That is what I had done. I found some samples of how to perform these operations on bitmaps in C/C++ and converted the logic to ABAP.
      (0) 
  8. B. Deterd
    Is it possible to extend this class to make thumbnails. Then this would be really helpful for a number of use-cases.

    Great work by the way. See you at Teched.

    Regards,
    Bert

    (0) 
    1. Thomas Jung Post author
      Thumbnails would require resizing the image, which this current class doesn’t do. However there have been some solutions posted to do so. Actually the easiest solution is to just use the IGS to resize. The same calls to convert the image type in the IGS (which I use in this class) can also resize. You just pass in the new dimensions and use the same file type for the source and destination.
      (0) 
  9. Sandra Rossi

    hello,

    If I’m not wrong (I didn’t test), there’s a just one mistake about the Endianness of the X to I conversion, that is, it works only in a Little Endian system. For instance, the READ4 macro should be modified this way:

      define read4.  "#EC NEEDED read four bytes as integer and move offset
        w4     = &1.
        IF abap_true = is_little_endian( ).
          concatenate w4+3(1) w4+2(1) w4+1(1) w4+0(1) into xstr in byte mode.
        ELSE.
          xstr = w4(4).
        ENDIF.
        &2     = xstr.
      end-of-definition.
    

    And IS_LITTLE_ENDIAN method may be created this way:

    CLASS-METHODS is_little_endian RETURNING VALUE(little_endian) TYPE abap_bool.
    METHOD is_little_endian.
      FIELD-SYMBOLS TYPE x.
      DATA i TYPE i.
      i = 1.
      ASSIGN i TO CASTING.
      IF(1) IS INITIAL.
        little_endian = abap_false. "i.e. it is a big endian system
      ELSE.
        little_endian = abap_true.
      ENDIF.
    ENDMETHOD.
    

    Sandra

    (0) 
  10. Rashmith Tula

    Hello Thomas,

       Thanks for sharing this great work. My question is not completely relevant to this doc but I will be really grateful if you can help me out if possible. Is there a way to download a scriptform in ‘.bmp’ format like we download in ‘.pdf’ format using the program ‘RSTXPDFT4’. Thanks in advance.

    Regards,

    Rashmith.

    (0) 
  11. Mo Chongbao

    Hi Thomas,

    I need to convert a bmp picture in local pc to 8-bit bmp and i found the method – TRANSFORM_GREYSCALE in your class could return a 8-bit bmp gray graphics, not colored.

    So could i know how to update this method to return a 8-bit bmp colored graphics?


    Could please help on this? it is very urgent for me. very appreciate!

    (0) 

Leave a Reply