const BitmapData* BitmapData::fromAsset(const char* name) { loom_asset_image_t* img = static_cast<loom_asset_image_t*>(loom_asset_lock(name, LATImage, 1)); loom_asset_unlock(name); if (img == NULL) return NULL; BitmapData* result = lmNew(NULL) BitmapData( (size_t)img->width, (size_t)img->height ); if (result == NULL) { lmLogError(gGFXLogGroup, "Unable to allocate memory for BitmapData asset data"); return NULL; } memcpy(result->data, img->bits, img->width * img->height * DATA_BPP); return result; }
static int __stdcall scaleImageOnDisk_body(void *param) { // Grab our arguments. RescaleNote *rn = (RescaleNote *)param; const char *outPath = rn->outPath.c_str(); const char *inPath = rn->inPath.c_str(); int outWidth = rn->outWidth; int outHeight = rn->outHeight; bool preserveAspect = rn->preserveAspect; // Load the image. We always work in 4 components (rgba). int t0 = platform_getMilliseconds(); loom_asset_image *lai = NULL; // Load async since we're in a background thread. while ((lai = (loom_asset_image *)loom_asset_lock(inPath, LATImage, 0)) == NULL) { loom_thread_yield(); } int imageX = lai->width; int imageY = lai->height; stbi_uc *imageBits = (stbi_uc *)lai->bits; lmLog(gGFXTextureLogGroup, "Image setup took %dms", t0 - platform_getMilliseconds()); int t1 = platform_getMilliseconds(); // Resize to fit within the specified size preserving aspect ratio, if flag is set. if (preserveAspect) { float scaleX = float(outWidth) / float(imageX); float scaleY = float(outHeight) / float(imageY); float actualScale = (scaleX < scaleY) ? scaleX : scaleY; outWidth = (int)(imageX * actualScale); outHeight = (int)(imageY * actualScale); lmLog(gGFXTextureLogGroup, "Scale to %d %d due to scale %f %f actual=%f", outWidth, outHeight, scaleX, scaleY, actualScale); } // Build a buffer for byte->float conversions... Resampler::Sample *buffRed = (Resampler::Sample *)malloc(sizeof(Resampler::Sample) * imageX); Resampler::Sample *buffGreen = (Resampler::Sample *)malloc(sizeof(Resampler::Sample) * imageX); Resampler::Sample *buffBlue = (Resampler::Sample *)malloc(sizeof(Resampler::Sample) * imageX); // And the downsampled image. Give a slight margin because the scaling routine above can give // up to outWidth inclusive as an output value. stbi_uc *outBuffer = (stbi_uc *)malloc(sizeof(stbi_uc) * 3 * (outWidth + 1) * (outHeight + 1)); // Set up the resamplers, reusing filter constants. const char *pFilter = "blackman"; float filter_scale = 1.0; Resampler resizeR(imageX, imageY, outWidth, outHeight, Resampler::BOUNDARY_CLAMP, 0.0f, 1.0f, pFilter, NULL, NULL, filter_scale, filter_scale); Resampler resizeG(imageX, imageY, outWidth, outHeight, Resampler::BOUNDARY_CLAMP, 0.0f, 1.0f, pFilter, resizeR.get_clist_x(), resizeR.get_clist_y(), filter_scale, filter_scale); Resampler resizeB(imageX, imageY, outWidth, outHeight, Resampler::BOUNDARY_CLAMP, 0.0f, 1.0f, pFilter, resizeR.get_clist_x(), resizeR.get_clist_y(), filter_scale, filter_scale); int resultY = 0; lmLog(gGFXTextureLogGroup, "Resample setup took %dms", t1 - platform_getMilliseconds()); int t2 = platform_getMilliseconds(); // Process each row of the image. for (int y = 0; y < imageY; y++) { // Deinterleave each row. for (int x = 0; x < imageX; x++) { buffRed[x] = Resampler::Sample(imageBits[(y * imageX * 4) + (x * 4) + 0]) / Resampler::Sample(255.f); buffGreen[x] = Resampler::Sample(imageBits[(y * imageX * 4) + (x * 4) + 1]) / Resampler::Sample(255.f); buffBlue[x] = Resampler::Sample(imageBits[(y * imageX * 4) + (x * 4) + 2]) / Resampler::Sample(255.f); } // Submit to resampler. lmAssert(resizeR.put_line(buffRed), "bad red"); lmAssert(resizeG.put_line(buffGreen), "bad green"); lmAssert(resizeB.put_line(buffBlue), "bad blue"); // If there are results, reinterleave and consume them. while (resizeR.check_line() && resizeG.check_line() && resizeB.check_line() && resultY < outHeight) { const Resampler::Sample *outRowR = resizeR.get_line(); const Resampler::Sample *outRowG = resizeG.get_line(); const Resampler::Sample *outRowB = resizeB.get_line(); if (outRowR || outRowG || outRowB) { lmAssert(outRowR && outRowG && outRowB, "Somehow got one line without others!"); } else { break; } // Find the row for output. stbi_uc *imageOutBits = outBuffer + (resultY * outWidth * 3); resultY++; for (int i = 0; i < outWidth; i++) { imageOutBits[i * 3 + 0] = int(outRowR[i] * Resampler::Sample(255.f)); imageOutBits[i * 3 + 1] = int(outRowG[i] * Resampler::Sample(255.f)); imageOutBits[i * 3 + 2] = int(outRowB[i] * Resampler::Sample(255.f)); } // Every hundred lines post an update. if (resultY % 100 == 0) { postResampleEvent(outPath, (float)resultY / (float)outHeight); } } } lmLog(gGFXTextureLogGroup, "Resample took %dms", t2 - platform_getMilliseconds()); // Write it back out. int t3 = platform_getMilliseconds(); jpge::compress_image_to_jpeg_file(outPath, outWidth, outHeight, 3, outBuffer); lmLog(gGFXTextureLogGroup, "JPEG output took %dms", t3 - platform_getMilliseconds()); // Post completion event. postResampleEvent(outPath, 1.0); // Free everything! loom_asset_unlock(inPath); free(buffRed); free(buffGreen); free(buffBlue); free(outBuffer); delete rn; return 0; }