diff --git a/es-app/src/MiximageGenerator.cpp b/es-app/src/MiximageGenerator.cpp index 48a5ad2ee..fa2b2366a 100644 --- a/es-app/src/MiximageGenerator.cpp +++ b/es-app/src/MiximageGenerator.cpp @@ -111,14 +111,14 @@ void MiximageGenerator::startThread(std::promise* miximagePromise) bool MiximageGenerator::generateImage() { FREE_IMAGE_FORMAT fileFormat; - FIBITMAP* screenshotFile = nullptr; - FIBITMAP* marqueeFile = nullptr; - FIBITMAP* boxFile = nullptr; - FIBITMAP* physicalMediaFile = nullptr; + FIBITMAP* screenshotFile {nullptr}; + FIBITMAP* marqueeFile {nullptr}; + FIBITMAP* boxFile {nullptr}; + FIBITMAP* physicalMediaFile {nullptr}; - unsigned int fileWidth = 0; - unsigned int fileHeight = 0; - unsigned int filePitch = 0; + unsigned int fileWidth {0}; + unsigned int fileHeight {0}; + unsigned int filePitch {0}; #if defined(_WIN64) fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mScreenshotPath).c_str()); @@ -336,19 +336,19 @@ bool MiximageGenerator::generateImage() resolutionMultiplier = 2; } - const unsigned int screenshotWidth = 530 * resolutionMultiplier; - const unsigned int screenshotOffset = 20 * resolutionMultiplier; - const unsigned int screenshotFrameWidth = 6 * resolutionMultiplier; - const unsigned int screenshotHeight = 400 * resolutionMultiplier; + const unsigned int screenshotWidth {530 * resolutionMultiplier}; + const unsigned int screenshotOffset {20 * resolutionMultiplier}; + const unsigned int screenshotFrameWidth {6 * resolutionMultiplier}; + const unsigned int screenshotHeight {400 * resolutionMultiplier}; // These sizes are increased slightly when adding the drop shadow. - const unsigned int marqueeTargetWidth = 310 * resolutionMultiplier; - const unsigned int marqueeTargetHeight = 230 * resolutionMultiplier; - unsigned int boxTargetWidth = 0; - unsigned int boxTargetHeight = 0; - unsigned int coverTargetWidth = 0; - unsigned int physicalMediaTargetWidth = 0; - unsigned int physicalMediaTargetHeight = 0; + const unsigned int marqueeTargetWidth {310 * resolutionMultiplier}; + const unsigned int marqueeTargetHeight {230 * resolutionMultiplier}; + unsigned int boxTargetWidth {0}; + unsigned int boxTargetHeight {0}; + unsigned int coverTargetWidth {0}; + unsigned int physicalMediaTargetWidth {0}; + unsigned int physicalMediaTargetHeight {0}; if (Settings::getInstance()->getString("MiximageBoxSize") == "small") { boxTargetWidth = 264 * resolutionMultiplier; @@ -379,12 +379,12 @@ bool MiximageGenerator::generateImage() physicalMediaTargetHeight = 120 * resolutionMultiplier; } - const unsigned int marqueeShadowSize = 6 * resolutionMultiplier; - const unsigned int boxShadowSize = 6 * resolutionMultiplier; - const unsigned int physicalMediaShadowSize = 6 * resolutionMultiplier; + const unsigned int marqueeShadowSize {6 * resolutionMultiplier}; + const unsigned int boxShadowSize {6 * resolutionMultiplier}; + const unsigned int physicalMediaShadowSize {6 * resolutionMultiplier}; if (FreeImage_GetBPP(screenshotFile) != 32) { - FIBITMAP* screenshotTemp = FreeImage_ConvertTo32Bits(screenshotFile); + FIBITMAP* screenshotTemp {FreeImage_ConvertTo32Bits(screenshotFile)}; FreeImage_Unload(screenshotFile); screenshotFile = screenshotTemp; } @@ -396,12 +396,12 @@ bool MiximageGenerator::generateImage() std::vector screenshotVector(fileWidth * fileHeight * 4); FreeImage_ConvertToRawBits(reinterpret_cast(&screenshotVector.at(0)), screenshotFile, - filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1); + filePitch, 32, FI_RGBA_BLUE, FI_RGBA_GREEN, FI_RGBA_RED, 1); CImg screenshotImage(fileWidth, fileHeight, 1, 4, 0); // Convert the RGBA image to CImg internal format. - Utils::CImg::convertRGBAToCImg(screenshotVector, screenshotImage); + Utils::CImg::convertBGRAToCImg(screenshotVector, screenshotImage); screenshotVector.clear(); if (Settings::getInstance()->getBool("MiximageRemoveLetterboxes")) @@ -426,17 +426,17 @@ bool MiximageGenerator::generateImage() // of the miximage. screenshotImage.get_shared_channel(3).fill(255); - int xPosScreenshot = 0; - int yPosScreenshot = 0; + int xPosScreenshot {0}; + int yPosScreenshot {0}; - int xPosMarquee = 0; - int yPosMarquee = 0; + int xPosMarquee {0}; + int yPosMarquee {0}; - int xPosBox = 0; - int yPosBox = 0; + int xPosBox {0}; + int yPosBox {0}; - int xPosPhysicalMedia = 0; - int yPosPhysicalMedia = 0; + int xPosPhysicalMedia {0}; + int yPosPhysicalMedia {0}; CImg canvasImage(mWidth, mHeight, 1, 4, 0); @@ -459,7 +459,7 @@ bool MiximageGenerator::generateImage() if (mMarquee) { if (FreeImage_GetBPP(marqueeFile) != 32) { - FIBITMAP* marqueeTemp = FreeImage_ConvertTo32Bits(marqueeFile); + FIBITMAP* marqueeTemp {FreeImage_ConvertTo32Bits(marqueeFile)}; FreeImage_Unload(marqueeFile); marqueeFile = marqueeTemp; } @@ -471,16 +471,16 @@ bool MiximageGenerator::generateImage() std::vector marqueeVector(fileWidth * fileHeight * 4); FreeImage_ConvertToRawBits(reinterpret_cast(&marqueeVector.at(0)), marqueeFile, - filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1); + filePitch, 32, FI_RGBA_BLUE, FI_RGBA_GREEN, FI_RGBA_RED, 1); marqueeImage = CImg(FreeImage_GetWidth(marqueeFile), FreeImage_GetHeight(marqueeFile), 1, 4, 0); - Utils::CImg::convertRGBAToCImg(marqueeVector, marqueeImage); + Utils::CImg::convertBGRAToCImg(marqueeVector, marqueeImage); Utils::CImg::removeTransparentPadding(marqueeImage); - unsigned int marqueeWidth = static_cast(marqueeImage.width()); - unsigned int marqueeHeight = static_cast(marqueeImage.height()); + unsigned int marqueeWidth {static_cast(marqueeImage.width())}; + unsigned int marqueeHeight {static_cast(marqueeImage.height())}; calculateMarqueeSize(marqueeTargetWidth, marqueeTargetHeight, marqueeWidth, marqueeHeight); @@ -501,7 +501,7 @@ bool MiximageGenerator::generateImage() if (mBox3D || mCover) { if (FreeImage_GetBPP(boxFile) != 32) { - FIBITMAP* boxTemp = FreeImage_ConvertTo32Bits(boxFile); + FIBITMAP* boxTemp {FreeImage_ConvertTo32Bits(boxFile)}; FreeImage_Unload(boxFile); boxFile = boxTemp; } @@ -513,24 +513,25 @@ bool MiximageGenerator::generateImage() std::vector boxVector(fileWidth * fileHeight * 4); FreeImage_ConvertToRawBits(reinterpret_cast(&boxVector.at(0)), boxFile, filePitch, - 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1); + 32, FI_RGBA_BLUE, FI_RGBA_GREEN, FI_RGBA_RED, 1); boxImage = CImg(FreeImage_GetWidth(boxFile), FreeImage_GetHeight(boxFile), 1, 4); - Utils::CImg::convertRGBAToCImg(boxVector, boxImage); + Utils::CImg::convertBGRAToCImg(boxVector, boxImage); Utils::CImg::removeTransparentPadding(boxImage); - float sizeRatio = - static_cast(boxImage.width()) / static_cast(boxImage.height()); + float sizeRatio {static_cast(boxImage.width()) / + static_cast(boxImage.height())}; if (sizeRatio > 1.14f && Settings::getInstance()->getBool("MiximageRotateHorizontalBoxes")) boxImage.rotate(90.0f); - float scaleFactor = - static_cast(boxTargetHeight) / static_cast(boxImage.height()); - unsigned int width = static_cast(static_cast(boxImage.width()) * scaleFactor); - unsigned int targetWidth = 0; + float scaleFactor {static_cast(boxTargetHeight) / + static_cast(boxImage.height())}; + unsigned int width { + static_cast(static_cast(boxImage.width()) * scaleFactor)}; + unsigned int targetWidth {0}; // We make this distinction as some cover images are in square format and would cover // too much surface otherwise. @@ -541,7 +542,7 @@ bool MiximageGenerator::generateImage() if (width > targetWidth) { scaleFactor = static_cast(targetWidth) / static_cast(boxImage.width()); - int height = static_cast(static_cast(boxImage.height()) * scaleFactor); + int height {static_cast(static_cast(boxImage.height()) * scaleFactor)}; // We use Lanczos3 which is the highest quality resampling method available. boxImage.resize(targetWidth, height, 1, 4, 6); } @@ -562,7 +563,7 @@ bool MiximageGenerator::generateImage() if (mPhysicalMedia) { if (FreeImage_GetBPP(physicalMediaFile) != 32) { - FIBITMAP* physicalMediaTemp = FreeImage_ConvertTo32Bits(physicalMediaFile); + FIBITMAP* physicalMediaTemp {FreeImage_ConvertTo32Bits(physicalMediaFile)}; FreeImage_Unload(physicalMediaFile); physicalMediaFile = physicalMediaTemp; } @@ -574,26 +575,26 @@ bool MiximageGenerator::generateImage() std::vector physicalMediaVector(fileWidth * fileHeight * 4); FreeImage_ConvertToRawBits(reinterpret_cast(&physicalMediaVector.at(0)), - physicalMediaFile, filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, - FI_RGBA_BLUE, 1); + physicalMediaFile, filePitch, 32, FI_RGBA_BLUE, FI_RGBA_GREEN, + FI_RGBA_RED, 1); physicalMediaImage = CImg(FreeImage_GetWidth(physicalMediaFile), FreeImage_GetHeight(physicalMediaFile), 1, 4, 0); - Utils::CImg::convertRGBAToCImg(physicalMediaVector, physicalMediaImage); + Utils::CImg::convertBGRAToCImg(physicalMediaVector, physicalMediaImage); Utils::CImg::removeTransparentPadding(physicalMediaImage); // Make sure the image size is not exceeding either the target width or height. - float scaleFactorX = static_cast(physicalMediaTargetWidth) / - static_cast(physicalMediaImage.width()); - float scaleFactorY = static_cast(physicalMediaTargetHeight) / - static_cast(physicalMediaImage.height()); - float scaleFactor = std::min(scaleFactorX, scaleFactorY); + float scaleFactorX {static_cast(physicalMediaTargetWidth) / + static_cast(physicalMediaImage.width())}; + float scaleFactorY {static_cast(physicalMediaTargetHeight) / + static_cast(physicalMediaImage.height())}; + float scaleFactor {std::min(scaleFactorX, scaleFactorY)}; - unsigned int width = - static_cast(static_cast(physicalMediaImage.width()) * scaleFactor); - unsigned int height = - static_cast(static_cast(physicalMediaImage.height()) * scaleFactor); + unsigned int width {static_cast( + static_cast(physicalMediaImage.width()) * scaleFactor)}; + unsigned int height {static_cast( + static_cast(physicalMediaImage.height()) * scaleFactor)}; // We use Lanczos3 which is the highest quality resampling method available. physicalMediaImage.resize(width, height, 1, 4, 6); @@ -632,8 +633,8 @@ bool MiximageGenerator::generateImage() yPosScreenshot + screenshotHeight - 2, frameColor); // We draw circles in order to get rounded corners for the frame. - const unsigned int circleRadius = 8 * resolutionMultiplier; - const unsigned int circleOffset = 2 * resolutionMultiplier; + const unsigned int circleRadius {8 * resolutionMultiplier}; + const unsigned int circleOffset {2 * resolutionMultiplier}; // Upper left corner. frameImage.draw_circle(xPosScreenshot + circleOffset, yPosScreenshot + circleOffset, @@ -668,19 +669,19 @@ bool MiximageGenerator::generateImage() std::vector canvasVector; // Convert the image from CImg internal format. - Utils::CImg::convertCImgToRGBA(canvasImage, canvasVector); + Utils::CImg::convertCImgToBGRA(canvasImage, canvasVector); - FIBITMAP* mixImage = nullptr; + FIBITMAP* mixImage {nullptr}; mixImage = FreeImage_ConvertFromRawBits(&canvasVector.at(0), canvasImage.width(), canvasImage.height(), canvasImage.width() * 4, 32, - FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE); + FI_RGBA_BLUE, FI_RGBA_GREEN, FI_RGBA_RED); #if defined(_WIN64) - bool savedImage = - (FreeImage_SaveU(FIF_PNG, mixImage, - Utils::String::stringToWideString(getSavePath()).c_str()) != 0); + bool savedImage {FreeImage_SaveU(FIF_PNG, mixImage, + Utils::String::stringToWideString(getSavePath()).c_str()) != + 0}; #else - bool savedImage = (FreeImage_Save(FIF_PNG, mixImage, getSavePath().c_str()) != 0); + bool savedImage {FreeImage_Save(FIF_PNG, mixImage, getSavePath().c_str()) != 0}; #endif if (!savedImage) { @@ -705,14 +706,14 @@ void MiximageGenerator::calculateMarqueeSize(const unsigned int& targetWidth, unsigned int& width, unsigned int& height) { - unsigned int adjustedTargetWidth = 0; - float widthModifier = 0.5f; - float scaleFactor = 0.0f; + unsigned int adjustedTargetWidth {0}; + float widthModifier {0.5f}; + float scaleFactor {0.0f}; // The idea is to adjust the size of the marquee based on its surface area, so that // wider but shorter images get a larger width than taller images in order to use // an approximately equivalent amount of space on the miximage. - float widthRatio = static_cast(width) / static_cast(height); + float widthRatio {static_cast(width) / static_cast(height)}; widthModifier = glm::clamp(widthModifier + widthRatio / 6.5f, 0.0f, 1.0f); @@ -737,18 +738,18 @@ void MiximageGenerator::sampleFrameColor(CImg& screenshotImage, unsigned char (&frameColor)[4]) { // Calculate the number of samples relative to the configured resolution so we get - // the same result regardless of miximage target size seting. - unsigned int samples = static_cast(static_cast(mWidth) * 0.03125f); + // the same result regardless of miximage target size setting. + unsigned int samples {static_cast(static_cast(mWidth) * 0.03125f)}; - unsigned int red = 0; - unsigned int green = 0; - unsigned int blue = 0; + unsigned int red {0}; + unsigned int green {0}; + unsigned int blue {0}; - unsigned int redLine = 0; - unsigned int greenLine = 0; - unsigned int blueLine = 0; + unsigned int redLine {0}; + unsigned int greenLine {0}; + unsigned int blueLine {0}; - unsigned int counter = 0; + unsigned int counter {0}; // This is a very simple method to get an average pixel value. It's limited in that it // does not consider dominant colors and such, so the result could possibly be a value @@ -770,16 +771,19 @@ void MiximageGenerator::sampleFrameColor(CImg& screenshotImage, } } - unsigned char redC = glm::clamp(static_cast(redLine / 255), 0, 255); - unsigned char greenC = glm::clamp(static_cast(greenLine / 255), 0, 255); - unsigned char blueC = glm::clamp(static_cast(blueLine / 255), 0, 255); + unsigned char redC { + static_cast(glm::clamp(static_cast(redLine / 255), 0, 255))}; + unsigned char greenC { + static_cast(glm::clamp(static_cast(greenLine / 255), 0, 255))}; + unsigned char blueC { + static_cast(glm::clamp(static_cast(blueLine / 255), 0, 255))}; // Convert to the HSL color space to be able to modify saturation and lightness. CImg colorHSL = CImg<>(1, 1, 1, 3).fill(redC, greenC, blueC).RGBtoHSL(); // float hue = colorHSL(0, 0, 0, 0); - float saturation = colorHSL(0, 0, 0, 1); - float lightness = colorHSL(0, 0, 0, 2); + float saturation {colorHSL(0, 0, 0, 1)}; + float lightness {colorHSL(0, 0, 0, 2)}; // Decrease saturation slightly and increase lightness a bit, these adjustments // makes the end result look better than the raw average pixel value. Also clamp @@ -798,7 +802,7 @@ void MiximageGenerator::sampleFrameColor(CImg& screenshotImage, std::string MiximageGenerator::getSavePath() const { - const std::string name = Utils::FileSystem::getStem(mGame->getPath()); + const std::string name {Utils::FileSystem::getStem(mGame->getPath())}; std::string subFolders; // Extract possible subfolders from the path. @@ -806,7 +810,7 @@ std::string MiximageGenerator::getSavePath() const subFolders = Utils::String::replace(Utils::FileSystem::getParent(mGame->getPath()), mGame->getSystemEnvData()->mStartPath, ""); - std::string path = FileData::getMediaDirectory(); + std::string path {FileData::getMediaDirectory()}; if (!Utils::FileSystem::exists(path)) Utils::FileSystem::createDirectory(path); diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 80677adb2..b580b726f 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -187,9 +187,9 @@ void ImageComponent::cropTransparentPadding(const float maxSizeX, const float ma if (mSize == glm::vec2 {0.0f, 0.0f}) return; - std::vector imageRGBA {mTexture.get()->getRawRGBAData()}; + std::vector imageBGRA {mTexture.get()->getRawRGBAData()}; - if (imageRGBA.size() == 0) + if (imageBGRA.size() == 0) return; glm::ivec2 imageSize {mTexture.get()->getSize()}; @@ -198,8 +198,8 @@ void ImageComponent::cropTransparentPadding(const float maxSizeX, const float ma int paddingCoords[4] {0, 0, 0, 0}; // We need to convert our RGBA data to the CImg internal format as CImg does not interleave - // the pixels (as in RGBARGBARGBA). - Utils::CImg::convertRGBAToCImg(imageRGBA, imageCImg); + // the pixels (as in BGRABGRABGRA). + Utils::CImg::convertBGRAToCImg(imageBGRA, imageCImg); // This will give us the coordinates for the fully transparent areas. Utils::CImg::getTransparentPaddingCoords(imageCImg, paddingCoords); diff --git a/es-core/src/utils/CImgUtil.cpp b/es-core/src/utils/CImgUtil.cpp index 941fab649..e0ff53060 100644 --- a/es-core/src/utils/CImgUtil.cpp +++ b/es-core/src/utils/CImgUtil.cpp @@ -12,10 +12,39 @@ namespace Utils { namespace CImg { + void convertBGRAToCImg(const std::vector& imageBGRA, + cimg_library::CImg& image) + { + // CImg does not interleave pixels as in BGRABGRABGRA so a conversion is required. + int counter = 0; + for (int r = 0; r < image.height(); ++r) { + for (int c = 0; c < image.width(); ++c) { + image(c, r, 0, 0) = imageBGRA[counter + 0]; + image(c, r, 0, 1) = imageBGRA[counter + 1]; + image(c, r, 0, 2) = imageBGRA[counter + 2]; + image(c, r, 0, 3) = imageBGRA[counter + 3]; + counter += 4; + } + } + } + + void convertCImgToBGRA(const cimg_library::CImg& image, + std::vector& imageBGRA) + { + for (int r = image.height() - 1; r >= 0; --r) { + for (int c = 0; c < image.width(); ++c) { + imageBGRA.emplace_back((unsigned char)image(c, r, 0, 0)); + imageBGRA.emplace_back((unsigned char)image(c, r, 0, 1)); + imageBGRA.emplace_back((unsigned char)image(c, r, 0, 2)); + imageBGRA.emplace_back((unsigned char)image(c, r, 0, 3)); + } + } + } + void convertRGBAToCImg(const std::vector& imageRGBA, cimg_library::CImg& image) { - // CImg does not interleave the pixels as in RGBARGBARGBA so a conversion is required. + // CImg does not interleave pixels as in RGBARGBARGBA so a conversion is required. int counter = 0; for (int r = 0; r < image.height(); ++r) { for (int c = 0; c < image.width(); ++c) { diff --git a/es-core/src/utils/CImgUtil.h b/es-core/src/utils/CImgUtil.h index 203773461..50b975958 100644 --- a/es-core/src/utils/CImgUtil.h +++ b/es-core/src/utils/CImgUtil.h @@ -20,6 +20,10 @@ namespace Utils { namespace CImg { + void convertBGRAToCImg(const std::vector& imageBGRA, + cimg_library::CImg& image); + void convertCImgToBGRA(const cimg_library::CImg& image, + std::vector& imageBGRA); void convertRGBAToCImg(const std::vector& imageRGBA, cimg_library::CImg& image); void convertCImgToRGBA(const cimg_library::CImg& image,