00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #ifdef HAVE_CONFIG_H
00057 # include "config.h"
00058 #endif
00059 #if NEED_GNUG_PRAGMAS
00060 # pragma implementation
00061 #endif
00062
00063
00064
00065
00066
00067 #include "GScaler.h"
00068
00069
00070 #ifdef HAVE_NAMESPACES
00071 namespace DJVU {
00072 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00073 }
00074 #endif
00075 #endif
00076
00077
00079
00080
00081
00082 #define FRACBITS 4
00083 #define FRACSIZE (1<<FRACBITS)
00084 #define FRACSIZE2 (FRACSIZE>>1)
00085 #define FRACMASK (FRACSIZE-1)
00086
00087
00088
00089
00090
00091
00093
00094
00095
00096 static int interp_ok = 0;
00097 static short interp[FRACSIZE][512];
00098
00099 static void
00100 prepare_interp()
00101 {
00102 if (! interp_ok)
00103 {
00104 interp_ok = 1;
00105 for (int i=0; i<FRACSIZE; i++)
00106 {
00107 short *deltas = & interp[i][256];
00108 for (int j = -255; j <= 255; j++)
00109 deltas[j] = ( j*i + FRACSIZE2 ) >> FRACBITS;
00110 }
00111 }
00112 }
00113
00114
00115 static inline int
00116 mini(int x, int y)
00117 {
00118 return (x < y ? x : y);
00119 }
00120
00121
00122 static inline int
00123 maxi(int x, int y)
00124 {
00125 return (x > y ? x : y);
00126 }
00127
00128
00129
00130
00131
00132
00134
00135
00136
00137 GScaler::GScaler()
00138 : inw(0), inh(0),
00139 xshift(0), yshift(0), redw(0), redh(0),
00140 outw(0), outh(0),
00141 gvcoord(vcoord,0), ghcoord(hcoord,0)
00142 {
00143 }
00144
00145
00146 GScaler::~GScaler()
00147 {
00148 }
00149
00150
00151 void
00152 GScaler::set_input_size(int w, int h)
00153 {
00154 inw = w;
00155 inh = h;
00156 if (vcoord)
00157 {
00158 gvcoord.resize(0);
00159 }
00160 if (hcoord)
00161 {
00162 ghcoord.resize(0);
00163 }
00164 }
00165
00166
00167 void
00168 GScaler::set_output_size(int w, int h)
00169 {
00170 outw = w;
00171 outh = h;
00172 if (vcoord)
00173 {
00174 gvcoord.resize(0);
00175 }
00176 if (hcoord)
00177 {
00178 ghcoord.resize(0);
00179 }
00180 }
00181
00182
00183 static void
00184 prepare_coord(int *coord, int inmax, int outmax, int in, int out)
00185 {
00186 int len = (in*FRACSIZE);
00187 int beg = (len+out)/(2*out) - FRACSIZE2;
00188
00189 int y = beg;
00190 int z = out/2;
00191 int inmaxlim = (inmax-1)*FRACSIZE;
00192 for (int x=0; x<outmax; x++)
00193 {
00194 coord[x] = mini(y,inmaxlim);
00195 z = z + len;
00196 y = y + z / out;
00197 z = z % out;
00198 }
00199
00200 if (out==outmax && y!=beg+len)
00201 G_THROW( ERR_MSG("GScaler.assertion") );
00202 }
00203
00204
00205 void
00206 GScaler::set_horz_ratio(int numer, int denom)
00207 {
00208 if (! (inw>0 && inh>0 && outw>0 && outh>0))
00209 G_THROW( ERR_MSG("GScaler.undef_size") );
00210
00211 if (numer==0 && denom==0) {
00212 numer = outw;
00213 denom = inw;
00214 } else if (numer<=0 || denom<=0)
00215 G_THROW( ERR_MSG("GScaler.ratios") );
00216
00217 xshift = 0;
00218 redw = inw;
00219 while (numer+numer < denom) {
00220 xshift += 1;
00221 redw = (redw + 1) >> 1;
00222 numer = numer << 1;
00223 }
00224
00225 if (! hcoord)
00226 ghcoord.resize(outw);
00227 prepare_coord(hcoord, redw, outw, denom, numer);
00228 }
00229
00230
00231 void
00232 GScaler::set_vert_ratio(int numer, int denom)
00233 {
00234 if (! (inw>0 && inh>0 && outw>0 && outh>0))
00235 G_THROW( ERR_MSG("GScaler.undef_size") );
00236
00237 if (numer==0 && denom==0) {
00238 numer = outh;
00239 denom = inh;
00240 } else if (numer<=0 || denom<=0)
00241 G_THROW( ERR_MSG("GScaler.ratios") );
00242
00243 yshift = 0;
00244 redh = inh;
00245 while (numer+numer < denom) {
00246 yshift += 1;
00247 redh = (redh + 1) >> 1;
00248 numer = numer << 1;
00249 }
00250
00251 if (! vcoord)
00252 {
00253 gvcoord.resize(outh);
00254 }
00255 prepare_coord(vcoord, redh, outh, denom, numer);
00256 }
00257
00258
00259 void
00260 GScaler::make_rectangles(const GRect &desired, GRect &red, GRect &inp)
00261 {
00262
00263 if (desired.xmin<0 || desired.ymin<0 ||
00264 desired.xmax>outw || desired.ymax>outh )
00265 G_THROW( ERR_MSG("GScaler.too_big") );
00266
00267 if (!vcoord)
00268 set_vert_ratio(0,0);
00269 if (!hcoord)
00270 set_horz_ratio(0,0);
00271
00272 red.xmin = (hcoord[desired.xmin]) >> FRACBITS;
00273 red.ymin = (vcoord[desired.ymin]) >> FRACBITS;
00274 red.xmax = (hcoord[desired.xmax-1]+FRACSIZE-1) >> FRACBITS;
00275 red.ymax = (vcoord[desired.ymax-1]+FRACSIZE-1) >> FRACBITS;
00276
00277 red.xmin = maxi(red.xmin, 0);
00278 red.xmax = mini(red.xmax+1, redw);
00279 red.ymin = maxi(red.ymin, 0);
00280 red.ymax = mini(red.ymax+1, redh);
00281
00282 inp.xmin = maxi(red.xmin<<xshift, 0);
00283 inp.xmax = mini(red.xmax<<xshift, inw);
00284 inp.ymin = maxi(red.ymin<<yshift, 0);
00285 inp.ymax = mini(red.ymax<<yshift, inh);
00286 }
00287
00288
00289 void
00290 GScaler::get_input_rect( const GRect &desired_output, GRect &required_input )
00291 {
00292 GRect red;
00293 make_rectangles(desired_output, red, required_input);
00294 }
00295
00296
00297
00298
00299
00300
00302
00303
00304
00305 GBitmapScaler::GBitmapScaler()
00306 : glbuffer(lbuffer,0), gconv(conv,0), gp1(p1,0), gp2(p2,0)
00307 {
00308 }
00309
00310
00311 GBitmapScaler::GBitmapScaler(int inw, int inh, int outw, int outh)
00312 : glbuffer(lbuffer,0), gconv(conv,0), gp1(p1,0), gp2(p2,0)
00313 {
00314 set_input_size(inw, inh);
00315 set_output_size(outw, outh);
00316 }
00317
00318
00319 GBitmapScaler::~GBitmapScaler()
00320 {
00321 }
00322
00323
00324 unsigned char *
00325 GBitmapScaler::get_line(int fy,
00326 const GRect &required_red,
00327 const GRect &provided_input,
00328 const GBitmap &input )
00329 {
00330 if (fy < required_red.ymin)
00331 fy = required_red.ymin;
00332 else if (fy >= required_red.ymax)
00333 fy = required_red.ymax - 1;
00334
00335 if (fy == l2)
00336 return p2;
00337 if (fy == l1)
00338 return p1;
00339
00340 unsigned char *p = p1;
00341 p1 = p2;
00342 l1 = l2;
00343 p2 = p;
00344 l2 = fy;
00345 if (xshift==0 && yshift==0)
00346 {
00347
00348 int dx = required_red.xmin-provided_input.xmin;
00349 int dx1 = required_red.xmax-provided_input.xmin;
00350 const unsigned char *inp1 = input[fy-provided_input.ymin] + dx;
00351 while (dx++ < dx1)
00352 *p++ = conv[*inp1++];
00353 return p2;
00354 }
00355 else
00356 {
00357
00358 GRect line;
00359 line.xmin = required_red.xmin << xshift;
00360 line.xmax = required_red.xmax << xshift;
00361 line.ymin = fy << yshift;
00362 line.ymax = (fy+1) << yshift;
00363 line.intersect(line, provided_input);
00364 line.translate(-provided_input.xmin, -provided_input.ymin);
00365
00366 const unsigned char *botline = input[line.ymin];
00367 int rowsize = input.rowsize();
00368 int sw = 1<<xshift;
00369 int div = xshift+yshift;
00370 int rnd = 1<<(div-1);
00371
00372 for (int x=line.xmin; x<line.xmax; x+=sw,p++)
00373 {
00374 int g=0, s=0;
00375 const unsigned char *inp0 = botline + x;
00376 int sy1 = mini(line.height(), (1<<yshift));
00377 for (int sy=0; sy<sy1; sy++,inp0+=rowsize)
00378 {
00379 const unsigned char *inp1;
00380 const unsigned char *inp2 = inp0 + mini(x+sw, line.xmax) - x;
00381 for (inp1=inp0; inp1<inp2; inp1++)
00382 {
00383 g += conv[*inp1];
00384 s += 1;
00385 }
00386 }
00387 if (s == rnd+rnd)
00388 *p = (g+rnd)>>div;
00389 else
00390 *p = (g+s/2)/s;
00391 }
00392
00393 return p2;
00394 }
00395 }
00396
00397
00398 void
00399 GBitmapScaler::scale( const GRect &provided_input, const GBitmap &input,
00400 const GRect &desired_output, GBitmap &output )
00401 {
00402
00403 GRect required_input;
00404 GRect required_red;
00405 make_rectangles(desired_output, required_red, required_input);
00406
00407 if (provided_input.width() != (int)input.columns() ||
00408 provided_input.height() != (int)input.rows() )
00409 G_THROW( ERR_MSG("GScaler.no_match") );
00410 if (provided_input.xmin > required_input.xmin ||
00411 provided_input.ymin > required_input.ymin ||
00412 provided_input.xmax < required_input.xmax ||
00413 provided_input.ymax < required_input.ymax )
00414 G_THROW( ERR_MSG("GScaler.too_small") );
00415
00416 if (desired_output.width() != (int)output.columns() ||
00417 desired_output.height() != (int)output.rows() )
00418 output.init(desired_output.height(), desired_output.width());
00419 output.set_grays(256);
00420
00421 gp1.resize(0);
00422 gp2.resize(0);
00423 glbuffer.resize(0);
00424 prepare_interp();
00425 const int bufw = required_red.width();
00426 glbuffer.resize(bufw+2);
00427 gp1.resize(bufw);
00428 gp2.resize(bufw);
00429 l1 = l2 = -1;
00430
00431 gconv.resize(0);
00432 gconv.resize(256);
00433 int maxgray = input.get_grays()-1;
00434 for (int i=0; i<256; i++)
00435 {
00436 conv[i]=(i<= maxgray)
00437 ?(((i*255) + (maxgray>>1)) / maxgray)
00438 :255;
00439 }
00440
00441 for (int y=desired_output.ymin; y<desired_output.ymax; y++)
00442 {
00443
00444 {
00445 int fy = vcoord[y];
00446 int fy1 = fy>>FRACBITS;
00447 int fy2 = fy1+1;
00448 const unsigned char *lower, *upper;
00449
00450 lower = get_line(fy1, required_red, provided_input, input);
00451 upper = get_line(fy2, required_red, provided_input, input);
00452
00453 unsigned char *dest = lbuffer+1;
00454 const short *deltas = & interp[fy&FRACMASK][256];
00455 for(unsigned char const * const edest=(unsigned char const *)dest+bufw;
00456 dest<edest;upper++,lower++,dest++)
00457 {
00458 const int l = *lower;
00459 const int u = *upper;
00460 *dest = l + deltas[u-l];
00461 }
00462 }
00463
00464 {
00465
00466 lbuffer[0] = lbuffer[1];
00467 lbuffer[bufw] = lbuffer[bufw];
00468 unsigned char *line = lbuffer+1-required_red.xmin;
00469 unsigned char *dest = output[y-desired_output.ymin];
00470
00471 for (int x=desired_output.xmin; x<desired_output.xmax; x++)
00472 {
00473 int n = hcoord[x];
00474 const unsigned char *lower = line + (n>>FRACBITS);
00475 const short *deltas = &interp[n&FRACMASK][256];
00476 int l = lower[0];
00477 int u = lower[1];
00478 *dest = l + deltas[u-l];
00479 dest++;
00480 }
00481 }
00482 }
00483
00484 gp1.resize(0);
00485 gp2.resize(0);
00486 glbuffer.resize(0);
00487 gconv.resize(0);
00488 }
00489
00490
00491
00492
00493
00494
00496
00497
00498
00499 GPixmapScaler::GPixmapScaler()
00500 : glbuffer((void *&)lbuffer,0,sizeof(GPixel)),
00501 gp1((void *&)p1,0,sizeof(GPixel)),
00502 gp2((void *&)p2,0,sizeof(GPixel))
00503 {
00504 }
00505
00506
00507 GPixmapScaler::GPixmapScaler(int inw, int inh, int outw, int outh)
00508 : glbuffer((void *&)lbuffer,0,sizeof(GPixel)),
00509 gp1((void *&)p1,0,sizeof(GPixel)),
00510 gp2((void *&)p2,0,sizeof(GPixel))
00511 {
00512 set_input_size(inw, inh);
00513 set_output_size(outw, outh);
00514 }
00515
00516
00517 GPixmapScaler::~GPixmapScaler()
00518 {
00519 }
00520
00521
00522 GPixel *
00523 GPixmapScaler::get_line(int fy,
00524 const GRect &required_red,
00525 const GRect &provided_input,
00526 const GPixmap &input )
00527 {
00528 if (fy < required_red.ymin)
00529 fy = required_red.ymin;
00530 else if (fy >= required_red.ymax)
00531 fy = required_red.ymax - 1;
00532
00533 if (fy == l2)
00534 return p2;
00535 if (fy == l1)
00536 return p1;
00537
00538 GPixel *p=p1;
00539 p1 = p2;
00540 l1 = l2;
00541 p2 = p;
00542 l2 = fy;
00543
00544 GRect line;
00545 line.xmin = required_red.xmin << xshift;
00546 line.xmax = required_red.xmax << xshift;
00547 line.ymin = fy << yshift;
00548 line.ymax = (fy+1) << yshift;
00549 line.intersect(line, provided_input);
00550 line.translate(-provided_input.xmin, -provided_input.ymin);
00551
00552 const GPixel *botline = input[line.ymin];
00553 int rowsize = input.rowsize();
00554 int sw = 1<<xshift;
00555 int div = xshift+yshift;
00556 int rnd = 1<<(div-1);
00557
00558 for (int x=line.xmin; x<line.xmax; x+=sw,p++)
00559 {
00560 int r=0, g=0, b=0, s=0;
00561 const GPixel *inp0 = botline + x;
00562 int sy1 = mini(line.height(), (1<<yshift));
00563 for (int sy=0; sy<sy1; sy++,inp0+=rowsize)
00564 {
00565 const GPixel *inp1;
00566 const GPixel *inp2 = inp0 + mini(x+sw, line.xmax) - x;
00567 for (inp1 = inp0; inp1<inp2; inp1++)
00568 {
00569 r += inp1->r;
00570 g += inp1->g;
00571 b += inp1->b;
00572 s += 1;
00573 }
00574 }
00575 if (s == rnd+rnd)
00576 {
00577 p->r = (r+rnd) >> div;
00578 p->g = (g+rnd) >> div;
00579 p->b = (b+rnd) >> div;
00580 }
00581 else
00582 {
00583 p->r = (r+s/2)/s;
00584 p->g = (g+s/2)/s;
00585 p->b = (b+s/2)/s;
00586 }
00587 }
00588
00589 return (GPixel *)p2;
00590 }
00591
00592
00593 void
00594 GPixmapScaler::scale( const GRect &provided_input, const GPixmap &input,
00595 const GRect &desired_output, GPixmap &output )
00596 {
00597
00598 GRect required_input;
00599 GRect required_red;
00600 make_rectangles(desired_output, required_red, required_input);
00601
00602 if (provided_input.width() != (int)input.columns() ||
00603 provided_input.height() != (int)input.rows() )
00604 G_THROW( ERR_MSG("GScaler.no_match") );
00605 if (provided_input.xmin > required_input.xmin ||
00606 provided_input.ymin > required_input.ymin ||
00607 provided_input.xmax < required_input.xmax ||
00608 provided_input.ymax < required_input.ymax )
00609 G_THROW( ERR_MSG("GScaler.too_small") );
00610
00611 if (desired_output.width() != (int)output.columns() ||
00612 desired_output.height() != (int)output.rows() )
00613 output.init(desired_output.height(), desired_output.width());
00614
00615 gp1.resize(0,sizeof(GPixel));
00616 gp2.resize(0,sizeof(GPixel));
00617 glbuffer.resize(0,sizeof(GPixel));
00618 prepare_interp();
00619 const int bufw = required_red.width();
00620 glbuffer.resize(bufw+2,sizeof(GPixel));
00621 if (xshift>0 || yshift>0)
00622 {
00623 gp1.resize(bufw,sizeof(GPixel));
00624 gp2.resize(bufw,sizeof(GPixel));
00625 l1 = l2 = -1;
00626 }
00627
00628 for (int y=desired_output.ymin; y<desired_output.ymax; y++)
00629 {
00630
00631 {
00632 int fy = vcoord[y];
00633 int fy1 = fy>>FRACBITS;
00634 int fy2 = fy1+1;
00635 const GPixel *lower, *upper;
00636
00637 if (xshift>0 || yshift>0)
00638 {
00639 lower = get_line(fy1, required_red, provided_input, input);
00640 upper = get_line(fy2, required_red, provided_input, input);
00641 }
00642 else
00643 {
00644 int dx = required_red.xmin-provided_input.xmin;
00645 fy1 = maxi(fy1, required_red.ymin);
00646 fy2 = mini(fy2, required_red.ymax-1);
00647 lower = input[fy1-provided_input.ymin] + dx;
00648 upper = input[fy2-provided_input.ymin] + dx;
00649 }
00650
00651 GPixel *dest = lbuffer+1;
00652 const short *deltas = & interp[fy&FRACMASK][256];
00653 for(GPixel const * const edest = (GPixel const *)dest+bufw;
00654 dest<edest;upper++,lower++,dest++)
00655 {
00656 const int lower_r = lower->r;
00657 const int delta_r = deltas[(int)upper->r - lower_r];
00658 dest->r = lower_r + delta_r;
00659 const int lower_g = lower->g;
00660 const int delta_g = deltas[(int)upper->g - lower_g];
00661 dest->g = lower_g + delta_g;
00662 const int lower_b = lower->b;
00663 const int delta_b = deltas[(int)upper->b - lower_b];
00664 dest->b = lower_b + delta_b;
00665 }
00666 }
00667
00668 {
00669
00670 lbuffer[0] = lbuffer[1];
00671 lbuffer[bufw] = lbuffer[bufw];
00672 GPixel *line = lbuffer+1-required_red.xmin;
00673 GPixel *dest = output[y-desired_output.ymin];
00674
00675 for (int x=desired_output.xmin; x<desired_output.xmax; x++,dest++)
00676 {
00677 const int n = hcoord[x];
00678 const GPixel *lower = line + (n>>FRACBITS);
00679 const short *deltas = &interp[n&FRACMASK][256];
00680 const int lower_r = lower[0].r;
00681 const int delta_r = deltas[(int)lower[1].r - lower_r];
00682 dest->r = lower_r + delta_r;
00683 const int lower_g = lower[0].g;
00684 const int delta_g = deltas[(int)lower[1].g - lower_g];
00685 dest->g = lower_g + delta_g;
00686 const int lower_b = lower[0].b;
00687 const int delta_b = deltas[(int)lower[1].b - lower_b];
00688 dest->b = lower_b + delta_b;
00689 }
00690 }
00691 }
00692
00693 gp1.resize(0,sizeof(GPixel));
00694 gp2.resize(0,sizeof(GPixel));
00695 glbuffer.resize(0,sizeof(GPixel));
00696 }
00697
00698
00699
00700 #ifdef HAVE_NAMESPACES
00701 }
00702 # ifndef NOT_USING_DJVU_NAMESPACE
00703 using namespace DJVU;
00704 # endif
00705 #endif
00706