mirror of
https://github.com/microsoft/DirectXTex.git
synced 2026-02-07 13:26:13 +01:00
Portable PixMap reader/writers for texconv (#180)
This commit is contained in:
193
Texconv/ExtendedBMP.cpp
Normal file
193
Texconv/ExtendedBMP.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: ExtendedBMP.cpp
|
||||
//
|
||||
// Utilities for reading BMP files including the DXTn unofficial "FS70"
|
||||
// extension created for Microsoft flight simulators.
|
||||
//
|
||||
// http://www.mwgfx.co.uk/programs/dxtbmp.htm
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248926
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#define NODRAWTEXT
|
||||
#define NOMCX
|
||||
#define NOSERVICE
|
||||
#define NOHELP
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "DirectXTex.h"
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
|
||||
|
||||
using ScopedHandle = std::unique_ptr<void, handle_closer>;
|
||||
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
HRESULT ReadData(_In_z_ const wchar_t* szFile, std::unique_ptr<uint8_t[]>& blob, size_t& blobSize)
|
||||
{
|
||||
blob.reset();
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
|
||||
#else
|
||||
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
|
||||
#endif
|
||||
if (!hFile)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
// Get the file size
|
||||
FILE_STANDARD_INFO fileInfo;
|
||||
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
// File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough)
|
||||
if (fileInfo.EndOfFile.HighPart > 0)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
|
||||
}
|
||||
|
||||
// Zero-sized files assumed to be invalid
|
||||
if (fileInfo.EndOfFile.LowPart < 1)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Read file
|
||||
blob.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);
|
||||
if (!blob)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
if (!ReadFile(hFile.get(), blob.get(), fileInfo.EndOfFile.LowPart, &bytesRead, nullptr))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
if (bytesRead != fileInfo.EndOfFile.LowPart)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
blobSize = fileInfo.EndOfFile.LowPart;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT LoadFromExtendedBMPMemory(
|
||||
_In_reads_bytes_(size) const void* pSource,
|
||||
_In_ size_t size,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image)
|
||||
{
|
||||
// This loads from non-standard BMP files that are not supported by WIC
|
||||
image.Release();
|
||||
|
||||
if (size < (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)))
|
||||
return E_FAIL;
|
||||
|
||||
// Valid BMP files always start with 'BM' at the top
|
||||
auto filehdr = reinterpret_cast<const BITMAPFILEHEADER*>(pSource);
|
||||
if (filehdr->bfType != 0x4D42)
|
||||
return E_FAIL;
|
||||
|
||||
if (size < filehdr->bfOffBits)
|
||||
return E_FAIL;
|
||||
|
||||
auto header = reinterpret_cast<const BITMAPINFOHEADER*>(reinterpret_cast<const uint8_t*>(pSource) + sizeof(BITMAPFILEHEADER));
|
||||
if (header->biSize != sizeof(BITMAPINFOHEADER))
|
||||
return E_FAIL;
|
||||
|
||||
if (header->biWidth < 1 || header->biHeight < 1 || header->biPlanes != 1 || header->biBitCount != 16)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
|
||||
switch (header->biCompression)
|
||||
{
|
||||
case 0x31545844: // FourCC "DXT1"
|
||||
format = DXGI_FORMAT_BC1_UNORM;
|
||||
break;
|
||||
case 0x33545844: // FourCC "DXT3"
|
||||
format = DXGI_FORMAT_BC2_UNORM;
|
||||
break;
|
||||
case 0x35545844: // FourCC "DXT5"
|
||||
format = DXGI_FORMAT_BC3_UNORM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
HRESULT hr = image.Initialize2D(format, size_t(header->biWidth), size_t(header->biHeight), 1, 1);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (header->biSizeImage != image.GetPixelsSize())
|
||||
return E_UNEXPECTED;
|
||||
|
||||
size_t remaining = size - filehdr->bfOffBits;
|
||||
if (!remaining)
|
||||
return E_FAIL;
|
||||
|
||||
if (remaining < image.GetPixelsSize())
|
||||
return E_UNEXPECTED;
|
||||
|
||||
auto pixels = reinterpret_cast<const uint8_t*>(pSource) + filehdr->bfOffBits;
|
||||
|
||||
memcpy(image.GetPixels(), pixels, image.GetPixelsSize());
|
||||
|
||||
if (metadata)
|
||||
{
|
||||
*metadata = image.GetMetadata();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT __cdecl LoadFromBMPEx(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_In_ WIC_FLAGS flags,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> bmpData;
|
||||
size_t bmpSize;
|
||||
HRESULT hr = ReadData(szFile, bmpData, bmpSize);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = LoadFromWICMemory(bmpData.get(), bmpSize, flags, metadata, image);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = LoadFromExtendedBMPMemory(bmpData.get(), bmpSize, metadata, image);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user