Convert Zebra .GRF Hex to .BMP

Convert Zebra .GRF Hex to .BMP

Recently I needed to print a Zebra-formatted shipping label to a SATO printer. I have another program that transforms ZPL II to SATO but had not implemented graphics because there was no need.

Until now.

Below is RPGLE source that translates Zebra’s .GRF hex string to a .BMP string that can be used in SATO’s GM command and streamed to the SATO printer for printing. It’s implemented as a stand-alone program but can easily be changed to a procedure for inclusion in a *SRVPGM.

 h dftactgrp(*no)                                                           

 d pTotBytes       s              7p 0                                      
 d pBytesPerRow    s              7p 0                                      
 d pHexIn          s        1000000a   ccsid(65535)                         
 d pBmpOut         s        1000000a   ccsid(65535)                         
 d pBmpSize        s              7p 0                                     
 d div             s             10i 0                                      
 d rem             s             10i 0                                      
 d rows            s             10i 0                                      
 d pad             s              4a   varying ccsid(65535)                 
 d i#              s             10i 0                                      
 d j#              s             10i 0                                      

 d dsHeader        ds                  template                             
 d  id                            2a   ccsid(819)                           
 d  size                         10u 0                                      
 d  rsv1                          5i 0                                      
 d  rsv2                          5i 0                                      
 d  offset                       10u 0                                      

 d dsDIB           ds                  template                             
 d  sizeThisHdr                  10u 0                                      
 d  bmpWidthPx                   10i 0                                      
 d  bmpHeightPx                  10i 0                                      
 d  colorPlane#                   5u 0                                      
 d  pxBits                        5u 0                                      
 d  compress                     10u 0                                      
 d  sizeImg                      10u 0                                      
 d  hRes                         10i 0                                      
 d  vRes                         10i 0                                      
 d  color#Pal                    10u 0                                      
 d  color#Imp                    10u 0                                      

 d dsBmp           ds                  qualified inz                        
 d  header                             likeds(dsHeader)                     
 d  dib                                likeds(dsDIB)                        
 d  colorTbl                      8a   ccsid(65535)                         
 d  img                      999360a   ccsid(65535)                         
    
   // The IBM i uses Big Endian. Windows uses Little Endian.
   // These routines convert BE to LE:
 d LE4i            pr            10i 0                                      
 d  pInt                         10i 0 value                                

 d LE2i            pr             5i 0                                      
 d  pInt                          5i 0 value                                

 d LE4u            pr            10u 0                                      
 d  pUint                        10u 0 value                                

 d LE2u            pr             5u 0                                      
 d  pUint                         5u 0 value                                

 c     *entry        plist                                                  
 c                   parm                    pTotBytes                      
 c                   parm                    pBytesPerRow                   
 c                   parm                    pHexIn                         
 c                   parm                    pBmpOut                        
 c                   parm                    pBmpSize                                          

   *inlr = *on;

   pBmpOut  = *allx'00';                                                    
   pBmpSize = 0;                                                            
   clear dsBmp;                                                             

   if pBytesPerRow = 0;                                                     
     return;                                                                
   endif;                                                                   

   rows = pTotBytes / pBytesPerRow;                                         

   // image rows must be on dword boundary. Pad with x'00':                 
   div = %div(pBytesPerRow: 4);                                             
   rem = %rem(pBytesPerRow: 4);                                             
   select;                                                                  
     when rem = 1;                                                          
       pad = x'000000';                                                     
     when rem = 2;                                                          
       pad = x'0000';                                                       
     when rem = 3;                                                          
       pad = x'00';                                                         
     other;                                                                 
       pad = '';                                                            
   endsl;                                                                   

   rem = %len(pad);                                                         

   // Ensure pBmpOut won't overflow:                                        
   pBmpSize = ((pBytesPerRow + rem) * rows) +                               
              %size(dsHeader) +                                             
              %size(dsDIB) +                                                
              %size(dsBmp.colorTbl);                                        
   if pBmpSize > %size(pBmpOut);                                            
     pBmpSize = 0;                                                          
     return;                                                                
   endif;                                                                   

   dsBmp.header.id        = 'BM';                                           
   dsBmp.header.size      = LE4u(pBmpSize);                                 
   dsBmp.header.offset    = LE4u(%size(dsBmp) - %size(dsBmp.img));          
   dsBmp.dib.bmpWidthPx   = LE4i(pBytesPerRow * 8);                         
   dsBmp.dib.bmpHeightPx  = LE4i(rows);                                     
   dsBmp.dib.sizeThisHdr  = LE4u(%size(dsBmp.DIB));                         
   dsBmp.dib.colorPlane#  = LE2u(1);                                        
   dsBmp.dib.pxBits       = LE2u(1);                                        
   dsBmp.dib.compress     = 0;                                              
   dsBmp.dib.sizeImg      = 0;                                              
   dsBmp.dib.hRes         = 0;                                              
   dsBmp.dib.vRes         = 0;                                              
   dsBmp.dib.color#Pal    = 1;                                              
   dsBmp.dib.color#Imp    = 0;                                              
   dsBmp.colorTbl         = x'00000000FFFFFF00'; // monochrome              

   // .BMP files are read from the bottom up. This routine writes
   //  dsBmp.img bytes starting from the end:
   i# = pTotBytes - pBytesPerRow + 1;                                       
   j# = 1;                                                                  
   dow i# > 0;                                                              
     %subst(dsBmp.img: j#: pBytesPerRow + rem) =                            
     %bitnot(%subst(pHexIn: i#: pBytesPerRow) + pad);                       
     i# -= pBytesPerRow;                                                    
     j# += pBytesPerRow + rem;                                              
   enddo;                                                                   

   %subst(pBmpOut: 1: pBmpSize) = dsBmp;                                    
                                                   
   return;                                                                  
  *----------------------------------------------------------               
 p LE4i            b                                                        
 d LE4i            pi            10i 0                                      
 d  pInt                         10i 0 value                                

 d dsBigEnd        ds                  qualified inz                        
 d  int                          10i 0                                      
 d  byte1                         1a   overlay(int: 1)                      
 d  byte2                         1a   overlay(int: *next)                  
 d  byte3                         1a   overlay(int: *next)                  
 d  byte4                         1a   overlay(int: *next)                  

 d dsLitEnd        ds                  qualified inz                        
 d  int                          10i 0                                      
 d  byte4                         1a   overlay(int: 1)                      
 d  byte3                         1a   overlay(int: *next)                  
 d  byte2                         1a   overlay(int: *next)                  
 d  byte1                         1a   overlay(int: *next)                  

    dsBigEnd.int = pInt;                                                    
    eval-corr dsLitEnd = dsBigEnd;                                          
    return dsLitEnd.int;                                                    

 p LE4i            e                                                        
  *----------------------------------------------------------               
 p LE2i            b                                                        
 d LE2i            pi             5i 0                                      
 d  pInt                          5i 0 value                                

 d dsBigEnd        ds                  qualified inz                        
 d  int                           5i 0                                      
 d  byte1                         1a   overlay(int: 1)                      
 d  byte2                         1a   overlay(int: *next)                  

 d dsLitEnd        ds                  qualified inz                        
 d  int                           5i 0                                      
 d  byte2                         1a   overlay(int: *next)                  
 d  byte1                         1a   overlay(int: *next)                  

    dsBigEnd.int = pInt;                                                    
    eval-corr dsLitEnd = dsBigEnd;                                          
    return dsLitEnd.int;                                                    

 p LE2i            e                                                        
  *----------------------------------------------------------               
 p LE4u            b                                                        
 d LE4u            pi            10u 0                                      
 d  pUint                        10u 0 value                                

 d dsBigEnd        ds                  qualified inz                        
 d  uint                         10u 0                                      
 d  byte1                         1a   overlay(uint: 1)                     
 d  byte2                         1a   overlay(uint: *next)                 
 d  byte3                         1a   overlay(uint: *next)                 
 d  byte4                         1a   overlay(uint: *next)                 

 d dsLitEnd        ds                  qualified inz                        
 d  uint                         10u 0                                      
 d  byte4                         1a   overlay(uint: 1)                     
 d  byte3                         1a   overlay(uint: *next)                 
 d  byte2                         1a   overlay(uint: *next)                 
 d  byte1                         1a   overlay(uint: *next)                 

    dsBigEnd.uint = pUint;                                                  
    eval-corr dsLitEnd = dsBigEnd;                                          
    return dsLitEnd.uint;                                                   

 p LE4u            e                                                        
  *----------------------------------------------------------               
 p LE2u            b                                                        
 d LE2u            pi             5u 0                                      
 d  pUint                         5u 0 value                                

 d dsBigEnd        ds                  qualified inz                        
 d  uint                          5u 0                                      
 d  byte1                         1a   overlay(uint: 1)                     
 d  byte2                         1a   overlay(uint: *next)                 

 d dsLitEnd        ds                  qualified inz                        
 d  uint                          5u 0                                      
 d  byte2                         1a   overlay(uint: *next)                 
 d  byte1                         1a   overlay(uint: *next)                 

    dsBigEnd.uint = pUint;                                                  
    eval-corr dsLitEnd = dsBigEnd;                                          
    return dsLitEnd.uint;                                                   

 p LE2u            e                                                        
  *----------------------------------------------------------               

Leave a Reply

Your email address will not be published. Required fields are marked *