Function saveImage

Synopsis

#include <Source/Falcor/Utils/Image/Bitmap.h>

static void saveImage(const std::string &filename, uint32_t width, uint32_t height, FileFormat fileFormat, ExportFlags exportFlags, ResourceFormat resourceFormat, bool isTopDown, void *pData)

Description

Store a memory buffer to a PNG file.

Parameters:

[ in ] filename - Output filename. Can include a path - absolute or relative to the executable directory.

[ in ] width - The width of the image.

[ in ] height - The height of the image.

[ in ] fileFormat - The destination file format. See FileFormat enum above.

[ in ] exportFlags - The flags to export the file. See ExportFlags above.

[ in ] ResourceFormat - the format of the resource data

[ in ] isTopDown - Control the memory layout of the image. If true, the top-left pixel will be stored first, otherwise the bottom-left pixel will be stored first

[ in ] pData - Pointer to the buffer containing the image

Source

Lines 410-590 in Source/Falcor/Utils/Image/Bitmap.cpp. Line 77 in Source/Falcor/Utils/Image/Bitmap.h.

void Bitmap::saveImage(const std::string& filename, uint32_t width, uint32_t height, FileFormat fileFormat, ExportFlags exportFlags, ResourceFormat resourceFormat, bool isTopDown, void* pData)
{
    if (pData == nullptr)
    {
        logError("Bitmap::saveImage provided no data to save.");
        return;
    }
    if (is_set(exportFlags, ExportFlags::Uncompressed) && is_set(exportFlags, ExportFlags::Lossy))
    {
        logError("Bitmap::saveImage incompatible flags: lossy cannot be combined with uncompressed.");
        return;
    }
    int flags = 0;
    FIBITMAP* pImage = nullptr;
    uint32_t bytesPerPixel = getFormatBytesPerBlock(resourceFormat);
    // TODO: Replace this code for swapping channels. Can't use freeimage masks b/c they only care about 16 bpp images.
    if (resourceFormat == ResourceFormat::RGBA8Unorm || resourceFormat == ResourceFormat::RGBA8Snorm || resourceFormat == ResourceFormat::RGBA8UnormSrgb)
    {
        for (uint32_t a = 0; a < width*height; a++)
        {
            uint32_t* pPixel = (uint32_t*)pData;
            pPixel += a;
            uint8_t* ch = (uint8_t*)pPixel;
            std::swap(ch[0], ch[2]);
            if (is_set(exportFlags, ExportFlags::ExportAlpha) == false)
            {
                ch[3] = 0xff;
            }
        }
    }
    if (fileFormat == Bitmap::FileFormat::PfmFile || fileFormat == Bitmap::FileFormat::ExrFile)
    {
        std::vector<float> floatData;
        if (isConvertibleToRGBA32Float(resourceFormat))
        {
            floatData = convertToRGBA32Float(resourceFormat, width, height, pData);
            pData = floatData.data();
            resourceFormat = ResourceFormat::RGBA32Float;
            bytesPerPixel = 16;
        }
        else if (bytesPerPixel != 16 && bytesPerPixel != 12)
        {
            logError("Bitmap::saveImage supports only 32-bit/channel RGB/RGBA or 16-bit RGBA images as PFM/EXR files.");
            return;
        }
        const bool exportAlpha = is_set(exportFlags, ExportFlags::ExportAlpha);
        if (fileFormat == Bitmap::FileFormat::PfmFile)
        {
            if (is_set(exportFlags, ExportFlags::Lossy))
            {
                logError("Bitmap::saveImage: PFM does not support lossy compression mode.");
                return;
            }
            if (exportAlpha)
            {
                logError("Bitmap::saveImage: PFM does not support alpha channel.");
                return;
            }
        }
        if (exportAlpha && bytesPerPixel != 16)
        {
            logError("Bitmap::saveImage requesting to export alpha-channel to EXR file, but the resource doesn't have an alpha-channel");
            return;
        }
        // Upload the image manually and flip it vertically
        bool scanlineCopy = exportAlpha ? bytesPerPixel == 16 : bytesPerPixel == 12;
        pImage = FreeImage_AllocateT(exportAlpha ? FIT_RGBAF : FIT_RGBF, width, height);
        BYTE* head = (BYTE*)pData;
        for (unsigned y = 0; y < height; y++)
        {
            float* dstBits = (float*)FreeImage_GetScanLine(pImage, height - y - 1);
            if (scanlineCopy)
            {
                std::memcpy(dstBits, head, bytesPerPixel * width);
            }
            else
            {
                assert(exportAlpha == false);
                for (unsigned x = 0; x < width; x++)
                {
                    dstBits[x*3 + 0] = (((float*)head)[x*4 + 0]);
                    dstBits[x*3 + 1] = (((float*)head)[x*4 + 1]);
                    dstBits[x*3 + 2] = (((float*)head)[x*4 + 2]);
                }
            }
            head += bytesPerPixel * width;
        }
        if (fileFormat == Bitmap::FileFormat::ExrFile)
        {
            flags = 0;
            if (is_set(exportFlags, ExportFlags::Uncompressed))
            {
                flags |= EXR_NONE | EXR_FLOAT;
            }
            else if (is_set(exportFlags, ExportFlags::Lossy))
            {
                flags |= EXR_B44 | EXR_ZIP;
            }
        }
    }
    else
    {
        FIBITMAP* pTemp = FreeImage_ConvertFromRawBits((BYTE*)pData, width, height, bytesPerPixel * width, bytesPerPixel * 8, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, isTopDown);
        if (is_set(exportFlags, ExportFlags::ExportAlpha) == false || fileFormat == Bitmap::FileFormat::JpegFile)
        {
            pImage = FreeImage_ConvertTo24Bits(pTemp);
            FreeImage_Unload(pTemp);
        }
        else
        {
            pImage = pTemp;
        }
        std::vector<std::string> warnings;
        switch(fileFormat)
        {
        case FileFormat::JpegFile:
            if (is_set(exportFlags, ExportFlags::Lossy) == false || is_set(exportFlags, ExportFlags::Uncompressed))
            {
                flags = JPEG_QUALITYSUPERB | JPEG_SUBSAMPLING_444;
            }
            if (is_set(exportFlags, ExportFlags::ExportAlpha))
            {
                warnings.push_back("JPEG format does not support alpha channel.");
            }
            break;
        // Lossless formats
        case FileFormat::PngFile:
            flags = is_set(exportFlags, ExportFlags::Uncompressed) ? PNG_Z_NO_COMPRESSION : PNG_Z_BEST_COMPRESSION;
            if (is_set(exportFlags, ExportFlags::Lossy))
            {
                warnings.push_back("PNG format does not support lossy compression mode.");
            }
            break;
        case FileFormat::TgaFile:
            if (is_set(exportFlags, ExportFlags::Lossy))
            {
                warnings.push_back("TGA format does not support lossy compression mode.");
            }
            break;
        case FileFormat::BmpFile:
            if (is_set(exportFlags, ExportFlags::Lossy))
            {
                warnings.push_back("BMP format does not support lossy compression mode.");
            }
            if (is_set(exportFlags, ExportFlags::ExportAlpha))
            {
                warnings.push_back("BMP format does not support alpha channel.");
            }
            break;
        default:
            should_not_get_here();
        }
        if (warnings.empty() == false)
        {
            logWarning("Bitmap::saveImage: " + joinStrings(warnings, " "));
        }
    }
    if (!FreeImage_Save(toFreeImageFormat(fileFormat), pImage, filename.c_str(), flags))
    {
        logError("Bitmap::saveImage: FreeImage failed to save image");
    }
    FreeImage_Unload(pImage);
}





Add Discussion as Guest

Log in to DocsForge