Back to index

texmacs  1.0.7.15
glyph_shrink.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : glyph_shrink.cpp
00004 * DESCRIPTION: shrinking glyphs for anti-aliasing
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "bitmap_font.hpp"
00013 #include "renderer.hpp"
00014 
00015 static int
00016 log2i (int i) {
00017   int l;
00018   if (i==1) return 0;
00019   for (l=1; l<30; l++)
00020     if (i <= (1 << l)) return l;
00021   FAILED ("too large shrinking factor");
00022   return 0;
00023 }
00024 
00025 static int
00026 my_div (int a, int b) {
00027   if (a>=0) return a/b;
00028   else return -((b-1-a)/b);
00029 }
00030 
00031 static int
00032 my_mod (int a, int b) {
00033   if (a>=0) return a%b;
00034   else return b-1-((-1-a)%b);
00035 }
00036 
00037 static int
00038 my_norm (int a, int m) {
00039   a= my_mod (a, m);
00040   if (a<=(m>>1)) return a;
00041   else return m-a;
00042 }
00043 
00044 int
00045 get_hor_shift (glyph gl, int xfactor, int tx) {
00046   STACK_NEW_ARRAY (flag, bool, gl->width);
00047 
00048   // cout << "[";
00049   int x;
00050   for (x=0; x<gl->width; x++) {
00051     int max_count= 0, count=0, y;
00052     for (y=0; y<gl->height; y++)
00053       if (gl->get_1 (x,y)) count++;
00054       else {
00055        max_count = max (max_count, count);
00056        count     = 0;
00057       }
00058     max_count= max (max_count, count);
00059     flag[x]= (max_count>(gl->height>>1));
00060     // if (flag[x]) cout << "*"; else cout << " ";
00061   }
00062   // cout << "]   ";
00063 
00064   int first0=-1, first1=-1, last0=-1, last1=-1;
00065   for (x=0; x<gl->width; x++)
00066     if (flag[x]) {
00067       if (first0<0) first0= x;
00068       last0= x;
00069       while ((x<gl->width) && flag[x]) x++;
00070       if (first1<0) first1= x+ tx;
00071       last1= x+ tx;
00072       x--;
00073     }
00074   /* cout << first0 << ", " << first1 << ", "
00075      << last0  << ", " << last1  << "\n"; */
00076 
00077   STACK_DELETE_ARRAY (flag);
00078 
00079   if (first0==-1) return 0;
00080   if (first0==last0) return my_mod (gl->xoff- first0, xfactor);
00081 
00082   int first, last;
00083   int d00= my_norm (last0- first0, xfactor);
00084   int d01= my_norm (last1- first0, xfactor);
00085   int d10= my_norm (last0- first1, xfactor);
00086   int d11= my_norm (last1- first1, xfactor);
00087   if ((d00<=d01) && (d00<=d10) && (d00<=d11)) { first= first0; last= last0; }
00088   else if ((d01<=d10) && (d01<=d11)) { first= first0; last= last1; }
00089   else if (d10<=d11) { first= first1; last= last0; }
00090   else { first= first1; last= last1; }
00091 
00092   int middle, rest= my_mod (last- first, xfactor);
00093   if (rest <= (xfactor>>1)) middle= first+ (rest>>1);
00094   else middle= first- ((xfactor-rest)>>1);
00095   return my_mod (gl->xoff- middle, xfactor);
00096 }
00097 
00098 int
00099 get_ver_shift (glyph gl, int yfactor, int ty) {
00100   STACK_NEW_ARRAY (flag, bool, gl->height);
00101 
00102   // cout << "[";
00103   int y;
00104   for (y=0; y<gl->height; y++) {
00105     int max_count= 0, count=0, x;
00106     for (x=0; x<gl->width; x++)
00107       if (gl->get_1 (x,y)) count++;
00108       else {
00109        max_count = max (max_count, count);
00110        count     = 0;
00111       }
00112     max_count= max (max_count, count);
00113     flag[y]= (max_count>(gl->width>>1));
00114     // if (flag[y]) cout << "*"; else cout << " ";
00115   }
00116   // cout << "]   ";
00117 
00118   int first0=-1, first1=-1, last0=-1, last1=-1;
00119   for (y=0; y<gl->height; y++)
00120     if (flag[y]) {
00121       if (first0<0) first0= y;
00122       last0= y;
00123       while ((y<gl->height) && flag[y]) y++;
00124       if (first1<0) first1= y+ ty;
00125       last1= y+ ty;
00126       y--;
00127     }
00128   /* cout << first0 << ", " << first1 << ", "
00129      << last0  << ", " << last1  << "\n"; */
00130 
00131   STACK_DELETE_ARRAY (flag);
00132 
00133   if (first0==-1) return 0;
00134   if (first0==last0)
00135     return my_mod (gl->height- gl->yoff- 1- first0, yfactor);
00136 
00137   int first, last;
00138   int d00= my_norm (last0- first0, yfactor);
00139   int d01= my_norm (last1- first0, yfactor);
00140   int d10= my_norm (last0- first1, yfactor);
00141   int d11= my_norm (last1- first1, yfactor);
00142   if ((d00<=d01) && (d00<=d10) && (d00<=d11)) { first= first0; last= last0; }
00143   else if ((d01<=d10) && (d01<=d11)) { first= first0; last= last1; }
00144   else if (d10<=d11) { first= first1; last= last0; }
00145   else { first= first1; last= last1; }
00146 
00147   int middle, rest= my_mod (last- first, yfactor);
00148   if (rest <= (yfactor>>1)) middle= first+ (rest>>1);
00149   else middle= first- ((yfactor-rest)>>1);
00150   return my_mod (gl->height- gl->yoff- 1- middle, yfactor);
00151 }
00152 
00153 glyph
00154 shrink (glyph gl, int xfactor, int yfactor,
00155        int dx, int dy, int tx, int ty, SI& xo, SI& yo)
00156 {
00157   /*
00158   cout << "------------------------------------------------------------------------------\n";
00159   cout << "Shift by " << dx << ", " << dy << "\n";
00160   cout << "------------------------------------------------------------------------------\n\n";
00161   cout << gl << "\n";
00162   */
00163 
00164   int x1= dx- gl->xoff;
00165   int x2= dx- gl->xoff+ gl->width+ tx;
00166   int X1= my_div (x1, xfactor);
00167   int X2= my_div (x2+xfactor-1, xfactor);
00168 
00169   int y1= dy+ gl->yoff+ 1- gl->height;
00170   int y2= dy+ gl->yoff+ 1+ ty;
00171   int Y1= my_div (y1, yfactor);
00172   int Y2= my_div (y2+yfactor-1, yfactor);
00173 
00174   int frac_x= (dx- gl->xoff- X1*xfactor);
00175   int frac_y= (dy+ gl->yoff- Y1*yfactor);
00176   SI  off_x = (((-X1) *xfactor+ dx)*PIXEL + ((tx*PIXEL)>>1))/xfactor;
00177   SI  off_y = (((Y2-1)*yfactor- dy)*PIXEL - ((ty*PIXEL)>>1))/yfactor;
00178 
00179   int i, j, x, y;
00180   int index, indey, entry;
00181   int ww=(X2-X1)*xfactor, hh=(Y2-Y1)*yfactor;
00182   STACK_NEW_ARRAY (bitmap, int, ww*hh);
00183   for (i=0; i<ww*hh; i++) bitmap[i]=0;
00184   for (y=0, index= ww*frac_y+ frac_x; y<gl->height; y++, index-=ww)
00185     for (x=0; x<gl->width; x++)
00186       if (gl->get_1(x,y))
00187         for (j=0, indey=ww*ty; j<=ty; j++, indey-=ww) {
00188          entry = index+indey+x;
00189          for (i=0; i<=tx; i++, entry++)
00190            bitmap[entry]= 1;
00191        }
00192 
00193   int X, Y, sum, nr= xfactor*yfactor;
00194   int new_depth= gl->depth+ log2i (nr);
00195   if (new_depth > 8) new_depth= 8;
00196   glyph CB (X2-X1, Y2-Y1, -X1, Y2-1, new_depth, gl->status);
00197   for (Y=Y1; Y<Y2; Y++)
00198     for (X=X1; X<X2; X++) {
00199       sum=0;
00200       indey= ((Y-Y1)*ww+ (X-X1))*xfactor;
00201       for (j=0, index= indey; j<yfactor; j++, index+=ww)
00202        for (i=0; i<xfactor; i++)
00203          sum += bitmap[index+ i];
00204       if (nr >= 64) sum= (64 * sum) / nr;
00205       CB->set (X, Y, sum);
00206     }
00207   xo= off_x;
00208   yo= off_y;
00209   STACK_DELETE_ARRAY (bitmap);
00210 
00211   // cout << CB << "\n";
00212   return CB;
00213 }
00214 
00215 glyph
00216 shrink (glyph gl, int xfactor, int yfactor, SI& xo, SI& yo) {
00217   if ((gl->width==0) || (gl->height==0))
00218     FAILED ("zero size character");
00219 
00220   int tx= xfactor/3;
00221   int ty= yfactor/3;
00222   int dx=0, dy=0;
00223   if ((gl->status==0) && (xfactor>1)) dx= get_hor_shift (gl, xfactor, tx);
00224   // if ((gl->status==0) && (yfactor>1)) dy= get_ver_shift (gl, yfactor, ty);
00225 
00226   glyph ret= shrink (gl, xfactor, yfactor, dx, dy, tx, ty, xo, yo);
00227 #ifndef QTTEXMACS
00228   if (ret->status != 0) {
00229     if (ret->status&1) ret->adjust_top ();
00230     if (ret->status&2) ret->adjust_bot ();
00231     ret->yoff= yo= 0;
00232   }
00233 #endif
00234   return ret;
00235 }