home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxttf.zip / rxttf.c < prev    next >
C/C++ Source or Header  |  1999-03-14  |  18KB  |  604 lines

  1.  
  2. /***********************************************************************/
  3. /*                                                                     */
  4. /*   RxTTF - Copyright (C) 1999 Michal Necasek <mike@mendelu.cz>       */
  5. /*           Specification - Daniel Hellerstein <danielh@econ.ag.gov>  */
  6. /*                                                                     */
  7. /*   This code is in the public domain                                 */
  8. /*                                                                     */
  9. /*   This code is based on the work of the FreeType Project            */
  10. /*       http://www.freetype.org                                       */
  11. /*                                                                     */
  12. /***********************************************************************/
  13.  
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17.  
  18. #define  INCL_REXXSAA
  19. #include <os2.h>
  20. #include <rexxsaa.h>
  21.  
  22. #include "freetype.h"
  23.  
  24. /* exported functions */
  25. RexxFunctionHandler rxttf_image;
  26.  
  27.  
  28. #define  INVALID_ROUTINE 40            /* Raise Rexx error           */
  29. #define  VALID_ROUTINE    0            /* Successful completion      */
  30.  
  31. /* error codes */
  32. #define  NO_UTIL_ERROR    "0"          /* No error whatsoever        */
  33. #define  ERROR_NOMEM      "2"          /* Insufficient memory        */
  34. #define  ERROR_FILEOPEN   "3"          /* Error opening text file    */
  35. #define  ERROR_ENGINE     "4"          /* FreeType engine error      */
  36. #define  ERROR_REXXVAR    "5"          /* Rexx variable pool error   */
  37.  
  38. #define  MAX            256        /* temporary buffer length        */
  39. #define  IBUF_LEN       4096       /* Input buffer length            */
  40.  
  41. /*********************************************************************/
  42. /* RxStemData                                                        */
  43. /*   Structure which describes a generic                             */
  44. /*   stem variable.                                                  */
  45. /*********************************************************************/
  46.  
  47. typedef struct RxStemData {
  48.     SHVBLOCK shvb;                     /* Request block for RxVar    */
  49.     CHAR ibuf[IBUF_LEN];               /* Input buffer               */
  50.     CHAR varname[MAX];                 /* Buffer for the variable    */
  51.                                        /* name                       */
  52.     CHAR stemname[MAX];                /* Buffer for the variable    */
  53.                                        /* name                       */
  54.     ULONG stemlen;                     /* Length of stem.            */
  55.     ULONG vlen;                        /* Length of variable value   */
  56.     ULONG j;                           /* Temp counter               */
  57.     ULONG tlong;                       /* Temp counter               */
  58.     ULONG count;                       /* Number of elements         */
  59.                                        /* processed                  */
  60. } RXSTEMDATA;
  61.  
  62. #define BUILDRXSTRING(t, s) { \
  63.   strcpy((t)->strptr,(s));\
  64.   (t)->strlength = strlen((s)); \
  65. }
  66.  
  67. #define  Pi         3.1415926535
  68.  
  69. #define  MAXPTSIZE  500                 /* dtp */
  70.  
  71. char  Header[128];
  72.  
  73. TT_Engine    engine;
  74. TT_Face      face;
  75. TT_Instance  instance;
  76. TT_Glyph     glyph;
  77. TT_CharMap   char_map;
  78.  
  79. TT_Glyph_Metrics     metrics;
  80. TT_Outline           outline;
  81. TT_Face_Properties   properties;
  82. TT_Instance_Metrics  imetrics;
  83.  
  84. int  num_glyphs;
  85.  
  86. int  ptsize;
  87. int  hinted;
  88.  
  89. int            gray_render;
  90. int            font_smoothing = FALSE;
  91.  
  92. short  glyph_code[1024];
  93. int    num_codes;
  94.  
  95. /* the virtual palette */
  96. unsigned char  virtual_palette[5] = { 0, 1, 2, 3, 4 };
  97.  
  98. /* Or-ing the possible palette values gets us from 0 to 7 */
  99. /* We must bound check these...                           */
  100. unsigned char  bounded_palette[8] = { 0, 1, 2, 3, 4, 4, 4, 4 };
  101.  
  102. /* The target bitmap or pixmap -- covering the full display window/screen */
  103. TT_Raster_Map  Bit;
  104.  
  105. /* A smaller intermediate bitmap used to render individual glyphs when    */
  106. /* font smoothing mode is activated.  It is then or-ed to `Bit'.          */
  107. TT_Raster_Map  Small_Bit;
  108.  
  109. /* Clears the Small_Bit pixmap */
  110. void  Clear_Small( void )
  111. {
  112.   memset( Small_Bit.bitmap, 0, Small_Bit.size );
  113. }
  114.  
  115. /* Clears the Bit bitmap/pixmap */
  116. void  Clear_Bit( void )
  117. {
  118.   memset( Bit.bitmap, 0, Bit.size );
  119. }
  120.  
  121. TT_Error  Render_Single_Glyph( int       font_smoothing,
  122.                                TT_Glyph  glyph,
  123.                                int       x_offset,
  124.                                int       y_offset )
  125. {
  126.   if ( !font_smoothing )
  127.     return TT_Get_Glyph_Bitmap( glyph, &Bit,
  128.                                 (long)x_offset*64, (long)y_offset*64 );
  129.   else
  130.   {
  131.     TT_Glyph_Metrics  metrics;
  132.  
  133.     TT_Error    error;
  134.     TT_F26Dot6  x, y, xmin, ymin, xmax, ymax;
  135.     int         ioff, iread;
  136.     char        *off, *read, *_off, *_read;
  137.  
  138.  
  139.     /* font-smoothing mode */
  140.  
  141.     /* we begin by grid-fitting the bounding box */
  142.     TT_Get_Glyph_Metrics( glyph, &metrics );
  143.  
  144.     xmin = metrics.bbox.xMin & -64;
  145.     ymin = metrics.bbox.yMin & -64;
  146.     xmax = (metrics.bbox.xMax+63) & -64;
  147.     ymax = (metrics.bbox.yMax+63) & -64;
  148.  
  149.     /* now render the glyph in the small pixmap */
  150.  
  151.     /* IMPORTANT NOTE: the offset parameters passed to the function     */
  152.     /* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e.,        */
  153.     /* multiples of 64.  HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */
  154.     /* This is why we _did_ grid-fit the bounding box, especially xmin  */
  155.     /* and ymin.                                                        */
  156.  
  157.     error = TT_Get_Glyph_Pixmap( glyph, &Small_Bit, -xmin, -ymin );
  158.     if ( error )
  159.       return error;
  160.  
  161.     /* Blit-or the resulting small pixmap into the biggest one */
  162.     /* We do that by hand, and provide also clipping.          */
  163.  
  164.     xmin = (xmin >> 6) + x_offset;
  165.     ymin = (ymin >> 6) + y_offset;
  166.     xmax = (xmax >> 6) + x_offset;
  167.     ymax = (ymax >> 6) + y_offset;
  168.  
  169.     /* Take care of comparing xmin and ymin with signed values!  */
  170.     /* This was the cause of strange misplacements when Bit.rows */
  171.     /* was unsigned.                                             */
  172.  
  173.     if ( xmin >= (int)Bit.width   ||
  174.          ymin >= (int)Bit.rows    ||
  175.          xmax < 0                 ||
  176.          ymax < 0 )
  177.       return TT_Err_Ok;  /* nothing to do */
  178.  
  179.     /* Note that the clipping check is performed _after_ rendering */
  180.     /* the glyph in the small bitmap to let this function return   */
  181.     /* potential error codes for all glyphs, even hidden ones.     */
  182.  
  183.     /* In exotic glyphs, the bounding box may be larger than the   */
  184.     /* size of the small pixmap.  Take care of that here.          */
  185.  
  186.     if ( xmax-xmin + 1 > Small_Bit.width )
  187.       xmax = xmin + Small_Bit.width - 1;
  188.  
  189.     if ( ymax-ymin + 1 > Small_Bit.rows )
  190.       ymax = ymin + Small_Bit.rows - 1;
  191.  
  192.     /* set up clipping and cursors */
  193.  
  194.     iread = 0;
  195.     if ( ymin < 0 )
  196.     {
  197.       iread -= ymin * Small_Bit.cols;
  198.       ioff   = 0;
  199.       ymin   = 0;
  200.     }
  201.     else
  202.       ioff = ymin * Bit.cols;
  203.  
  204.     if ( ymax >= Bit.rows )
  205.       ymax = Bit.rows-1;
  206.  
  207.     if ( xmin < 0 )
  208.     {
  209.       iread -= xmin;
  210.       xmin   = 0;
  211.     }
  212.     else
  213.       ioff += xmin;
  214.  
  215.     if ( xmax >= Bit.width )
  216.       xmax = Bit.width - 1;
  217.  
  218.     _read = (char*)Small_Bit.bitmap + iread;
  219.     _off  = (char*)Bit.bitmap       + ioff;
  220.  
  221.     for ( y = ymin; y <= ymax; y++ )
  222.     {
  223.       read = _read;
  224.       off  = _off;
  225.  
  226.       for ( x = xmin; x <= xmax; x++ )
  227.       {
  228.         *off = bounded_palette[*off | *read];
  229.         off++;
  230.         read++;
  231.       }
  232.       _read += Small_Bit.cols;
  233.       _off  += Bit.cols;
  234.     }
  235.  
  236.     return TT_Err_Ok;
  237.   }
  238. }
  239.  
  240.  
  241. /* Convert an ASCII string to a string of glyph indexes.              */
  242. /*                                                                    */
  243. /* IMPORTANT NOTE:                                                    */
  244. /*                                                                    */
  245. /* There is no portable way to convert from any system's char. code   */
  246. /* to Unicode.  This function simply takes a char. string as argument */
  247. /* and "interprets" each character as a Unicode char. index with no   */
  248. /* further check.                                                     */
  249. /*                                                                    */
  250. /* This mapping is only valid for the ASCII character set (i.e.,      */
  251. /* codes 32 to 127); all other codes (like accentuated characters)    */
  252. /* will produce more or less random results, depending on the system  */
  253. /* being run.                                                         */
  254.  
  255. static ULONG CharToUnicode( char*  source )
  256. {
  257.   unsigned short  i, n;
  258.   unsigned short  platform, encoding;
  259.  
  260.   /* First, look for a Unicode charmap */
  261.  
  262.   n = properties.num_CharMaps;
  263.  
  264.   for ( i = 0; i < n; i++ )
  265.   {
  266.     TT_Get_CharMap_ID( face, i, &platform, &encoding );
  267.     if ( (platform == 3 && encoding == 1 )  ||
  268.          (platform == 0 && encoding == 0 ) )
  269.     {
  270.       TT_Get_CharMap( face, i, &char_map );
  271.       i = n + 1;
  272.     }
  273.   }
  274.  
  275.   if ( i == n ) {
  276.     return 1;   /* error - no Unicode cmap */
  277.   }
  278.  
  279.   for ( n = 0; n < 1024 && source[n]; n++ )
  280.     glyph_code[n] = TT_Char_Index( char_map, (short)source[n] );
  281.  
  282. #if 0
  283.   /* Note, if you have a function, say ToUnicode(), to convert from     */
  284.   /* char codes to Unicode, use the following line instead:             */
  285.  
  286.   glyph_code[n] = TT_Char_Index( char_map, ToUnicode( source[n] ) );
  287. #endif
  288.  
  289.   num_codes = n;
  290.  
  291.   return 0;
  292. }
  293.  
  294.  
  295. static ULONG  Reset_Scale( int  pointSize )
  296. {
  297.   TT_Error  error;
  298.  
  299.   error = TT_Set_Instance_CharSize( instance, pointSize * 64 );
  300.   if (error)
  301.   {
  302.     return 1; /* Error */
  303.   }
  304.  
  305.   TT_Get_Instance_Metrics( instance, &imetrics );
  306.  
  307.   return 0;   /* OK */
  308. }
  309.  
  310.  
  311. static TT_Error  LoadTrueTypeChar( int  idx, int  hint )
  312. {
  313.   int  flags;
  314.  
  315.  
  316.   flags = TTLOAD_SCALE_GLYPH;
  317.   if ( hint )
  318.     flags |= TTLOAD_HINT_GLYPH;
  319.  
  320.   return TT_Load_Glyph( instance, glyph, idx, flags );
  321. }
  322.  
  323.  
  324. static ULONG  Render_All( void )
  325. {
  326.   TT_F26Dot6  x, y, z, minx, miny, maxx, maxy;
  327.   int         i, j;
  328.  
  329.   TT_Error    error;
  330.  
  331.   /* On the first pass, we compute the compound bounding box */
  332.  
  333.   x = y = 0;
  334.  
  335.   maxx = maxy = 0;
  336.   minx = miny = 0xFFFF;
  337.  
  338.   for ( i = 0; i < num_codes; i++ )
  339.   {
  340.     if ( !(error = LoadTrueTypeChar( glyph_code[i], hinted )) )
  341.     {
  342.       TT_Get_Glyph_Metrics( glyph, &metrics );
  343.  
  344.       z = x + metrics.bbox.xMin;
  345.       if ( minx > z )
  346.         minx = z;
  347.  
  348.       z = x + metrics.bbox.yMax;
  349.       if ( maxx < z )
  350.         maxx = z;
  351.  
  352.       z = y + metrics.bbox.yMin;
  353.       if ( miny > z )
  354.         miny = z;
  355.  
  356.       z = y + metrics.bbox.yMax;
  357.       if ( maxy < z )
  358.         maxy = z;
  359.  
  360.       x += metrics.advance & -64;
  361.     }
  362.     else
  363.       /* Fail++ */ ;
  364.   }
  365.  
  366.   minx = ( minx & -64 ) >> 6;
  367.   miny = ( miny & -64 ) >> 6;
  368.  
  369.   maxx = ( (maxx + 63) & -64 ) >> 6;
  370.   maxy = ( (maxy + 63) & -64 ) >> 6;
  371.  
  372.   if (minx > 0)
  373.     Bit.width = maxx + minx + 2;
  374.   else
  375.     Bit.width = maxx - minx + 2;
  376.  
  377.   Bit.rows  = maxy - miny;
  378.  
  379.   Bit.flow   = TT_Flow_Down;
  380.  
  381.   if ( font_smoothing )
  382.     Bit.cols = (Bit.width+3) & -4;
  383.   else
  384.     Bit.cols = (Bit.width+7) >> 3;
  385.  
  386.   Bit.size   = (long)Bit.cols * Bit.rows;
  387.  
  388.   if ( Bit.bitmap )
  389.     free( Bit.bitmap );
  390.   Bit.bitmap = malloc( (int)Bit.size );
  391.   if ( !Bit.bitmap )
  392.     return 1;  /* Error */
  393.  
  394.   Clear_Bit();
  395.  
  396.   /* On the second pass, we render each glyph to its centered position. */
  397.   /* This is slow, because we reload each glyph to render it!           */
  398.  
  399.   x = /*minx*/0;
  400.   y = miny;
  401.  
  402.   for (i = 0; i < num_codes; i++)
  403.   {
  404.     if (!(error = LoadTrueTypeChar(glyph_code[i], hinted)))
  405.     {
  406.       TT_Get_Glyph_Metrics(glyph, &metrics);
  407.  
  408.       Render_Single_Glyph(gray_render, glyph, x - minx, -y);
  409.  
  410.       x += metrics.advance / 64;
  411.     }
  412.   }
  413.  
  414.   return 0;  /* OK */
  415. }
  416.  
  417. /* Convert bitmap to REXX stem variable */
  418. int Process_Bitmap(TT_Raster_Map  *Bit, RXSTEMDATA *ldp, RXSTRING *retstr) {
  419.    int  i, j, k;
  420.    char elem;
  421.  
  422.    ldp->vlen = Bit->width;
  423.    ldp->shvb.shvnext = NULL;
  424.  
  425.    for (i = 0; i < Bit->rows; i++) {
  426.       for (j = 0; j < Bit->cols; j++) {
  427.          for (k = 7; k >= 0 ; k--) {
  428.             elem = (((char *)(Bit->bitmap))[i * Bit->cols + j] >> k) & 0x01;
  429.             ldp->ibuf[j * 8 + 7 - k] = elem ? 1 : 0;
  430.          }
  431.       }
  432.       /* now create one 'line' of stem variable */
  433.       sprintf(ldp->varname+ldp->stemlen, "%d", ldp->count);
  434.       ldp->count++;
  435.  
  436.       ldp->shvb.shvname.strptr = ldp->varname;
  437.       ldp->shvb.shvname.strlength = strlen(ldp->varname);
  438.       ldp->shvb.shvnamelen = ldp->shvb.shvname.strlength;
  439.       ldp->shvb.shvvalue.strptr = ldp->ibuf;
  440.       ldp->shvb.shvvalue.strlength = ldp->vlen;
  441.       ldp->shvb.shvvaluelen = ldp->vlen;
  442.       ldp->shvb.shvcode = RXSHV_SET;
  443.       ldp->shvb.shvret = 0;
  444.       if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN) {
  445.          BUILDRXSTRING(retstr, ERROR_REXXVAR);
  446.          return VALID_ROUTINE;        /* error on non-zero          */
  447.       }
  448.    }
  449.  
  450.                                      /* set stem.!rows to # of rows */
  451.   sprintf(ldp->ibuf, "%d", Bit->rows);
  452.   strcpy(&(ldp->varname[ldp->stemlen]), "!ROWS");
  453.   ldp->shvb.shvnext = NULL;
  454.   ldp->shvb.shvname.strptr = ldp->varname;
  455.   ldp->shvb.shvname.strlength = strlen(ldp->varname);
  456.   ldp->shvb.shvnamelen = strlen(ldp->varname);
  457.   ldp->shvb.shvvalue.strptr = ldp->ibuf;
  458.   ldp->shvb.shvvalue.strlength = strlen(ldp->ibuf);
  459.   ldp->shvb.shvvaluelen = ldp->shvb.shvvalue.strlength;
  460.   ldp->shvb.shvcode = RXSHV_SET;
  461.   ldp->shvb.shvret = 0;
  462.   if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN) {
  463.     BUILDRXSTRING(retstr, ERROR_REXXVAR);
  464.     return VALID_ROUTINE;              /* error on non-zero          */
  465.   }
  466.  
  467.                                   /* set stem.!cols to # of columns  */
  468.   sprintf(ldp->ibuf, "%d", Bit->width);
  469.   strcpy(&(ldp->varname[ldp->stemlen]), "!COLS");
  470.   ldp->shvb.shvnext = NULL;
  471.   ldp->shvb.shvname.strptr = ldp->varname;
  472.   ldp->shvb.shvname.strlength = strlen(ldp->varname);
  473.   ldp->shvb.shvnamelen = strlen(ldp->varname);
  474.   ldp->shvb.shvvalue.strptr = ldp->ibuf;
  475.   ldp->shvb.shvvalue.strlength = strlen(ldp->ibuf);
  476.   ldp->shvb.shvvaluelen = ldp->shvb.shvvalue.strlength;
  477.   ldp->shvb.shvcode = RXSHV_SET;
  478.   ldp->shvb.shvret = 0;
  479.   if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN) {
  480.     BUILDRXSTRING(retstr, ERROR_REXXVAR);
  481.     return VALID_ROUTINE;              /* error on non-zero          */
  482.   }
  483.  
  484.   return VALID_ROUTINE;                /* no error on call           */
  485. }
  486.  
  487. /*  int  rxttf_image( int  argc, char**  argv )*/
  488. ULONG rxttf_image(CHAR *name, ULONG numargs, RXSTRING args[],
  489.                   CHAR *queuename, RXSTRING *retstr)
  490. {
  491.   int    i;
  492.   int    XisSetup = 0;
  493.   char   filename[128 + 4];
  494.   char   *inputString;
  495.   int    option;
  496.   int    res = 96;
  497.  
  498.   TT_Error  error;
  499.  
  500.   RXSTEMDATA ldp;
  501.  
  502.   BUILDRXSTRING(retstr, NO_UTIL_ERROR); /* pass back result          */
  503.  
  504.   /* check  arguments */
  505.   if (numargs !=  4 ||
  506.       !RXVALIDSTRING(args[0]) ||
  507.       !RXVALIDSTRING(args[1]) ||
  508.       !RXVALIDSTRING(args[2]) ||
  509.       !RXVALIDSTRING(args[3]))
  510.     return INVALID_ROUTINE;            /* raise an error             */
  511.  
  512.   inputString = args[0].strptr;
  513.   strncpy(filename, args[1].strptr, 128);
  514.   ptsize = atoi(args[2].strptr); /* #### add error checking */
  515.  
  516.                                        /* Initialize data area       */
  517.   ldp.count = 0;
  518.   strcpy(ldp.varname, args[3].strptr);
  519.   ldp.stemlen = args[3].strlength;
  520.   strupr(ldp.varname);                 /* uppercase the name         */
  521.  
  522.   if (ldp.varname[ldp.stemlen-1] != '.')
  523.     ldp.varname[ldp.stemlen++] = '.';
  524.  
  525.   /* Initialize engine */
  526.   error = TT_Init_FreeType( &engine );
  527.   if ( error ) {
  528.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  529.     return VALID_ROUTINE;
  530.   }
  531.  
  532.   hinted = 1;
  533.  
  534.   filename[128] = '\0';
  535.  
  536.   /* Load typeface */
  537.   error = TT_Open_Face( engine, filename, &face );
  538.  
  539.   if ( error == TT_Err_Could_Not_Open_File ) {
  540.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  541.     return VALID_ROUTINE;
  542.   }
  543.   else if (error) {
  544.     BUILDRXSTRING(retstr, ERROR_FILEOPEN);
  545.     return VALID_ROUTINE;
  546.   }
  547.  
  548.   /* get face properties and allocate preload arrays */
  549.   TT_Get_Face_Properties( face, &properties );
  550.  
  551.   num_glyphs = properties.num_Glyphs;
  552.  
  553.   /* create glyph */
  554.   error = TT_New_Glyph( face, &glyph );
  555.   if ( error ) {
  556.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  557.     return VALID_ROUTINE;
  558.   }
  559.  
  560.   /* create instance */
  561.   error = TT_New_Instance( face, &instance );
  562.   if ( error ) {
  563.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  564.     return VALID_ROUTINE;
  565.   }
  566.  
  567.   error = TT_Set_Instance_Resolutions( instance, res, res );
  568.   if ( error ) {
  569.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  570.     return VALID_ROUTINE;
  571.   }
  572.  
  573.   if ( !XisSetup )
  574.   {
  575.     XisSetup = 1;
  576.  
  577.     if ( gray_render )
  578.     {
  579.       TT_Set_Raster_Gray_Palette( engine, virtual_palette );
  580.     }
  581.   }
  582.  
  583.   if (Reset_Scale( ptsize )) {
  584.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  585.     return VALID_ROUTINE;
  586.   }
  587.  
  588.   if (CharToUnicode(inputString)) {
  589.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  590.     return VALID_ROUTINE;
  591.   }
  592.  
  593.   if (Render_All()) {
  594.     BUILDRXSTRING(retstr, ERROR_ENGINE);
  595.     return VALID_ROUTINE;
  596.   }
  597.  
  598.   TT_Done_FreeType( engine );
  599.  
  600.   return Process_Bitmap(&Bit, &ldp, retstr);
  601.  
  602. }
  603.  
  604.