/* zoom() Resizes bitmaps while resampling them. Returns -1 if error, 0 if success. */ int zoom( ILimage *dst, ILimage *src, double (*filterf)(double), double fwidth) { ILubyte* tmp; double xscale, yscale; /* zoom scale factors */ int xx; int i, j, k; /* loop variables */ int n; /* pixel number */ double center, left, right; /* filter calculation variables */ double width, fscale, weight; /* filter calculation variables */ ILubyte pel, pel2; int bPelDelta; CLIST *contribY; /* array of contribution lists */ CLIST contribX; int nRet = -1; /* create intermediate column to hold horizontal dst column zoom */ tmp = (ILubyte*)ialloc(src->Height * sizeof(ILubyte)); if (tmp == NULL) { return 0; } xscale = (double) dst->Width / (double) src->Width; /* Build y weights */ /* pre-calculate filter contributions for a column */ contribY = (CLIST*)icalloc(dst->Height, sizeof(CLIST)); if (contribY == NULL) { ifree(tmp); return -1; } yscale = (double) dst->Height / (double) src->Height; if(yscale < 1.0) { width = fwidth / yscale; fscale = 1.0 / yscale; for(i = 0; i < (ILint)dst->Height; ++i) { contribY[i].n = 0; contribY[i].p = (CONTRIB*)icalloc((int) (width * 2 + 1), sizeof(CONTRIB)); if(contribY[i].p == NULL) { ifree(tmp); ifree(contribY); return -1; } center = (double) i / yscale; left = ceil(center - width); right = floor(center + width); for(j = (int)left; j <= right; ++j) { weight = center - (double) j; weight = (*filterf)(weight / fscale) / fscale; n = wrap_filter_sample(j, src->Height); k = contribY[i].n++; contribY[i].p[k].pixel = n; contribY[i].p[k].weight = weight; } } } else { for(i = 0; i < (ILint)dst->Height; ++i) { contribY[i].n = 0; contribY[i].p = (CONTRIB*)icalloc((int) (fwidth * 2 + 1), sizeof(CONTRIB)); if (contribY[i].p == NULL) { ifree(tmp); ifree(contribY); return -1; } center = (double) i / yscale; left = ceil(center - fwidth); right = floor(center + fwidth); for(j = (int)left; j <= right; ++j) { weight = center - (double) j; weight = (*filterf)(weight); n = wrap_filter_sample(j, src->Height); k = contribY[i].n++; contribY[i].p[k].pixel = n; contribY[i].p[k].weight = weight; } } } for(xx = 0; xx < (ILint)dst->Width; xx++) { if(0 != calc_x_contrib(&contribX, xscale, fwidth, dst->Width, src->Width, filterf, xx)) { goto __zoom_cleanup; } /* Apply horz filter to make dst column in tmp. */ for(k = 0; k < (ILint)src->Height; ++k) { weight = 0.0; bPelDelta = IL_FALSE; // Denton: Put get_pixel source here //pel = get_pixel(src, contribX.p[0].pixel, k); pel = src->Data[k * src->Bps + contribX.p[0].pixel * src->Bpp + c]; for(j = 0; j < contribX.n; ++j) { // Denton: Put get_pixel source here //pel2 = get_pixel(src, contribX.p[j].pixel, k); pel2 = src->Data[k * src->Bps + contribX.p[j].pixel * src->Bpp + c]; if(pel2 != pel) bPelDelta = IL_TRUE; weight += pel2 * contribX.p[j].weight; } weight = bPelDelta ? roundcloser(weight) : pel; tmp[k] = (ILubyte)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL); } /* next row in temp column */ ifree(contribX.p); /* The temp column has been built. Now stretch it vertically into dst column. */ for(i = 0; i < (ILint)dst->Height; ++i) { weight = 0.0; bPelDelta = IL_FALSE; pel = tmp[contribY[i].p[0].pixel]; for(j = 0; j < contribY[i].n; ++j) { pel2 = tmp[contribY[i].p[j].pixel]; if(pel2 != pel) bPelDelta = IL_TRUE; weight += pel2 * contribY[i].p[j].weight; } weight = bPelDelta ? roundcloser(weight) : pel; // Denton: Put set_pixel source here //put_pixel(dst, xx, i, (ILubyte)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL)); dst->Data[i * dst->Bps + xx * dst->Bpp + c] = (ILubyte)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL); } /* next dst row */ } /* next dst column */ nRet = 0; /* success */ __zoom_cleanup: ifree(tmp); // Free the memory allocated for vertical filter weights for (i = 0; i < (ILint)dst->Height; ++i) ifree(contribY[i].p); ifree(contribY); return nRet; } /* zoom */
//--------------------------------------------------------------------------- static int ib_resample(tTVPBaseBitmap *dst, const tTVPRect &destrect, const tTVPBaseBitmap *src, const tTVPRect &srcrect, real_t (*filterf)(real_t), // void (*blend)(tjs_uint32 *dest, tjs_uint32 src), real_t fwidth) { pixel_t * tmp; real_t xscale, yscale; /* zoom scale factors */ int xx; int i, j, k; /* loop variables */ int n; /* pixel number */ real_t center, left, right; /* filter calculation variables */ real_t width, fscale; /* filter calculation variables */ pixel_real_t_t weight; pixel_t pel, pel2; pixel_t bPelDelta; CLIST *contribY; /* array of contribution lists */ CLIST contribX; int nRet = -1; int srcwidth = srcrect.get_width(); int srcheight = srcrect.get_height(); int destwidth = destrect.get_width(); int destheight = destrect.get_height(); /* create intermediate column to hold horizontal dst column zoom */ tmp = (pixel_t*)malloc(srcheight * sizeof(pixel_t)); if(tmp == NULL) return 0; xscale = (real_t) destwidth / (real_t) srcwidth; /* Build y weights */ /* pre-calculate filter contributions for a column */ contribY = (CLIST *)calloc(destheight, sizeof(CLIST)); if(contribY == NULL) { free(tmp); return -1; } yscale = (real_t) destheight / (real_t) srcheight; if(yscale < 1.0) { real_t weight; width = fwidth / yscale; fscale = static_cast<real_t>(1.0 / yscale); for(i = 0; i < destheight; ++i) { real_t w_sum = 0; contribY[i].n = 0; contribY[i].p = (CONTRIB *)calloc((int) (width * 2 + 1), sizeof(CONTRIB)); if(contribY[i].p == NULL) { free(tmp); free(contribY); return -1; } center = (real_t) i * fscale; left = ceil(center - width); right = floor(center + width); for(j = (int)left; j <= right; ++j) { weight = center - (real_t) j; weight = (*filterf)(weight * yscale); //* yscale; w_sum += weight; if(j < 0) { n = -j; } else if(j >= srcheight) { n = (srcheight - j) + srcheight - 1; } else { n = j; } if(n < 0) n = 0; if(n >= srcheight - 1) n = srcheight - 1; k = contribY[i].n++; contribY[i].p[k].pixel = n; contribY[i].p[k].weight = weight; } if(w_sum != 0.0) { w_sum = static_cast<real_t>(1.0 / w_sum); for(j = 0; j < contribY[i].n; j ++) contribY[i].p[j].weight *= w_sum; } } } else { real_t weight; for(i = 0; i < destheight; ++i) { contribY[i].n = 0; contribY[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), sizeof(CONTRIB)); if(contribY[i].p == NULL) { free(tmp); free(contribY); return -1; } center = (real_t) i / yscale; left = ceil(center - fwidth); right = floor(center + fwidth); for(j = (int)left; j <= right; ++j) { weight = center - (real_t) j; weight = (*filterf)(weight); if(j < 0) { n = -j; } else if(j >= srcheight) { n = (srcheight - j) + srcheight - 1; } else { n = j; } if(n < 0) n = 0; if(n >= srcheight - 1) n = srcheight - 1; k = contribY[i].n++; contribY[i].p[k].pixel = n; contribY[i].p[k].weight = weight; } } } const pixel_t *srclinestart = (const pixel_t*)src->GetScanLine(srcrect.top) + srcrect.left; tjs_int srcpitchbytes = src->GetPitchBytes(); pixel_t *destlinestart = (pixel_t*)dst->GetScanLineForWrite(destrect.top) + destrect.left; tjs_int destpitchbytes = dst->GetPitchBytes(); for(xx = 0; xx < destwidth; xx++) { if(0 != calc_x_contrib(&contribX, xscale, fwidth, destwidth, srcwidth, filterf, xx)) { goto __zoom_cleanup; } /* Apply horz filter to make dst column in tmp. */ { const pixel_t *line = srclinestart; for(k = 0; k < srcheight; ++k) { weight.r = weight.g = weight.b = weight.a = 0; bPelDelta.r = bPelDelta.g = bPelDelta.b = bPelDelta.a = FALSE; pel = line[contribX.p[0].pixel]; for(j = contribX.n - 1; j >= 0; --j) { CONTRIB *c = contribX.p + j; pel2 = line[c->pixel]; bPelDelta.r |= (pel2.r - pel.r); bPelDelta.b |= (pel2.b - pel.b); bPelDelta.g |= (pel2.g - pel.g); bPelDelta.a |= (pel2.a - pel.a); weight.r += pel2.r * c->weight; weight.g += pel2.g * c->weight; weight.b += pel2.b * c->weight; weight.a += pel2.a * c->weight; } weight.r = static_cast<real_t>(bPelDelta.r ? roundcloser(weight.r) : pel.r); weight.g = static_cast<real_t>(bPelDelta.g ? roundcloser(weight.g) : pel.g); weight.b = static_cast<real_t>(bPelDelta.b ? roundcloser(weight.b) : pel.b); weight.a = static_cast<real_t>(bPelDelta.a ? roundcloser(weight.a) : pel.a); tmp[k].r = (unsigned char)CLAMP(static_cast<int>(weight.r), 0, 255); tmp[k].g = (unsigned char)CLAMP(static_cast<int>(weight.g), 0, 255); tmp[k].b = (unsigned char)CLAMP(static_cast<int>(weight.b), 0, 255); tmp[k].a = (unsigned char)CLAMP(static_cast<int>(weight.a), 0, 255); //(tjs_uint8*)(line) += srcpitchbytes; const tjs_uint8* b = reinterpret_cast<const tjs_uint8*>(line); b += srcpitchbytes; line = reinterpret_cast<const pixel_t*>(b); } /* next row in temp column */ } free(contribX.p); /* The temp column has been built. Now stretch it vertically into dst column. */ { pixel_t *line = destlinestart; for(i = 0; i < destheight; ++i) { CLIST *cl = contribY + i; weight.r = weight.g = weight.b = weight.a = 0; bPelDelta.r = bPelDelta.g = bPelDelta.b = bPelDelta.a = FALSE; pel = tmp[cl->p[0].pixel]; for(j = cl->n - 1; j >= 0; --j) { CONTRIB *c = cl->p + j; pel2 = tmp[c->pixel]; bPelDelta.r |= (pel2.r - pel.r); bPelDelta.b |= (pel2.b - pel.b); bPelDelta.g |= (pel2.g - pel.g); bPelDelta.a |= (pel2.a - pel.a); weight.r += pel2.r * c->weight; weight.g += pel2.g * c->weight; weight.b += pel2.b * c->weight; weight.a += pel2.a * c->weight; } weight.r = static_cast<real_t>(bPelDelta.r ? roundcloser(weight.r) : pel.r); weight.g = static_cast<real_t>(bPelDelta.g ? roundcloser(weight.g) : pel.g); weight.b = static_cast<real_t>(bPelDelta.b ? roundcloser(weight.b) : pel.b); weight.a = static_cast<real_t>(bPelDelta.a ? roundcloser(weight.a) : pel.a); line[xx].r = (unsigned char)CLAMP(static_cast<int>(weight.r), 0, 255); line[xx].g = (unsigned char)CLAMP(static_cast<int>(weight.g), 0, 255); line[xx].b = (unsigned char)CLAMP(static_cast<int>(weight.b), 0, 255); line[xx].a = (unsigned char)CLAMP(static_cast<int>(weight.a), 0, 255); const tjs_uint8* b = reinterpret_cast<const tjs_uint8*>(line); b += destpitchbytes; line = const_cast<pixel_t*>(reinterpret_cast<const pixel_t*>(b)); //(const tjs_uint8*)(line) += destpitchbytes; } /* next dst row */ } } /* next dst column */ nRet = 0; /* success */ __zoom_cleanup: free(tmp); /* free the memory allocated for vertical filter weights */ for(i = 0; i < destheight; ++i) free(contribY[i].p); free(contribY); return nRet; } /* ib_resample */