Containers::Array<char> StbPngImageConverter::doExportToData(const ImageView2D& image) {
    #ifndef MAGNUM_TARGET_GLES
    if(image.storage().swapBytes()) {
        Error() << "Trade::StbPngImageConverter::exportToData(): pixel byte swap is not supported";
        return nullptr;
    }
    #endif

    if(image.type() != PixelType::UnsignedByte) {
        Error() << "Trade::StbPngImageConverter::exportToData(): unsupported pixel type" << image.type();
        return nullptr;
    }

    Int components;
    switch(image.format()) {
        #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
        case PixelFormat::Red:
        #endif
        #ifdef MAGNUM_TARGET_GLES2
        case PixelFormat::Luminance:
        #endif
            components = 1;
            break;
        #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
        case PixelFormat::RG:
        #endif
        #ifdef MAGNUM_TARGET_GLES2
        case PixelFormat::LuminanceAlpha:
        #endif
            components = 2;
            break;
        case PixelFormat::RGB: components = 3; break;
        case PixelFormat::RGBA: components = 4; break;
        default:
            Error() << "Trade::StbPngImageConverter::exportToData(): unsupported pixel format" << image.format();
            return nullptr;
    }

    /* Data properties */
    std::size_t offset;
    Math::Vector2<std::size_t> dataSize;
    std::tie(offset, dataSize, std::ignore) = image.dataProperties();

    /* Reverse rows in image data */
    Containers::Array<unsigned char> reversedData{image.data().size()};
    for(Int y = 0; y != image.size().y(); ++y) {
        std::copy(image.data<unsigned char>() + offset + y*dataSize.x(), image.data<unsigned char>() + offset + (y + 1)*dataSize.x(), reversedData + (image.size().y() - y - 1)*dataSize.x());
    }

    Int size;
    unsigned char* const data = stbi_write_png_to_mem(reversedData, dataSize.x(), image.size().x(), image.size().y(), components, &size);
    CORRADE_INTERNAL_ASSERT(data);

    /* Wrap the data in an array with custom deleter (we can't use delete[]) */
    Containers::Array<char> fileData{reinterpret_cast<char*>(data), std::size_t(size),
        [](char* data, std::size_t) { std::free(data); }};

    return fileData;
}
示例#2
0
Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& image) {
    #ifndef MAGNUM_TARGET_GLES
    if(image.storage().swapBytes()) {
        Error() << "Trade::TgaImageConverter::exportToData(): pixel byte swap is not supported";
        return nullptr;
    }
    #endif

    if(image.format() != PixelFormat::RGB &&
       image.format() != PixelFormat::RGBA
       #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
       && image.format() != PixelFormat::Red
       #endif
       #ifdef MAGNUM_TARGET_GLES2
       && image.format() != PixelFormat::Luminance
       #endif
       )
    {
        Error() << "Trade::TgaImageConverter::exportToData(): unsupported color format" << image.format();
        return nullptr;
    }

    if(image.type() != PixelType::UnsignedByte) {
        Error() << "Trade::TgaImageConverter::exportToData(): unsupported color type" << image.type();
        return nullptr;
    }

    /* Initialize data buffer */
    const auto pixelSize = UnsignedByte(image.pixelSize());
    Containers::Array<char> data{Containers::ValueInit, sizeof(TgaHeader) + pixelSize*image.size().product()};

    /* Fill header */
    auto header = reinterpret_cast<TgaHeader*>(data.begin());
    switch(image.format()) {
        case PixelFormat::RGB:
        case PixelFormat::RGBA:
            header->imageType = 2;
            break;
        #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
        case PixelFormat::Red:
        #endif
        #ifdef MAGNUM_TARGET_GLES2
        case PixelFormat::Luminance:
        #endif
            header->imageType = 3;
            break;
        default: CORRADE_ASSERT_UNREACHABLE();
    }
    header->bpp = pixelSize*8;
    header->width = UnsignedShort(Utility::Endianness::littleEndian(image.size().x()));
    header->height = UnsignedShort(Utility::Endianness::littleEndian(image.size().y()));

    /* Image data pointer including skip */
    const char* imageData = image.data() + std::get<0>(image.dataProperties());

    /* Fill data or copy them row by row if we need to drop the padding */
    const std::size_t rowSize = image.size().x()*pixelSize;
    const std::size_t rowStride = std::get<1>(image.dataProperties()).x();
    if(rowStride != rowSize) {
        for(std::int_fast32_t y = 0; y != image.size().y(); ++y)
            std::copy_n(imageData + y*rowStride, rowSize, data.begin() + sizeof(TgaHeader) + y*rowSize);
    } else std::copy_n(imageData, pixelSize*image.size().product(), data.begin() + sizeof(TgaHeader));

    if(image.format() == PixelFormat::RGB) {
        auto pixels = reinterpret_cast<Math::Vector3<UnsignedByte>*>(data.begin()+sizeof(TgaHeader));
        std::transform(pixels, pixels + image.size().product(), pixels,
            [](Math::Vector3<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r'>(pixel); });
    } else if(image.format() == PixelFormat::RGBA) {
        auto pixels = reinterpret_cast<Math::Vector4<UnsignedByte>*>(data.begin()+sizeof(TgaHeader));
        std::transform(pixels, pixels + image.size().product(), pixels,
            [](Math::Vector4<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r', 'a'>(pixel); });
    }

    return data;
}
 Containers::Array<char> doExportToData(const ImageView2D& image) override {
     return Containers::Array<char>::from(char(image.size().x()), char(image.size().y()));
 };