Containers::Optional<ImageData2D> DevIlImageImporter::doImage2D(UnsignedInt) { ILuint imgID = 0; ilGenImages(1, &imgID); ilBindImage(imgID); /* So we can use the shorter if(!ilFoo()) */ static_assert(!IL_FALSE, "IL_FALSE doesn't have a zero value"); if(!ilLoadL(IL_TYPE_UNKNOWN, _in, _in.size())) { /* iluGetString() returns empty string for 0x512, which is even more useless than just returning the error ID */ Error() << "Trade::DevIlImageImporter::image2D(): cannot open the image:" << ilGetError(); return Containers::NullOpt; } const Vector2i size{ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT)}; Int components; bool rgbaNeeded = false; PixelFormat format; switch(ilGetInteger(IL_IMAGE_FORMAT)) { /* Grayscale */ case IL_LUMINANCE: format = PixelFormat::R8Unorm; components = 1; break; /* Grayscale + alpha */ case IL_LUMINANCE_ALPHA: format = PixelFormat::RG8Unorm; components = 2; break; /* BGR */ case IL_BGR: rgbaNeeded = true; format = PixelFormat::RGB8Unorm; components = 3; break; /* BGRA */ case IL_BGRA: rgbaNeeded = true; format = PixelFormat::RGBA8Unorm; components = 4; break; /* RGB */ case IL_RGB: format = PixelFormat::RGB8Unorm; components = 3; break; /* RGBA */ case IL_RGBA: format = PixelFormat::RGBA8Unorm; components = 4; break; /* No idea, convert to RGBA */ default: format = PixelFormat::RGBA8Unorm; components = 4; rgbaNeeded = true; } /* If the format isn't one we recognize, convert to RGB(A) */ if(rgbaNeeded && !ilConvertImage(components == 3 ? IL_RGB : IL_RGBA, IL_UNSIGNED_BYTE)) { /* iluGetString() returns empty string for 0x512, which is even more useless than just returning the error ID */ Error() << "Trade::DevIlImageImporter::image2D(): cannot convert image:" << ilGetError(); return Containers::NullOpt; } /* Flip the image to match OpenGL's conventions */ /** @todo use our own routine to avoid linking to ILU */ ILinfo ImageInfo; iluGetImageInfo(&ImageInfo); if(ImageInfo.Origin == IL_ORIGIN_UPPER_LEFT) iluFlipImage(); /* Copy the data into array that is owned by us and not by IL */ Containers::Array<char> imageData{std::size_t(size.product()*components)}; std::copy_n(reinterpret_cast<char*>(ilGetData()), imageData.size(), imageData.begin()); /* Release the texture back to DevIL */ ilDeleteImages(1, &imgID); /* Adjust pixel storage if row size is not four byte aligned */ PixelStorage storage; if((size.x()*components)%4 != 0) storage.setAlignment(1); return Trade::ImageData2D{storage, format, size, std::move(imageData)}; }
std::optional<ImageData2D> TgaImporter::doImage2D(UnsignedInt) { /* Check if the file is long enough */ if(_in.size() < std::streamoff(sizeof(TgaHeader))) { Error() << "Trade::TgaImporter::image2D(): the file is too short:" << _in.size() << "bytes"; return std::nullopt; } const TgaHeader& header = *reinterpret_cast<const TgaHeader*>(_in.data()); /* Size in machine endian */ const Vector2i size{Utility::Endianness::littleEndian(header.width), Utility::Endianness::littleEndian(header.height)}; /* Image format */ PixelFormat format; if(header.colorMapType != 0) { Error() << "Trade::TgaImporter::image2D(): paletted files are not supported"; return std::nullopt; } /* Color */ if(header.imageType == 2) { switch(header.bpp) { case 24: format = PixelFormat::RGB; break; case 32: format = PixelFormat::RGBA; break; default: Error() << "Trade::TgaImporter::image2D(): unsupported color bits-per-pixel:" << header.bpp; return std::nullopt; } /* Grayscale */ } else if(header.imageType == 3) { #if defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) format = Context::hasCurrent() && Context::current().isExtensionSupported<Extensions::GL::EXT::texture_rg>() ? PixelFormat::Red : PixelFormat::Luminance; #elif !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) format = PixelFormat::Red; #else format = PixelFormat::Luminance; #endif if(header.bpp != 8) { Error() << "Trade::TgaImporter::image2D(): unsupported grayscale bits-per-pixel:" << header.bpp; return std::nullopt; } /* Compressed files */ } else { Error() << "Trade::TgaImporter::image2D(): unsupported (compressed?) image type:" << header.imageType; return std::nullopt; } Containers::Array<char> data{std::size_t(size.product())*header.bpp/8}; std::copy_n(_in + sizeof(TgaHeader), data.size(), data.begin()); /* Adjust pixel storage if row size is not four byte aligned */ PixelStorage storage; if((size.x()*header.bpp/8)%4 != 0) storage.setAlignment(1); if(format == PixelFormat::RGB) { auto pixels = reinterpret_cast<Math::Vector3<UnsignedByte>*>(data.data()); std::transform(pixels, pixels + size.product(), pixels, [](Math::Vector3<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r'>(pixel); }); } else if(format == PixelFormat::RGBA) { auto pixels = reinterpret_cast<Math::Vector4<UnsignedByte>*>(data.data()); std::transform(pixels, pixels + size.product(), pixels, [](Math::Vector4<UnsignedByte> pixel) { return Math::swizzle<'b', 'g', 'r', 'a'>(pixel); }); } return ImageData2D{storage, format, PixelType::UnsignedByte, size, std::move(data)}; }