void hqx_scale(gdImagePtr srcIm, int factor, gdImagePtr* result) { gdImagePtr dstIm; uint32_t *srcBuffer, *dstBuffer; size_t srcSize, dstSize; uint32_t w, h; uint32_t x, y; w = gdImageSX(srcIm); h = gdImageSY(srcIm); srcSize = sizeof(uint32_t) * w * h; dstSize = sizeof(uint32_t) * factor * w * factor * h; // Unfortunately it doesn't work to simply pass the gd buffer from the // gdImage struct to hqx, and the gd documentation explicitly says // not to access member fields directly. Thus we allocate two buffers // and copy the data back and forth as a workaround. srcBuffer = (uint32_t*)emalloc(srcSize); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { srcBuffer[w*y + x] = gdImageGetPixel(srcIm, x, y); } } dstBuffer = (uint32_t*)emalloc(dstSize); if (factor == 4) { hq4x_32_rb(srcBuffer, sizeof(uint32_t)*w, dstBuffer, sizeof(uint32_t)*factor*w, w, h); } else if (factor == 3) { hq3x_32_rb(srcBuffer, sizeof(uint32_t)*w, dstBuffer, sizeof(uint32_t)*factor*w, w, h); } else if (factor == 2) { hq2x_32_rb(srcBuffer, sizeof(uint32_t)*w, dstBuffer, sizeof(uint32_t)*factor*w, w, h); } dstIm = gdImageCreateTrueColor(factor*w, factor*h); gdImageAlphaBlending(dstIm, 0); gdImageSaveAlpha(dstIm, 1); for (y = 0; y < factor*h; y++) { for (x = 0; x < factor*w; x++) { gdImageSetPixel(dstIm, x, y, dstBuffer[factor*w*y + x]); } } efree(srcBuffer); efree(dstBuffer); *result = dstIm; }
/** * Internal 8-bit Zoomer without smoothing. * Source code originally from SDL_gfx (LGPL) with permission by author. * * Zooms 8bit palette/Y 'src' surface to 'dst' surface. * Assumes src and dst surfaces are of 8-bit depth. * Assumes dst surface was allocated with the correct dimensions. * * @param src The surface to zoom (input). * @param dst The zoomed surface (output). * @param flipx Flag indicating if the image should be horizontally flipped. * @param flipy Flag indicating if the image should be vertically flipped. * @return 0 for success or -1 for error. */ int Zoom::_zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy) { int x, y; static Uint32 *sax, *say; Uint32 *csax, *csay; int csx, csy; Uint8 *sp, *dp, *csp; int dgap; static bool proclaimed = false; if (Screen::is32bitEnabled()) { if (Options::useXBRZFilter) { // check the resolution to see which scale we need for (size_t factor = 2; factor <= 5; factor++) { if (dst->w == src->w * (int)factor && dst->h == src->h * (int)factor) { xbrz::scale(factor, (uint32_t*)src->pixels, (uint32_t*)dst->pixels, src->w, src->h, xbrz::RGB); return 0; } } } if (Options::useHQXFilter) { static bool initDone = false; if (!initDone) { hqxInit(); initDone = true; } // HQX_API void HQX_CALLCONV hq2x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height ); if (dst->w == src->w * 2 && dst->h == src->h * 2) { hq2x_32_rb((uint32_t*)src->pixels, src->pitch, (uint32_t*)dst->pixels, dst->pitch, src->w, src->h); return 0; } if (dst->w == src->w * 3 && dst->h == src->h * 3) { hq3x_32_rb((uint32_t*)src->pixels, src->pitch, (uint32_t*)dst->pixels, dst->pitch, src->w, src->h); return 0; } if (dst->w == src->w * 4 && dst->h == src->h * 4) { hq4x_32_rb((uint32_t*)src->pixels, src->pitch, (uint32_t*)dst->pixels, dst->pitch, src->w, src->h); return 0; } } } if (Options::useScaleFilter) { // check the resolution to see which of scale2x, scale3x, etc. we need for (size_t factor = 2; factor <= 4; factor++) { if (dst->w == src->w * (int)factor && dst->h == src->h * (int)factor && !scale_precondition(factor, src->format->BytesPerPixel, src->w, src->h)) { scale(factor, dst->pixels, dst->pitch, src->pixels, src->pitch, src->format->BytesPerPixel, src->w, src->h); return 0; } } } // if we're scaling by a factor of 2 or 4, try to use a more efficient function /* if (src->format->BytesPerPixel == 1 && dst->format->BytesPerPixel == 1) { #ifdef __SSE2__ static bool _haveSSE2 = haveSSE2(); if (_haveSSE2 && !((ptrdiff_t)src->pixels % 16) && !((ptrdiff_t)dst->pixels % 16)) // alignment check { if (dst->w == src->w * 2 && dst->h == src->h * 2) return zoomSurface2X_SSE2(src, dst); else if (dst->w == src->w * 4 && dst->h == src->h * 4) return zoomSurface4X_SSE2(src, dst); } else { static bool complained = false; if (!complained) { complained = true; Log(LOG_ERROR) << "Misaligned surface buffers."; } } #endif // __WORDSIZE is defined on Linux, SIZE_MAX on Windows #if defined(__WORDSIZE) && (__WORDSIZE == 64) || defined(SIZE_MAX) && (SIZE_MAX > 0xFFFFFFFF) if (dst->w == src->w * 2 && dst->h == src->h * 2) return zoomSurface2X_64bit(src, dst); else if (dst->w == src->w * 4 && dst->h == src->h * 4) return zoomSurface4X_64bit(src, dst); #else if (sizeof(void *) == 8) { if (dst->w == src->w * 2 && dst->h == src->h * 2) return zoomSurface2X_64bit(src, dst); else if (dst->w == src->w * 4 && dst->h == src->h * 4) return zoomSurface4X_64bit(src, dst); } else { if (dst->w == src->w * 2 && dst->h == src->h * 2) return zoomSurface2X_32bit(src, dst); else if (dst->w == src->w * 4 && dst->h == src->h * 4) return zoomSurface4X_32bit(src, dst); } #endif // maybe X is scaled by 2 or 4 but not Y? if (dst->w == src->w * 4) return zoomSurface4X_XAxis_32bit(src, dst); else if (dst->w == src->w * 2) return zoomSurface2X_XAxis_32bit(src, dst); } */ if (!proclaimed) { Log(LOG_INFO) << "Using software scaling routine. For best results, try an OpenGL filter."; proclaimed = true; } /* * Allocate memory for row increments */ if ((sax = (Uint32 *) realloc(sax, (dst->w + 1) * sizeof(Uint32))) == NULL) { sax = 0; return (-1); } if ((say = (Uint32 *) realloc(say, (dst->h + 1) * sizeof(Uint32))) == NULL) { say = 0; //free(sax); return (-1); } /* * Pointer setup */ sp = csp = (Uint8 *) src->pixels; dp = (Uint8 *) dst->pixels; dgap = dst->pitch - dst->w; if (flipx) csp += (src->w-1); if (flipy) csp = ( (Uint8*)csp + src->pitch*(src->h-1) ); /* * Precalculate row increments */ csx = 0; csax = sax; for (x = 0; x < dst->w; x++) { csx += src->w; *csax = 0; while (csx >= dst->w) { csx -= dst->w; (*csax)++; } (*csax) *= (flipx ? -1 : 1); csax++; } csy = 0; csay = say; for (y = 0; y < dst->h; y++) { csy += src->h; *csay = 0; while (csy >= dst->h) { csy -= dst->h; (*csay)++; } (*csay) *= src->pitch * (flipy ? -1 : 1); csay++; } /* * Draw */ csay = say; for (y = 0; y < dst->h; y++) { csax = sax; sp = csp; for (x = 0; x < dst->w; x++) { /* * Draw */ *dp = *sp; /* * Advance source pointers */ sp += (*csax); csax++; /* * Advance destination pointer */ dp++; } /* * Advance source pointer (for row) */ csp += (*csay); csay++; /* * Advance destination pointers */ dp += dgap; } /* * Never remove temp arrays */ //free(sax); //free(say); return 0; }