blob: f1492cb73245b569597d61a2a7f55f639b9c97ed [file] [log] [blame]
// ==========================================================
// Utility functions
//
// Design and implementation by
// - Floris van den Berg (flvdberg@wxs.nl)
// - Hervé Drolon <drolon@infonie.fr>
// - Ryan Rubley (ryan@lostreality.org)
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#ifndef UTILITIES_H
#define UTILITIES_H
// ==========================================================
// Standard includes used by the library
// ==========================================================
#include <math.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <assert.h>
#include <limits.h>
#include <string>
#include <list>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <sstream>
#include <algorithm>
// ==========================================================
// Bitmap palette and pixels alignment
// ==========================================================
#define FIBITMAP_ALIGNMENT 16 // We will use a 16 bytes alignment boundary
// Memory allocation on a specified alignment boundary
// defined in BitmapAccess.cpp
void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment);
void FreeImage_Aligned_Free(void* mem);
// ==========================================================
// File I/O structs
// ==========================================================
// these structs are for file I/O and should not be confused with similar
// structs in FreeImage.h which are for in-memory bitmap handling
#ifdef _WIN32
#pragma pack(push, 1)
#else
#pragma pack(1)
#endif // _WIN32
typedef struct tagFILE_RGBA {
unsigned char r,g,b,a;
} FILE_RGBA;
typedef struct tagFILE_BGRA {
unsigned char b,g,r,a;
} FILE_BGRA;
typedef struct tagFILE_RGB {
unsigned char r,g,b;
} FILE_RGB;
typedef struct tagFILE_BGR {
unsigned char b,g,r;
} FILE_BGR;
#ifdef _WIN32
#pragma pack(pop)
#else
#pragma pack()
#endif // _WIN32
// ==========================================================
// Utility functions
// ==========================================================
#ifndef _WIN32
inline char*
i2a(unsigned i, char *a, unsigned r) {
if (i/r > 0) a = i2a(i/r,a,r);
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r];
return a+1;
}
/**
Transforms integer i into an ascii string and stores the result in a;
string is encoded in the base indicated by r.
@param i Number to be converted
@param a String result
@param r Base of value; must be in the range 2 - 36
@return Returns a
*/
inline char *
_itoa(int i, char *a, int r) {
r = ((r < 2) || (r > 36)) ? 10 : r;
if(i < 0) {
*a = '-';
*i2a(-i, a+1, r) = 0;
}
else *i2a(i, a, r) = 0;
return a;
}
#endif // !_WIN32
inline unsigned char
HINIBBLE (unsigned char byte) {
return byte & 0xF0;
}
inline unsigned char
LOWNIBBLE (unsigned char byte) {
return byte & 0x0F;
}
inline int
CalculateUsedBits(int bits) {
int bit_count = 0;
unsigned bit = 1;
for (unsigned i = 0; i < 32; i++) {
if ((bits & bit) == bit) {
bit_count++;
}
bit <<= 1;
}
return bit_count;
}
inline int
CalculateLine(int width, int bitdepth) {
return ((width * bitdepth) + 7) / 8;
}
inline int
CalculatePitch(int line) {
return line + 3 & ~3;
}
inline int
CalculateUsedPaletteEntries(int bit_count) {
if ((bit_count >= 1) && (bit_count <= 8))
return 1 << bit_count;
return 0;
}
inline unsigned char *
CalculateScanLine(unsigned char *bits, unsigned pitch, int scanline) {
return (bits + (pitch * scanline));
}
inline void
ReplaceExtension(char *result, const char *filename, const char *extension) {
for (size_t i = strlen(filename) - 1; i > 0; --i) {
if (filename[i] == '.') {
memcpy(result, filename, i);
result[i] = '.';
memcpy(result + i + 1, extension, strlen(extension) + 1);
return;
}
}
memcpy(result, filename, strlen(filename));
result[strlen(filename)] = '.';
memcpy(result + strlen(filename) + 1, extension, strlen(extension) + 1);
}
// ==========================================================
// Big Endian / Little Endian utility functions
// ==========================================================
inline WORD
__SwapUInt16(WORD arg) {
#if defined(_MSC_VER) && _MSC_VER >= 1310
return _byteswap_ushort(arg);
#elif defined(__i386__) && defined(__GNUC__)
__asm__("xchgb %b0, %h0" : "+q" (arg));
return arg;
#elif defined(__ppc__) && defined(__GNUC__)
WORD result;
__asm__("lhbrx %0,0,%1" : "=r" (result) : "r" (&arg), "m" (arg));
return result;
#else
// swap bytes
WORD result;
result = ((arg << 8) & 0xFF00) | ((arg >> 8) & 0x00FF);
return result;
#endif
}
inline DWORD
__SwapUInt32(DWORD arg) {
#if defined(_MSC_VER) && _MSC_VER >= 1310
return _byteswap_ulong(arg);
#elif defined(__i386__) && defined(__GNUC__)
__asm__("bswap %0" : "+r" (arg));
return arg;
#elif defined(__ppc__) && defined(__GNUC__)
DWORD result;
__asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&arg), "m" (arg));
return result;
#else
// swap words then bytes
DWORD result;
result = ((arg & 0x000000FF) << 24) | ((arg & 0x0000FF00) << 8) | ((arg >> 8) & 0x0000FF00) | ((arg >> 24) & 0x000000FF);
return result;
#endif
}
/**
for later use ...
inline uint64_t
SwapInt64(uint64_t arg) {
#if defined(_MSC_VER) && _MSC_VER >= 1310
return _byteswap_uint64(arg);
#else
union Swap {
uint64_t sv;
uint32_t ul[2];
} tmp, result;
tmp.sv = arg;
result.ul[0] = SwapInt32(tmp.ul[1]);
result.ul[1] = SwapInt32(tmp.ul[0]);
return result.sv;
#endif
}
*/
inline void
SwapShort(WORD *sp) {
*sp = __SwapUInt16(*sp);
}
inline void
SwapLong(DWORD *lp) {
*lp = __SwapUInt32(*lp);
}
// ==========================================================
// Greyscale and color conversion
// ==========================================================
#define GREY(r, g, b) (BYTE)(((WORD)r * 77 + (WORD)g * 150 + (WORD)b * 29) >> 8) // .299R + .587G + .114B
/*
#define GREY(r, g, b) (BYTE)(((WORD)r * 169 + (WORD)g * 256 + (WORD)b * 87) >> 9) // .33R + 0.5G + .17B
*/
#define RGB565(b, g, r) ((((b) >> 3) << FI16_565_BLUE_SHIFT) | (((g) >> 2) << FI16_565_GREEN_SHIFT) | (((r) >> 3) << FI16_565_RED_SHIFT))
#define RGB555(b, g, r) ((((b) >> 3) << FI16_555_BLUE_SHIFT) | (((g) >> 3) << FI16_555_GREEN_SHIFT) | (((r) >> 3) << FI16_555_RED_SHIFT))
#define FORMAT_RGB565(dib) ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) &&(FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) &&(FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK))
#define RGBQUAD_TO_WORD(dib, color) (FORMAT_RGB565(dib) ? RGB565((color)->rgbBlue, (color)->rgbGreen, (color)->rgbRed) : RGB555((color)->rgbBlue, (color)->rgbGreen, (color)->rgbRed))
#define CREATE_GREYSCALE_PALETTE(palette, entries) \
for (unsigned i = 0, v = 0; i < entries; i++, v += 0x00FFFFFF / (entries - 1)) { \
((unsigned *)palette)[i] = v; \
}
#define CREATE_GREYSCALE_PALETTE_REVERSE(palette, entries) \
for (unsigned i = 0, v = 0x00FFFFFF; i < entries; i++, v -= (0x00FFFFFF / (entries - 1))) { \
((unsigned *)palette)[i] = v; \
}
// ==========================================================
// Template utility functions
// ==========================================================
/// Max function
template <class T> T MAX(T a, T b) {
return (a > b) ? a: b;
}
/// Min function
template <class T> T MIN(T a, T b) {
return (a < b) ? a: b;
}
/// INPLACESWAP adopted from codeguru.com
template <class T> void INPLACESWAP(T& a, T& b) {
a ^= b; b ^= a; a ^= b;
}
/** This procedure computes minimum min and maximum max
of n numbers using only (3n/2) - 2 comparisons.
min = L[i1] and max = L[i2].
ref: Aho A.V., Hopcroft J.E., Ullman J.D.,
The design and analysis of computer algorithms,
Addison-Wesley, Reading, 1974.
*/
template <class T> void
MAXMIN(const T* L, long n, T& max, T& min) {
long i1, i2, i, j;
T x1, x2;
long k1, k2;
i1 = 0; i2 = 0; min = L[0]; max = L[0]; j = 0;
if((n % 2) != 0) j = 1;
for(i = j; i < n; i+= 2) {
k1 = i; k2 = i+1;
x1 = L[k1]; x2 = L[k2];
if(x1 > x2) {
k1 = k2; k2 = i;
x1 = x2; x2 = L[k2];
}
if(x1 < min) {
min = x1; i1 = k1;
}
if(x2 > max) {
max = x2; i2 = k2;
}
}
}
// ==========================================================
// Generic error messages
// ==========================================================
static const char *FI_MSG_ERROR_MEMORY = "Memory allocation failed";
static const char *FI_MSG_ERROR_DIB_MEMORY = "DIB allocation failed";
static const char *FI_MSG_ERROR_PARSING = "Parsing error";
static const char *FI_MSG_ERROR_MAGIC_NUMBER = "Invalid magic number";
static const char *FI_MSG_ERROR_UNSUPPORTED_FORMAT = "Unsupported format";
static const char *FI_MSG_ERROR_UNSUPPORTED_COMPRESSION = "Unsupported compression type";
#endif // UTILITIES_H