mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-15 20:42:40 +00:00
Before this addition, Aseprite supported following BMP formats: - Size = 12 (OS/2 BMP 1.0) - Size = 40 (Windows BMP v3) Now extended support has been added to the BMP extension: - Load BMP files with BMP header size: - Size = 12 (OS/2 BMP 1.0) - Size = 16 (OS/2 BMP 2.0 - size 16) - Size = 24 (OS/2 BMP 2.0 - size 24) - Size = 40 (Windows BMP v3) - Size = 52 (BITMAPV2INFOHEADER) - Size = 56 (BITMAPV3INFOHEADER) - Size = 60 (OS/2 BMP 2.0 - size 60) - Size = 64 (OS/2 BMP 2.0 - size 64) - Size = 108 (BITMAPV4INFOHEADER) at the moment colorimetry isn’t supported. - Size = 124 (BITMAPV5INFOHEADER) at the moment ICC profiles not supported. - Load BMP with alpha channel. - Load BMP 2bit color depth. - Export BMP files with alpha channel (not palette based).
This commit is contained in:
parent
282328d6d6
commit
bdcabdedf3
@ -6,6 +6,11 @@
|
|||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
//
|
//
|
||||||
// bmp.c - Based on the code of Seymour Shlien and Jonas Petersen.
|
// bmp.c - Based on the code of Seymour Shlien and Jonas Petersen.
|
||||||
|
//
|
||||||
|
// Info about BMP format:
|
||||||
|
// https://en.wikipedia.org/wiki/BMP_file_format
|
||||||
|
// http://justsolve.archiveteam.org/wiki/BMP
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -46,6 +51,7 @@ class BmpFormat : public FileFormat {
|
|||||||
uint32_t red_mask; // Mask for red channel.
|
uint32_t red_mask; // Mask for red channel.
|
||||||
uint32_t green_mask; // Mask for green channel.
|
uint32_t green_mask; // Mask for green channel.
|
||||||
uint32_t blue_mask; // Mask for blue channel.
|
uint32_t blue_mask; // Mask for blue channel.
|
||||||
|
uint32_t alpha_mask; // Mask for alpha channel.
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* onGetName() const override {
|
const char* onGetName() const override {
|
||||||
@ -65,6 +71,7 @@ class BmpFormat : public FileFormat {
|
|||||||
FILE_SUPPORT_LOAD |
|
FILE_SUPPORT_LOAD |
|
||||||
FILE_SUPPORT_SAVE |
|
FILE_SUPPORT_SAVE |
|
||||||
FILE_SUPPORT_RGB |
|
FILE_SUPPORT_RGB |
|
||||||
|
FILE_SUPPORT_RGBA |
|
||||||
FILE_SUPPORT_GRAY |
|
FILE_SUPPORT_GRAY |
|
||||||
FILE_SUPPORT_INDEXED |
|
FILE_SUPPORT_INDEXED |
|
||||||
FILE_SUPPORT_SEQUENCES |
|
FILE_SUPPORT_SEQUENCES |
|
||||||
@ -82,34 +89,63 @@ FileFormat* CreateBmpFormat()
|
|||||||
return new BmpFormat;
|
return new BmpFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BI_RGB 0
|
#define BI_RGB 0
|
||||||
#define BI_RLE8 1
|
#define BI_RLE8 1
|
||||||
#define BI_RLE4 2
|
#define BI_RLE4 2
|
||||||
#define BI_BITFIELDS 3
|
#define BI_BITFIELDS 3
|
||||||
|
#define BI_ALPHABITFIELDS 6
|
||||||
|
|
||||||
#define OS2INFOHEADERSIZE 12
|
#define OS2FILEHEADERSIZE 14
|
||||||
#define WININFOHEADERSIZE 40
|
|
||||||
|
|
||||||
typedef struct BITMAPFILEHEADER
|
#define OS2INFOHEADERSIZE 12
|
||||||
|
#define OS22INFOHEADERSIZE16 16
|
||||||
|
#define OS22INFOHEADERSIZE24 24
|
||||||
|
#define WININFOHEADERSIZE 40
|
||||||
|
#define BV2INFOHEADERSIZE 52
|
||||||
|
#define BV3INFOHEADERSIZE 56
|
||||||
|
#define OS22INFOHEADERSIZE60 60
|
||||||
|
#define OS22INFOHEADERSIZE64 64
|
||||||
|
#define BV4INFOHEADERSIZE 108
|
||||||
|
#define BV5INFOHEADERSIZE 124
|
||||||
|
|
||||||
|
struct BITMAPFILEHEADER
|
||||||
{
|
{
|
||||||
uint32_t bfType;
|
uint32_t bfType;
|
||||||
uint32_t bfSize;
|
uint32_t bfSize;
|
||||||
uint16_t bfReserved1;
|
uint16_t bfReserved1;
|
||||||
uint16_t bfReserved2;
|
uint16_t bfReserved2;
|
||||||
uint32_t bfOffBits;
|
uint32_t bfOffBits;
|
||||||
} BITMAPFILEHEADER;
|
};
|
||||||
|
|
||||||
// Used for both OS/2 and Windows BMP.
|
// Used for all Info Header Sizes.
|
||||||
// Contains only the parameters needed to load the image.
|
// Contains only the parameters needed to load the image.
|
||||||
typedef struct BITMAPINFOHEADER
|
struct BITMAPINFOHEADER
|
||||||
{
|
{
|
||||||
|
uint32_t biSize;
|
||||||
uint32_t biWidth;
|
uint32_t biWidth;
|
||||||
uint32_t biHeight;
|
uint32_t biHeight;
|
||||||
uint16_t biBitCount;
|
uint16_t biBitCount;
|
||||||
uint32_t biCompression;
|
uint32_t biCompression;
|
||||||
} BITMAPINFOHEADER;
|
uint32_t biClrUsed;
|
||||||
|
uint32_t rMask;
|
||||||
|
uint32_t gMask;
|
||||||
|
uint32_t bMask;
|
||||||
|
uint32_t aMask;
|
||||||
|
|
||||||
typedef struct WINBMPINFOHEADER // Size: 40.
|
bool isRGBMasks() const
|
||||||
|
{
|
||||||
|
return biSize >= BV2INFOHEADERSIZE ||
|
||||||
|
biCompression == BI_BITFIELDS ||
|
||||||
|
biCompression == BI_ALPHABITFIELDS;
|
||||||
|
};
|
||||||
|
bool isAlphaMask() const
|
||||||
|
{
|
||||||
|
return biSize >= BV3INFOHEADERSIZE ||
|
||||||
|
biCompression == BI_ALPHABITFIELDS;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WINBMPINFOHEADER // Size: 16 to 64
|
||||||
{
|
{
|
||||||
uint32_t biWidth;
|
uint32_t biWidth;
|
||||||
uint32_t biHeight;
|
uint32_t biHeight;
|
||||||
@ -121,15 +157,92 @@ typedef struct WINBMPINFOHEADER // Size: 40.
|
|||||||
uint32_t biYPelsPerMeter;
|
uint32_t biYPelsPerMeter;
|
||||||
uint32_t biClrUsed;
|
uint32_t biClrUsed;
|
||||||
uint32_t biClrImportant;
|
uint32_t biClrImportant;
|
||||||
} WINBMPINFOHEADER;
|
|
||||||
|
|
||||||
typedef struct OS2BMPINFOHEADER // Size: 12.
|
uint32_t redMask;
|
||||||
|
uint32_t greenMask;
|
||||||
|
uint32_t blueMask;
|
||||||
|
uint32_t alphaMask;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OS2BMPINFOHEADER // Size: 12.
|
||||||
{
|
{
|
||||||
uint16_t biWidth;
|
uint16_t biWidth;
|
||||||
uint16_t biHeight;
|
uint16_t biHeight;
|
||||||
uint16_t biPlanes;
|
uint16_t biPlanes;
|
||||||
uint16_t biBitCount;
|
uint16_t biBitCount;
|
||||||
} OS2BMPINFOHEADER;
|
};
|
||||||
|
|
||||||
|
// TO DO: support ICC profiles and colorimetry
|
||||||
|
struct CIEXYZ
|
||||||
|
{
|
||||||
|
uint32_t ciexyzX; // Fix Point: 2 bits integer part, 30 bits to fractional part
|
||||||
|
uint32_t ciexyzY;
|
||||||
|
uint32_t ciexyzZ;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CIEXYZTRIPLE
|
||||||
|
{
|
||||||
|
CIEXYZ ciexyzRed;
|
||||||
|
CIEXYZ ciexyzGreen;
|
||||||
|
CIEXYZ ciexyzBlue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BMPV4HEADER // Size: 108.
|
||||||
|
{
|
||||||
|
uint32_t bV4Width;
|
||||||
|
uint32_t bV4Height;
|
||||||
|
uint16_t bV4Planes;
|
||||||
|
uint16_t bV4BitCount;
|
||||||
|
uint32_t bV4Compression;
|
||||||
|
uint32_t bV4SizeImage;
|
||||||
|
uint32_t bV4XPelsPerMeter;
|
||||||
|
uint32_t bV4YPelsPerMeter;
|
||||||
|
uint32_t bV4ClrUsed;
|
||||||
|
uint32_t bV4ClrImportant;
|
||||||
|
|
||||||
|
uint32_t bV4RedMask;
|
||||||
|
uint32_t bV4GreenMask;
|
||||||
|
uint32_t bV4BlueMask;
|
||||||
|
uint32_t bV4AlphaMask;
|
||||||
|
// TO DO: support ICC profiles and colorimetry
|
||||||
|
uint32_t bV4CSType;
|
||||||
|
CIEXYZTRIPLE bV4Endpoints;
|
||||||
|
uint32_t bV4GammaRed;
|
||||||
|
uint32_t bV4GammaGreen;
|
||||||
|
uint32_t bV4GammaBlue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BMPV5HEADER // Size: 124.
|
||||||
|
{
|
||||||
|
uint32_t bV5Width;
|
||||||
|
uint32_t bV5Height;
|
||||||
|
uint16_t bV5Planes;
|
||||||
|
uint16_t bV5BitCount;
|
||||||
|
uint32_t bV5Compression;
|
||||||
|
|
||||||
|
uint32_t bV5SizeImage;
|
||||||
|
uint32_t bV5XPelsPerMeter;
|
||||||
|
uint32_t bV5YPelsPerMeter;
|
||||||
|
uint32_t bV5ClrUsed;
|
||||||
|
uint32_t bV5ClrImportant;
|
||||||
|
|
||||||
|
uint32_t bV5RedMask;
|
||||||
|
uint32_t bV5GreenMask;
|
||||||
|
uint32_t bV5BlueMask;
|
||||||
|
uint32_t bV5AlphaMask;
|
||||||
|
// TO DO: support ICC profiles and colorimetry
|
||||||
|
uint32_t bV5CSType;
|
||||||
|
CIEXYZTRIPLE bV5Endpoints;
|
||||||
|
|
||||||
|
uint32_t bV5GammaRed;
|
||||||
|
uint32_t bV5GammaGreen;
|
||||||
|
uint32_t bV5GammaBlue;
|
||||||
|
|
||||||
|
uint32_t bV5Intent;
|
||||||
|
uint32_t bV5ProfileData;
|
||||||
|
uint32_t bV5ProfileSize;
|
||||||
|
uint32_t bV5Reserved;
|
||||||
|
};
|
||||||
|
|
||||||
/* read_bmfileheader:
|
/* read_bmfileheader:
|
||||||
* Reads a BMP file header and check that it has the BMP magic number.
|
* Reads a BMP file header and check that it has the BMP magic number.
|
||||||
@ -155,21 +268,68 @@ static int read_win_bminfoheader(FILE *f, BITMAPINFOHEADER *infoheader)
|
|||||||
{
|
{
|
||||||
WINBMPINFOHEADER win_infoheader;
|
WINBMPINFOHEADER win_infoheader;
|
||||||
|
|
||||||
|
int biSize = infoheader->biSize;
|
||||||
|
|
||||||
|
if (biSize != OS22INFOHEADERSIZE16 &&
|
||||||
|
biSize != OS22INFOHEADERSIZE24 &&
|
||||||
|
biSize != WININFOHEADERSIZE &&
|
||||||
|
biSize != BV2INFOHEADERSIZE &&
|
||||||
|
biSize != BV3INFOHEADERSIZE &&
|
||||||
|
biSize != OS22INFOHEADERSIZE60 &&
|
||||||
|
biSize != OS22INFOHEADERSIZE64)
|
||||||
|
return -1;
|
||||||
|
|
||||||
win_infoheader.biWidth = fgetl(f);
|
win_infoheader.biWidth = fgetl(f);
|
||||||
win_infoheader.biHeight = fgetl(f);
|
win_infoheader.biHeight = fgetl(f);
|
||||||
win_infoheader.biPlanes = fgetw(f);
|
win_infoheader.biPlanes = fgetw(f);
|
||||||
win_infoheader.biBitCount = fgetw(f);
|
win_infoheader.biBitCount = fgetw(f); // = 16 bytes
|
||||||
win_infoheader.biCompression = fgetl(f);
|
|
||||||
win_infoheader.biSizeImage = fgetl(f);
|
win_infoheader.redMask = 0;
|
||||||
win_infoheader.biXPelsPerMeter = fgetl(f);
|
win_infoheader.greenMask = 0;
|
||||||
win_infoheader.biYPelsPerMeter = fgetl(f);
|
win_infoheader.blueMask = 0;
|
||||||
win_infoheader.biClrUsed = fgetl(f);
|
win_infoheader.alphaMask = 0;
|
||||||
win_infoheader.biClrImportant = fgetl(f);
|
if (biSize == OS22INFOHEADERSIZE16)
|
||||||
|
win_infoheader.biCompression = BI_RGB; // = 16 bytes
|
||||||
|
else {
|
||||||
|
ASSERT(biSize >= OS22INFOHEADERSIZE24);
|
||||||
|
win_infoheader.biCompression = fgetl(f);
|
||||||
|
win_infoheader.biSizeImage = fgetl(f); // = 24 bytes
|
||||||
|
|
||||||
|
if (biSize >= WININFOHEADERSIZE) {
|
||||||
|
win_infoheader.biXPelsPerMeter = fgetl(f);
|
||||||
|
win_infoheader.biYPelsPerMeter = fgetl(f);
|
||||||
|
win_infoheader.biClrUsed = fgetl(f);
|
||||||
|
win_infoheader.biClrImportant = fgetl(f); // = 40 bytes (WININFOHEADERSIZE)
|
||||||
|
|
||||||
|
// 'biCompression' is needed to execute
|
||||||
|
// infoheader->isRGBMasks() and infoheader->isAlphaMask()
|
||||||
|
infoheader->biCompression = win_infoheader.biCompression;
|
||||||
|
|
||||||
|
if (infoheader->isRGBMasks()) {
|
||||||
|
win_infoheader.redMask = fgetl(f);
|
||||||
|
win_infoheader.greenMask = fgetl(f);
|
||||||
|
win_infoheader.blueMask = fgetl(f); // = 52 bytes (BV2INFOHEADERSIZE)
|
||||||
|
if (infoheader->isAlphaMask()) {
|
||||||
|
win_infoheader.alphaMask = fgetl(f); // = 56 bytes (BV3INFOHEADERSIZE)
|
||||||
|
if (biSize >= OS22INFOHEADERSIZE60) {
|
||||||
|
fgetl(f); // <--discarded // = 60 bytes
|
||||||
|
if (biSize == OS22INFOHEADERSIZE64)
|
||||||
|
fgetl(f); // <--discarded // = 64 bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
infoheader->biWidth = win_infoheader.biWidth;
|
infoheader->biWidth = win_infoheader.biWidth;
|
||||||
infoheader->biHeight = win_infoheader.biHeight;
|
infoheader->biHeight = win_infoheader.biHeight;
|
||||||
infoheader->biBitCount = win_infoheader.biBitCount;
|
infoheader->biBitCount = win_infoheader.biBitCount;
|
||||||
infoheader->biCompression = win_infoheader.biCompression;
|
infoheader->biCompression = win_infoheader.biCompression;
|
||||||
|
infoheader->biClrUsed = win_infoheader.biClrUsed;
|
||||||
|
infoheader->rMask = win_infoheader.redMask;
|
||||||
|
infoheader->gMask = win_infoheader.greenMask;
|
||||||
|
infoheader->bMask = win_infoheader.blueMask;
|
||||||
|
infoheader->aMask = win_infoheader.alphaMask;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -190,6 +350,130 @@ static int read_os2_bminfoheader(FILE *f, BITMAPINFOHEADER *infoheader)
|
|||||||
infoheader->biHeight = os2_infoheader.biHeight;
|
infoheader->biHeight = os2_infoheader.biHeight;
|
||||||
infoheader->biBitCount = os2_infoheader.biBitCount;
|
infoheader->biBitCount = os2_infoheader.biBitCount;
|
||||||
infoheader->biCompression = 0;
|
infoheader->biCompression = 0;
|
||||||
|
infoheader->biClrUsed = -1; // Not defined in this format
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read_v4_bminfoheader:
|
||||||
|
* Reads information from an V4 format BMP file header.
|
||||||
|
*/
|
||||||
|
static int read_v4_bminfoheader(FILE *f, BITMAPINFOHEADER *infoheader)
|
||||||
|
{
|
||||||
|
BMPV4HEADER v4_infoheader;
|
||||||
|
|
||||||
|
v4_infoheader.bV4Width = fgetl(f);
|
||||||
|
v4_infoheader.bV4Height = fgetl(f);
|
||||||
|
v4_infoheader.bV4Planes = fgetw(f);
|
||||||
|
v4_infoheader.bV4BitCount = fgetw(f);
|
||||||
|
v4_infoheader.bV4Compression = fgetl(f);
|
||||||
|
|
||||||
|
v4_infoheader.bV4SizeImage = fgetl(f);
|
||||||
|
v4_infoheader.bV4XPelsPerMeter = fgetl(f);
|
||||||
|
v4_infoheader.bV4YPelsPerMeter = fgetl(f);
|
||||||
|
v4_infoheader.bV4ClrUsed = fgetl(f);
|
||||||
|
v4_infoheader.bV4ClrImportant = fgetl(f);
|
||||||
|
|
||||||
|
v4_infoheader.bV4RedMask = fgetl(f);
|
||||||
|
v4_infoheader.bV4GreenMask = fgetl(f);
|
||||||
|
v4_infoheader.bV4BlueMask = fgetl(f);
|
||||||
|
v4_infoheader.bV4AlphaMask = fgetl(f);
|
||||||
|
|
||||||
|
// TO DO: support ICC profiles and colorimetry
|
||||||
|
v4_infoheader.bV4CSType = fgetl(f);
|
||||||
|
|
||||||
|
// CIEXYZTRIPLE {
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzRed.ciexyzX = fgetl(f);
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzRed.ciexyzY = fgetl(f);
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzRed.ciexyzZ = fgetl(f);
|
||||||
|
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzGreen.ciexyzX = fgetl(f);
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzGreen.ciexyzY = fgetl(f);
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzGreen.ciexyzZ = fgetl(f);
|
||||||
|
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzBlue.ciexyzX = fgetl(f);
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzBlue.ciexyzY = fgetl(f);
|
||||||
|
v4_infoheader.bV4Endpoints.ciexyzBlue.ciexyzZ = fgetl(f);
|
||||||
|
// } CIEXYZTRIPLE
|
||||||
|
|
||||||
|
v4_infoheader.bV4GammaRed = fgetl(f);
|
||||||
|
v4_infoheader.bV4GammaGreen = fgetl(f);
|
||||||
|
v4_infoheader.bV4GammaBlue = fgetl(f);
|
||||||
|
|
||||||
|
infoheader->biWidth = v4_infoheader.bV4Width;
|
||||||
|
infoheader->biHeight = v4_infoheader.bV4Height;
|
||||||
|
infoheader->biBitCount = v4_infoheader.bV4BitCount;
|
||||||
|
infoheader->biCompression = v4_infoheader.bV4Compression;
|
||||||
|
infoheader->biClrUsed = v4_infoheader.bV4ClrUsed;
|
||||||
|
|
||||||
|
infoheader->rMask = v4_infoheader.bV4RedMask;
|
||||||
|
infoheader->gMask = v4_infoheader.bV4GreenMask;
|
||||||
|
infoheader->bMask = v4_infoheader.bV4BlueMask;
|
||||||
|
infoheader->aMask = v4_infoheader.bV4AlphaMask;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read_v5_bminfoheader:
|
||||||
|
* Reads information from an V5 format BMP file header.
|
||||||
|
*/
|
||||||
|
static int read_v5_bminfoheader(FILE *f, BITMAPINFOHEADER *infoheader)
|
||||||
|
{
|
||||||
|
BMPV5HEADER v5_infoheader;
|
||||||
|
|
||||||
|
v5_infoheader.bV5Width = fgetl(f);
|
||||||
|
v5_infoheader.bV5Height = fgetl(f);
|
||||||
|
v5_infoheader.bV5Planes = fgetw(f);
|
||||||
|
v5_infoheader.bV5BitCount = fgetw(f);
|
||||||
|
v5_infoheader.bV5Compression = fgetl(f);
|
||||||
|
|
||||||
|
v5_infoheader.bV5SizeImage = fgetl(f);
|
||||||
|
v5_infoheader.bV5XPelsPerMeter = fgetl(f);
|
||||||
|
v5_infoheader.bV5YPelsPerMeter = fgetl(f);
|
||||||
|
v5_infoheader.bV5ClrUsed = fgetl(f);
|
||||||
|
v5_infoheader.bV5ClrImportant = fgetl(f);
|
||||||
|
|
||||||
|
v5_infoheader.bV5RedMask = fgetl(f);
|
||||||
|
v5_infoheader.bV5GreenMask = fgetl(f);
|
||||||
|
v5_infoheader.bV5BlueMask = fgetl(f);
|
||||||
|
v5_infoheader.bV5AlphaMask = fgetl(f);
|
||||||
|
|
||||||
|
// TO DO: support ICC profiles and colorimetry
|
||||||
|
v5_infoheader.bV5CSType = fgetl(f);
|
||||||
|
|
||||||
|
// CIEXYZTRIPLE {
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzRed.ciexyzX = fgetl(f);
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzRed.ciexyzY = fgetl(f);
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzRed.ciexyzZ = fgetl(f);
|
||||||
|
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzGreen.ciexyzX = fgetl(f);
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzGreen.ciexyzY = fgetl(f);
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzGreen.ciexyzZ = fgetl(f);
|
||||||
|
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzBlue.ciexyzX = fgetl(f);
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzBlue.ciexyzY = fgetl(f);
|
||||||
|
v5_infoheader.bV5Endpoints.ciexyzBlue.ciexyzZ = fgetl(f);
|
||||||
|
// } CIEXYZTRIPLE
|
||||||
|
|
||||||
|
v5_infoheader.bV5GammaRed = fgetl(f);
|
||||||
|
v5_infoheader.bV5GammaGreen = fgetl(f);
|
||||||
|
v5_infoheader.bV5GammaBlue = fgetl(f);
|
||||||
|
|
||||||
|
v5_infoheader.bV5Intent = fgetl(f);
|
||||||
|
v5_infoheader.bV5ProfileData = fgetl(f);
|
||||||
|
v5_infoheader.bV5ProfileSize = fgetl(f);
|
||||||
|
fgetl(f); // <-- Reserved DWORD
|
||||||
|
|
||||||
|
infoheader->biWidth = v5_infoheader.bV5Width;
|
||||||
|
infoheader->biHeight = v5_infoheader.bV5Height;
|
||||||
|
infoheader->biBitCount = v5_infoheader.bV5BitCount;
|
||||||
|
infoheader->biCompression = v5_infoheader.bV5Compression;
|
||||||
|
infoheader->biClrUsed = v5_infoheader.bV5ClrUsed;
|
||||||
|
|
||||||
|
infoheader->rMask = v5_infoheader.bV5RedMask;
|
||||||
|
infoheader->gMask = v5_infoheader.bV5GreenMask;
|
||||||
|
infoheader->bMask = v5_infoheader.bV5BlueMask;
|
||||||
|
infoheader->aMask = v5_infoheader.bV5AlphaMask;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -253,6 +537,38 @@ static void read_1bit_line(int length, FILE *f, Image *image, int line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read_2bit_line (not standard):
|
||||||
|
* Support function for reading the 2 bit bitmap file format.
|
||||||
|
*/
|
||||||
|
static void read_2bit_line(int length, FILE *f, Image *image, int line)
|
||||||
|
{
|
||||||
|
unsigned char b[16];
|
||||||
|
unsigned long n;
|
||||||
|
int i, j, k;
|
||||||
|
int temp;
|
||||||
|
int pix;
|
||||||
|
|
||||||
|
for (i=0; i<length; i++) {
|
||||||
|
j = i % 16;
|
||||||
|
if (j == 0) {
|
||||||
|
n = fgetl(f);
|
||||||
|
for (k=0; k<4; k++) {
|
||||||
|
temp = n & 255;
|
||||||
|
b[k*4+3] = temp & 3;
|
||||||
|
temp = temp >> 2;
|
||||||
|
b[k*4+2] = temp & 3;
|
||||||
|
temp = temp >> 2;
|
||||||
|
b[k*4+1] = temp & 3;
|
||||||
|
temp = temp >> 2;
|
||||||
|
b[k*4] = temp & 3;
|
||||||
|
n = n >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pix = b[j];
|
||||||
|
put_pixel(image, i, line, pix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* read_4bit_line:
|
/* read_4bit_line:
|
||||||
* Support function for reading the 4 bit bitmap file format.
|
* Support function for reading the 4 bit bitmap file format.
|
||||||
*/
|
*/
|
||||||
@ -305,9 +621,9 @@ static void read_8bit_line(int length, FILE *f, Image *image, int line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_16bit_line(int length, FILE *f, Image *image, int line)
|
static void read_16bit_line(int length, FILE *f, Image *image, int line, bool& withAlpha)
|
||||||
{
|
{
|
||||||
int i, r, g, b, word;
|
int i, r, g, b, a, word;
|
||||||
|
|
||||||
for (i=0; i<length; i++) {
|
for (i=0; i<length; i++) {
|
||||||
word = fgetw(f);
|
word = fgetw(f);
|
||||||
@ -315,11 +631,13 @@ static void read_16bit_line(int length, FILE *f, Image *image, int line)
|
|||||||
r = (word >> 10) & 0x1f;
|
r = (word >> 10) & 0x1f;
|
||||||
g = (word >> 5) & 0x1f;
|
g = (word >> 5) & 0x1f;
|
||||||
b = (word) & 0x1f;
|
b = (word) & 0x1f;
|
||||||
|
a = (word & 0x8000 ? 255 : 0);
|
||||||
|
if (a)
|
||||||
|
withAlpha = true;
|
||||||
put_pixel(image, i, line,
|
put_pixel(image, i, line,
|
||||||
rgba(scale_5bits_to_8bits(r),
|
rgba(scale_5bits_to_8bits(r),
|
||||||
scale_5bits_to_8bits(g),
|
scale_5bits_to_8bits(g),
|
||||||
scale_5bits_to_8bits(b), 255));
|
scale_5bits_to_8bits(b), a));
|
||||||
}
|
}
|
||||||
|
|
||||||
i = (2*i) % 4;
|
i = (2*i) % 4;
|
||||||
@ -345,23 +663,26 @@ static void read_24bit_line(int length, FILE *f, Image *image, int line)
|
|||||||
fgetc(f);
|
fgetc(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_32bit_line(int length, FILE *f, Image *image, int line)
|
static void read_32bit_line(int length, FILE *f, Image *image, int line,
|
||||||
|
bool& withAlpha)
|
||||||
{
|
{
|
||||||
int i, r, g, b;
|
int i, r, g, b, a;
|
||||||
|
|
||||||
for (i=0; i<length; i++) {
|
for (i=0; i<length; i++) {
|
||||||
b = fgetc(f);
|
b = fgetc(f);
|
||||||
g = fgetc(f);
|
g = fgetc(f);
|
||||||
r = fgetc(f);
|
r = fgetc(f);
|
||||||
fgetc(f);
|
a = fgetc(f);
|
||||||
put_pixel(image, i, line, rgba(r, g, b, 255));
|
if (a)
|
||||||
|
withAlpha = true;
|
||||||
|
put_pixel(image, i, line, rgba(r, g, b, a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read_image:
|
/* read_image:
|
||||||
* For reading the noncompressed BMP image format.
|
* For reading the noncompressed BMP image format.
|
||||||
*/
|
*/
|
||||||
static void read_image(FILE *f, Image *image, const BITMAPINFOHEADER *infoheader, FileOp *fop)
|
static void read_image(FILE *f, Image *image, const BITMAPINFOHEADER *infoheader, FileOp *fop, bool& withAlpha)
|
||||||
{
|
{
|
||||||
int i, line, height, dir;
|
int i, line, height, dir;
|
||||||
|
|
||||||
@ -373,17 +694,26 @@ static void read_image(FILE *f, Image *image, const BITMAPINFOHEADER *infoheader
|
|||||||
for (i=0; i<height; i++, line+=dir) {
|
for (i=0; i<height; i++, line+=dir) {
|
||||||
switch (infoheader->biBitCount) {
|
switch (infoheader->biBitCount) {
|
||||||
case 1: read_1bit_line(infoheader->biWidth, f, image, line); break;
|
case 1: read_1bit_line(infoheader->biWidth, f, image, line); break;
|
||||||
|
case 2: read_2bit_line(infoheader->biWidth, f, image, line); break;
|
||||||
case 4: read_4bit_line(infoheader->biWidth, f, image, line); break;
|
case 4: read_4bit_line(infoheader->biWidth, f, image, line); break;
|
||||||
case 8: read_8bit_line(infoheader->biWidth, f, image, line); break;
|
case 8: read_8bit_line(infoheader->biWidth, f, image, line); break;
|
||||||
case 16: read_16bit_line(infoheader->biWidth, f, image, line); break;
|
case 16: read_16bit_line(infoheader->biWidth, f, image, line, withAlpha); break;
|
||||||
case 24: read_24bit_line(infoheader->biWidth, f, image, line); break;
|
case 24: read_24bit_line(infoheader->biWidth, f, image, line); break;
|
||||||
case 32: read_32bit_line(infoheader->biWidth, f, image, line); break;
|
case 32: read_32bit_line(infoheader->biWidth, f, image, line, withAlpha); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fop->setProgress((float)(i+1) / (float)(height));
|
fop->setProgress((float)(i+1) / (float)(height));
|
||||||
if (fop->isStop())
|
if (fop->isStop())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((infoheader->biBitCount == 32 ||
|
||||||
|
infoheader->biBitCount == 16 ) && !withAlpha) {
|
||||||
|
LockImageBits<RgbTraits> imageBits(image, image->bounds());
|
||||||
|
auto imgIt = imageBits.begin(), imgEnd = imageBits.end();
|
||||||
|
for (; imgIt != imgEnd; ++imgIt)
|
||||||
|
*imgIt |= 0xff000000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read_rle8_compressed_image:
|
/* read_rle8_compressed_image:
|
||||||
@ -545,27 +875,33 @@ static void read_rle4_compressed_image(FILE *f, Image *image, const BITMAPINFOHE
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infoheader,
|
static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infoheader,
|
||||||
unsigned long rmask, unsigned long gmask, unsigned long bmask)
|
uint32_t rmask, uint32_t gmask, uint32_t bmask,
|
||||||
|
uint32_t amask, bool& withAlpha)
|
||||||
{
|
{
|
||||||
#define CALC_SHIFT(c) \
|
#define CALC_SHIFT(c) \
|
||||||
mask = ~c##mask; \
|
c##shift = 0; \
|
||||||
c##shift = 0; \
|
if (c##mask) { \
|
||||||
while (mask & 1) { \
|
mask = ~c##mask; \
|
||||||
++c##shift; \
|
while (mask & 1) { \
|
||||||
mask >>= 1; \
|
++c##shift; \
|
||||||
} \
|
mask >>= 1; \
|
||||||
if ((c##mask >> c##shift) == 0x1f) \
|
} \
|
||||||
c##scale = scale_5bits_to_8bits; \
|
if (mask) { \
|
||||||
else if ((c##mask >> c##shift) == 0x3f) \
|
mask = ~mask; \
|
||||||
c##scale = scale_6bits_to_8bits; \
|
while (mask & 1) { \
|
||||||
else \
|
c##bits++; \
|
||||||
c##scale = NULL;
|
mask >>= 1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
c##bits = 32 - c##shift; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
c##bits = 8; \
|
||||||
|
|
||||||
unsigned long buffer, mask, rshift, gshift, bshift;
|
uint32_t buffer, mask, rshift, gshift, bshift, ashift;
|
||||||
int i, j, k, line, height, dir, r, g, b;
|
int rbits = 0, gbits = 0, bbits = 0, abits = 0;
|
||||||
int (*rscale)(int);
|
int i, j, k, line, height, dir, r, g, b, a;
|
||||||
int (*gscale)(int);
|
|
||||||
int (*bscale)(int);
|
|
||||||
int bits_per_pixel;
|
int bits_per_pixel;
|
||||||
int bytes_per_pixel;
|
int bytes_per_pixel;
|
||||||
|
|
||||||
@ -578,6 +914,7 @@ static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infohea
|
|||||||
CALC_SHIFT(r);
|
CALC_SHIFT(r);
|
||||||
CALC_SHIFT(g);
|
CALC_SHIFT(g);
|
||||||
CALC_SHIFT(b);
|
CALC_SHIFT(b);
|
||||||
|
CALC_SHIFT(a);
|
||||||
|
|
||||||
/* calculate bits-per-pixel and bytes-per-pixel */
|
/* calculate bits-per-pixel and bytes-per-pixel */
|
||||||
bits_per_pixel = infoheader->biBitCount;
|
bits_per_pixel = infoheader->biBitCount;
|
||||||
@ -594,12 +931,16 @@ static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infohea
|
|||||||
r = (buffer & rmask) >> rshift;
|
r = (buffer & rmask) >> rshift;
|
||||||
g = (buffer & gmask) >> gshift;
|
g = (buffer & gmask) >> gshift;
|
||||||
b = (buffer & bmask) >> bshift;
|
b = (buffer & bmask) >> bshift;
|
||||||
|
a = (buffer & amask) >> ashift;
|
||||||
|
|
||||||
r = rscale ? rscale(r): r;
|
r = (rbits == 8 ? r : scale_xxbits_to_8bits(rbits, r) );
|
||||||
g = gscale ? gscale(g): g;
|
g = (gbits == 8 ? g : scale_xxbits_to_8bits(gbits, g) );
|
||||||
b = bscale ? bscale(b): b;
|
b = (bbits == 8 ? b : scale_xxbits_to_8bits(bbits, b) );
|
||||||
|
a = (abits == 8 ? a : scale_xxbits_to_8bits(abits, a) );
|
||||||
|
|
||||||
put_pixel_fast<RgbTraits>(image, j, line, rgba(r, g, b, 255));
|
if (a)
|
||||||
|
withAlpha = true;
|
||||||
|
put_pixel_fast<RgbTraits>(image, j, line, rgba(r, g, b, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
j = (bytes_per_pixel*j) % 4;
|
j = (bytes_per_pixel*j) % 4;
|
||||||
@ -608,12 +949,19 @@ static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infohea
|
|||||||
fgetc(f);
|
fgetc(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!withAlpha) {
|
||||||
|
LockImageBits<RgbTraits> imageBits(image, image->bounds());
|
||||||
|
auto imgIt = imageBits.begin(), imgEnd = imageBits.end();
|
||||||
|
for (; imgIt != imgEnd; ++imgIt)
|
||||||
|
*imgIt |= 0xff000000;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BmpFormat::onLoad(FileOp *fop)
|
bool BmpFormat::onLoad(FileOp *fop)
|
||||||
{
|
{
|
||||||
unsigned long rmask, gmask, bmask;
|
uint32_t rmask, gmask, bmask, amask;
|
||||||
BITMAPFILEHEADER fileheader;
|
BITMAPFILEHEADER fileheader;
|
||||||
BITMAPINFOHEADER infoheader;
|
BITMAPINFOHEADER infoheader;
|
||||||
unsigned long biSize;
|
unsigned long biSize;
|
||||||
@ -626,31 +974,79 @@ bool BmpFormat::onLoad(FileOp *fop)
|
|||||||
if (read_bmfileheader(f, &fileheader) != 0)
|
if (read_bmfileheader(f, &fileheader) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
biSize = fgetl(f);
|
infoheader.biSize = fgetl(f);
|
||||||
|
|
||||||
if (biSize == WININFOHEADERSIZE) {
|
if (infoheader.biSize >= 16 && infoheader.biSize <= 64) {
|
||||||
format = BMP_OPTIONS_FORMAT_WINDOWS;
|
format = BMP_OPTIONS_FORMAT_WINDOWS;
|
||||||
|
|
||||||
if (read_win_bminfoheader(f, &infoheader) != 0) {
|
if (read_win_bminfoheader(f, &infoheader) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (infoheader.biCompression != BI_BITFIELDS)
|
if (infoheader.biCompression != BI_BITFIELDS &&
|
||||||
read_bmicolors(fop, fileheader.bfOffBits - 54, f, true);
|
infoheader.biCompression != BI_ALPHABITFIELDS)
|
||||||
|
read_bmicolors(fop,
|
||||||
|
fileheader.bfOffBits - infoheader.biSize - OS2FILEHEADERSIZE,
|
||||||
|
f, true);
|
||||||
|
else if (infoheader.biBitCount <= 8)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else if (biSize == OS2INFOHEADERSIZE) {
|
else if (infoheader.biSize == OS2INFOHEADERSIZE) {
|
||||||
format = BMP_OPTIONS_FORMAT_OS2;
|
format = BMP_OPTIONS_FORMAT_OS2;
|
||||||
|
|
||||||
if (read_os2_bminfoheader(f, &infoheader) != 0) {
|
if (read_os2_bminfoheader(f, &infoheader) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* compute number of colors recorded */
|
/* compute number of colors recorded */
|
||||||
if (infoheader.biCompression != BI_BITFIELDS)
|
if (infoheader.biCompression != BI_BITFIELDS &&
|
||||||
read_bmicolors(fop, fileheader.bfOffBits - 26, f, false);
|
infoheader.biCompression != BI_ALPHABITFIELDS)
|
||||||
|
read_bmicolors(fop,
|
||||||
|
fileheader.bfOffBits - infoheader.biSize - OS2FILEHEADERSIZE,
|
||||||
|
f, false);
|
||||||
|
else if (infoheader.biBitCount <= 8)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (infoheader.biSize == BV4INFOHEADERSIZE) {
|
||||||
|
format = BMP_OPTIONS_FORMAT_WINDOWS;
|
||||||
|
|
||||||
|
if (read_v4_bminfoheader(f, &infoheader) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* compute number of colors recorded */
|
||||||
|
if (infoheader.biCompression != BI_BITFIELDS &&
|
||||||
|
infoheader.biCompression != BI_ALPHABITFIELDS)
|
||||||
|
read_bmicolors(fop,
|
||||||
|
fileheader.bfOffBits - infoheader.biSize - OS2FILEHEADERSIZE,
|
||||||
|
f, true);
|
||||||
|
else if (infoheader.biBitCount <= 8)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (infoheader.biSize == BV5INFOHEADERSIZE) {
|
||||||
|
format = BMP_OPTIONS_FORMAT_WINDOWS;
|
||||||
|
|
||||||
|
if (read_v5_bminfoheader(f, &infoheader) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* compute number of colors recorded */
|
||||||
|
if (infoheader.biCompression != BI_BITFIELDS &&
|
||||||
|
infoheader.biCompression != BI_ALPHABITFIELDS)
|
||||||
|
read_bmicolors(fop,
|
||||||
|
fileheader.bfOffBits - infoheader.biSize - OS2FILEHEADERSIZE,
|
||||||
|
f, true);
|
||||||
|
else if (infoheader.biBitCount <= 8)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check compatible Compression
|
||||||
|
if (infoheader.biCompression == 4 ||
|
||||||
|
infoheader.biCompression == 5 ||
|
||||||
|
infoheader.biCompression > 6) {
|
||||||
|
fop->setError("Unsupported BMP compression.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check image size is valid
|
// Check image size is valid
|
||||||
{
|
{
|
||||||
if (int(infoheader.biWidth) < 1 ||
|
if (int(infoheader.biWidth) < 1 ||
|
||||||
@ -681,13 +1077,14 @@ bool BmpFormat::onLoad(FileOp *fop)
|
|||||||
pixelFormat = IMAGE_INDEXED;
|
pixelFormat = IMAGE_INDEXED;
|
||||||
|
|
||||||
/* bitfields have the 'mask' for each component */
|
/* bitfields have the 'mask' for each component */
|
||||||
if (infoheader.biCompression == BI_BITFIELDS) {
|
if (infoheader.isRGBMasks()) {
|
||||||
rmask = fgetl(f);
|
rmask = infoheader.rMask;
|
||||||
gmask = fgetl(f);
|
gmask = infoheader.gMask;
|
||||||
bmask = fgetl(f);
|
bmask = infoheader.bMask;
|
||||||
|
amask = (infoheader.isAlphaMask() ? infoheader.aMask : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rmask = gmask = bmask = 0;
|
rmask = gmask = bmask = amask = 0;
|
||||||
|
|
||||||
ImageRef image = fop->sequenceImage(pixelFormat,
|
ImageRef image = fop->sequenceImage(pixelFormat,
|
||||||
infoheader.biWidth,
|
infoheader.biWidth,
|
||||||
@ -697,14 +1094,21 @@ bool BmpFormat::onLoad(FileOp *fop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pixelFormat == IMAGE_RGB)
|
if (pixelFormat == IMAGE_RGB)
|
||||||
clear_image(image.get(), rgba(0, 0, 0, 255));
|
clear_image(image.get(),
|
||||||
|
rgba(0, 0, 0, (infoheader.isAlphaMask() ? 0 : 255)));
|
||||||
else
|
else
|
||||||
clear_image(image.get(), 0);
|
clear_image(image.get(), 0);
|
||||||
|
|
||||||
|
// We indirectly calculate 'on the fly' if the BMP file
|
||||||
|
// has all its pixels with alpha value equal to 0 (i.e. BMP
|
||||||
|
// without alpha channel) or if there is at least one pixel
|
||||||
|
// with non 0 alpha (i.e. BMP works with alpha channel).
|
||||||
|
// The result of this analysis will be stored in the boolean 'withAlpha'.
|
||||||
|
bool withAlpha = false;
|
||||||
switch (infoheader.biCompression) {
|
switch (infoheader.biCompression) {
|
||||||
|
|
||||||
case BI_RGB:
|
case BI_RGB:
|
||||||
read_image(f, image.get(), &infoheader, fop);
|
read_image(f, image.get(), &infoheader, fop, withAlpha);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BI_RLE8:
|
case BI_RLE8:
|
||||||
@ -716,7 +1120,9 @@ bool BmpFormat::onLoad(FileOp *fop)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BI_BITFIELDS:
|
case BI_BITFIELDS:
|
||||||
if (read_bitfields_image(f, image.get(), &infoheader, rmask, gmask, bmask) < 0) {
|
case BI_ALPHABITFIELDS:
|
||||||
|
if (read_bitfields_image(f, image.get(), &infoheader,
|
||||||
|
rmask, gmask, bmask, amask, withAlpha) < 0) {
|
||||||
fop->setError("Unsupported bitfields in the BMP file.\n");
|
fop->setError("Unsupported bitfields in the BMP file.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -742,7 +1148,12 @@ bool BmpFormat::onLoad(FileOp *fop)
|
|||||||
bmp_options->red_mask = rmask;
|
bmp_options->red_mask = rmask;
|
||||||
bmp_options->green_mask = gmask;
|
bmp_options->green_mask = gmask;
|
||||||
bmp_options->blue_mask = bmask;
|
bmp_options->blue_mask = bmask;
|
||||||
|
if (withAlpha) {
|
||||||
|
bmp_options->alpha_mask = amask;
|
||||||
|
fop->sequenceSetHasAlpha(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bmp_options->alpha_mask = 0;
|
||||||
fop->setLoadedFormatOptions(bmp_options);
|
fop->setLoadedFormatOptions(bmp_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,9 +1171,14 @@ bool BmpFormat::onSave(FileOp *fop)
|
|||||||
int biSizeImage;
|
int biSizeImage;
|
||||||
int ncolors = fop->sequenceGetNColors();
|
int ncolors = fop->sequenceGetNColors();
|
||||||
int bpp = 0;
|
int bpp = 0;
|
||||||
|
bool withAlpha = img->needAlpha();
|
||||||
|
|
||||||
switch (spec.colorMode()) {
|
switch (spec.colorMode()) {
|
||||||
case ColorMode::RGB:
|
case ColorMode::RGB:
|
||||||
bpp = 24;
|
if (withAlpha)
|
||||||
|
bpp = 32;
|
||||||
|
else
|
||||||
|
bpp = 24;
|
||||||
break;
|
break;
|
||||||
case ColorMode::GRAYSCALE:
|
case ColorMode::GRAYSCALE:
|
||||||
bpp = 8;
|
bpp = 8;
|
||||||
@ -789,13 +1205,18 @@ bool BmpFormat::onSave(FileOp *fop)
|
|||||||
|
|
||||||
if (bpp <= 8) {
|
if (bpp <= 8) {
|
||||||
biSizeImage = (w + filler)*bpp/8 * h;
|
biSizeImage = (w + filler)*bpp/8 * h;
|
||||||
bfSize = (54 // header
|
bfSize = (WININFOHEADERSIZE + OS2FILEHEADERSIZE // header
|
||||||
+ ncolors*4 // palette
|
+ ncolors*4 // palette
|
||||||
+ biSizeImage); // image data
|
+ biSizeImage); // image data
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
biSizeImage = (w*3 + filler) * h;
|
biSizeImage = (w*3 + filler) * h;
|
||||||
bfSize = 54 + biSizeImage; // header + image data
|
if (withAlpha)
|
||||||
|
bfSize = BV3INFOHEADERSIZE +
|
||||||
|
OS2FILEHEADERSIZE + biSizeImage; // header + image data
|
||||||
|
else
|
||||||
|
bfSize = WININFOHEADERSIZE +
|
||||||
|
OS2FILEHEADERSIZE + biSizeImage; // header + image data
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHandle handle(open_file_with_exception_sync_on_close(fop->filename(), "wb"));
|
FileHandle handle(open_file_with_exception_sync_on_close(fop->filename(), "wb"));
|
||||||
@ -807,25 +1228,38 @@ bool BmpFormat::onSave(FileOp *fop)
|
|||||||
fputw(0, f); /* bfReserved1 */
|
fputw(0, f); /* bfReserved1 */
|
||||||
fputw(0, f); /* bfReserved2 */
|
fputw(0, f); /* bfReserved2 */
|
||||||
|
|
||||||
if (bpp <= 8) /* bfOffBits */
|
if (bpp <= 8) {
|
||||||
fputl(54+ncolors*4, f);
|
fputl(WININFOHEADERSIZE + OS2FILEHEADERSIZE +
|
||||||
else
|
ncolors * 4, f); /* bfOffBits */
|
||||||
fputl(54, f);
|
/* info_header */
|
||||||
|
fputl(WININFOHEADERSIZE, f); /* biSize */
|
||||||
|
}
|
||||||
|
else if (withAlpha) {
|
||||||
|
fputl(BV3INFOHEADERSIZE + OS2FILEHEADERSIZE, f); /* bfOffBits -taking account RBGA masks- */
|
||||||
|
/* info_header */
|
||||||
|
fputl(BV3INFOHEADERSIZE, f); /* biSize */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fputl(WININFOHEADERSIZE + OS2FILEHEADERSIZE, f); /* bfOffBits */
|
||||||
|
/* info_header */
|
||||||
|
fputl(WININFOHEADERSIZE, f); /* biSize */
|
||||||
|
}
|
||||||
|
|
||||||
/* info_header */
|
|
||||||
fputl(40, f); /* biSize */
|
|
||||||
fputl(w, f); /* biWidth */
|
fputl(w, f); /* biWidth */
|
||||||
fputl(h, f); /* biHeight */
|
fputl(h, f); /* biHeight */
|
||||||
fputw(1, f); /* biPlanes */
|
fputw(1, f); /* biPlanes */
|
||||||
fputw(bpp, f); /* biBitCount */
|
fputw(bpp, f); /* biBitCount */
|
||||||
fputl(0, f); /* biCompression */
|
if (withAlpha) /* biCompression */
|
||||||
|
fputl(BI_BITFIELDS, f);
|
||||||
|
else
|
||||||
|
fputl(BI_RGB, f);
|
||||||
fputl(biSizeImage, f); /* biSizeImage */
|
fputl(biSizeImage, f); /* biSizeImage */
|
||||||
fputl(0xB12, f); /* biXPelsPerMeter (0xB12 = 72 dpi) */
|
fputl(0xB12, f); /* biXPelsPerMeter (0xB12 = 72 dpi) */
|
||||||
fputl(0xB12, f); /* biYPelsPerMeter */
|
fputl(0xB12, f); /* biYPelsPerMeter */
|
||||||
|
|
||||||
if (bpp <= 8) {
|
if (bpp <= 8) {
|
||||||
fputl(ncolors, f); /* biClrUsed */
|
fputl(ncolors, f); /* biClrUsed */
|
||||||
fputl(ncolors, f); /* biClrImportant */
|
fputl(ncolors, f); /* biClrImportant */
|
||||||
|
|
||||||
// Save the palette
|
// Save the palette
|
||||||
for (i=0; i<ncolors; i++) {
|
for (i=0; i<ncolors; i++) {
|
||||||
@ -837,8 +1271,14 @@ bool BmpFormat::onSave(FileOp *fop)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fputl(0, f); /* biClrUsed */
|
fputl(0, f); /* biClrUsed */
|
||||||
fputl(0, f); /* biClrImportant */
|
fputl(0, f); /* biClrImportant */
|
||||||
|
if (withAlpha) {
|
||||||
|
fputl(0x00ff0000, f);
|
||||||
|
fputl(0x0000ff00, f);
|
||||||
|
fputl(0x000000ff, f);
|
||||||
|
fputl(0xff000000, f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only used in indexed mode
|
// Only used in indexed mode
|
||||||
@ -861,6 +1301,8 @@ bool BmpFormat::onSave(FileOp *fop)
|
|||||||
fputc(rgba_getb(c), f);
|
fputc(rgba_getb(c), f);
|
||||||
fputc(rgba_getg(c), f);
|
fputc(rgba_getg(c), f);
|
||||||
fputc(rgba_getr(c), f);
|
fputc(rgba_getr(c), f);
|
||||||
|
if (withAlpha)
|
||||||
|
fputc(rgba_geta(c), f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
// Copyright (C) 2020 Igara Studio S.A.
|
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -28,6 +28,18 @@ namespace doc {
|
|||||||
return (v << 2) | (v >> 4);
|
return (v << 2) | (v >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int scale_xxbits_to_8bits(const int xx, const int v) {
|
||||||
|
switch (xx) {
|
||||||
|
case 3:
|
||||||
|
return scale_3bits_to_8bits(v);
|
||||||
|
case 5:
|
||||||
|
return scale_5bits_to_8bits(v);
|
||||||
|
case 6:
|
||||||
|
return scale_6bits_to_8bits(v);
|
||||||
|
}
|
||||||
|
return (int)(255.0 / (double(1<<xx) - 1.0) * (double)v);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace doc
|
} // namespace doc
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user