summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp')
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp1591
1 files changed, 0 insertions, 1591 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
deleted file mode 100644
index 84864308e0..0000000000
--- a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
+++ /dev/null
@@ -1,1591 +0,0 @@
-// ==========================================================
-// TARGA Loader and Writer
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Jani Kajala (janik@remedy.fi)
-// - Martin Weber (martweb@gmx.net)
-// - Machiel ten Brinke (brinkem@uni-one.nl)
-// - Peter Lemmens (peter.lemmens@planetinternet.be)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
-//
-// 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!
-// ==========================================================
-
-#include "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// Constants + headers
-// ----------------------------------------------------------
-
-#ifdef _WIN32
-#pragma pack(push, 1)
-#else
-#pragma pack(1)
-#endif
-
-typedef struct tagTGAHEADER {
- BYTE id_length; //! length of the image ID field
- BYTE color_map_type; //! whether a color map is included
- BYTE image_type; //! compression and color types
-
- WORD cm_first_entry; //! first entry index (offset into the color map table)
- WORD cm_length; //! color map length (number of entries)
- BYTE cm_size; //! color map entry size, in bits (number of bits per pixel)
-
- WORD is_xorigin; //! X-origin of image (absolute coordinate of lower-left corner for displays where origin is at the lower left)
- WORD is_yorigin; //! Y-origin of image (as for X-origin)
- WORD is_width; //! image width
- WORD is_height; //! image height
- BYTE is_pixel_depth; //! bits per pixel
- BYTE is_image_descriptor; //! image descriptor, bits 3-0 give the alpha channel depth, bits 5-4 give direction
-} TGAHEADER;
-
-typedef struct tagTGAEXTENSIONAREA {
- WORD extension_size; // Size in bytes of the extension area, always 495
- char author_name[41]; // Name of the author. If not used, bytes should be set to NULL (\0) or spaces
- char author_comments[324]; // A comment, organized as four lines, each consisting of 80 characters plus a NULL
- WORD datetime_stamp[6]; // Date and time at which the image was created
- char job_name[41]; // Job ID
- WORD job_time[3]; // Hours, minutes and seconds spent creating the file (for billing, etc.)
- char software_id[41]; // The application that created the file
- BYTE software_version[3];
- DWORD key_color;
- WORD pixel_aspect_ratio[2];
- WORD gamma_value[2];
- DWORD color_correction_offset; // Number of bytes from the beginning of the file to the color correction table if present
- DWORD postage_stamp_offset; // Number of bytes from the beginning of the file to the postage stamp image if present
- DWORD scan_line_offset; // Number of bytes from the beginning of the file to the scan lines table if present
- BYTE attributes_type; // Specifies the alpha channel
-} TGAEXTENSIONAREA;
-
-typedef struct tagTGAFOOTER {
- DWORD extension_offset; // extension area offset : offset in bytes from the beginning of the file
- DWORD developer_offset; // developer directory offset : offset in bytes from the beginning of the file
- char signature[18]; // signature string : contains "TRUEVISION-XFILE.\0"
-} TGAFOOTER;
-
-#ifdef _WIN32
-#pragma pack(pop)
-#else
-#pragma pack()
-#endif
-
-static const char *FI_MSG_ERROR_CORRUPTED = "Image data corrupted";
-
-// ----------------------------------------------------------
-// Image type
-//
-#define TGA_NULL 0 // no image data included
-#define TGA_CMAP 1 // uncompressed, color-mapped image
-#define TGA_RGB 2 // uncompressed, true-color image
-#define TGA_MONO 3 // uncompressed, black-and-white image
-#define TGA_RLECMAP 9 // run-length encoded, color-mapped image
-#define TGA_RLERGB 10 // run-length encoded, true-color image
-#define TGA_RLEMONO 11 // run-length encoded, black-and-white image
-#define TGA_CMPCMAP 32 // compressed (Huffman/Delta/RLE) color-mapped image (e.g., VDA/D) - Obsolete
-#define TGA_CMPCMAP4 33 // compressed (Huffman/Delta/RLE) color-mapped four pass image (e.g., VDA/D) - Obsolete
-
-// ==========================================================
-// Thumbnail functions
-// ==========================================================
-
-class TargaThumbnail
-{
-public:
- TargaThumbnail() : _w(0), _h(0), _depth(0), _data(NULL) {
- }
- ~TargaThumbnail() {
- if(_data) {
- free(_data);
- }
- }
-
- BOOL isNull() const {
- return (_data == NULL);
- }
-
- BOOL read(FreeImageIO *io, fi_handle handle, size_t size) {
- io->read_proc(&_w, 1, 1, handle);
- io->read_proc(&_h, 1, 1, handle);
-
- const size_t sizeofData = size - 2;
- _data = (BYTE*)malloc(sizeofData);
- if(_data) {
- return (io->read_proc(_data, 1, (unsigned)sizeofData, handle) == sizeofData);
- }
- return FALSE;
- }
-
- void setDepth(BYTE dp) {
- _depth = dp;
- }
-
- FIBITMAP* toFIBITMAP();
-
-private:
- BYTE _w;
- BYTE _h;
- BYTE _depth;
- BYTE* _data;
-};
-
-#ifdef FREEIMAGE_BIGENDIAN
-static void
-swapShortPixels(FIBITMAP* dib) {
- if(FreeImage_GetImageType(dib) != FIT_BITMAP) {
- return;
- }
-
- const unsigned Bpp = FreeImage_GetBPP(dib)/8;
- if(Bpp != 2) {
- return;
- }
-
- BYTE* bits = FreeImage_GetBits(dib);
- const unsigned height = FreeImage_GetHeight(dib);
- const unsigned pitch = FreeImage_GetPitch(dib);
-
- BYTE* line = bits;
- for(unsigned y = 0; y < height; y++, line += pitch) {
- for(BYTE* pixel = line; pixel < line + pitch ; pixel += Bpp) {
- SwapShort((WORD*)pixel);
- }
- }
-}
-#endif // FREEIMAGE_BIGENDIAN
-
-FIBITMAP* TargaThumbnail::toFIBITMAP() {
- if(isNull() || _depth == 0) {
- return NULL;
- }
-
- const unsigned line_size = _depth * _w / 8;
- FIBITMAP* dib = FreeImage_Allocate(_w, _h, _depth);
- if(!dib) {
- return NULL;
- }
-
- const BYTE* line = _data;
- const BYTE height = _h;
- for (BYTE h = 0; h < height; ++h, line += line_size) {
- BYTE* dst_line = FreeImage_GetScanLine(dib, height - 1 - h);
- memcpy(dst_line, line, line_size);
- }
-
-#ifdef FREEIMAGE_BIGENDIAN
- swapShortPixels(dib);
-#endif
-
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
- SwapRedBlue32(dib);
-#endif
-
- return dib;
-}
-// ==========================================================
-// Internal functions
-// ==========================================================
-
-/** This class is used when loading RLE compressed images, it implements io cache of fixed size.
- In general RLE compressed images *should* be compressed line by line with line sizes stored in Scan Line Table section.
- In reality, however there are images not obeying the specification, compressing image data continuously across lines,
- making it impossible to load the file cached at every line.
-*/
-class IOCache
-{
-public:
- IOCache(FreeImageIO *io, fi_handle handle, size_t size) :
- _ptr(NULL), _begin(NULL), _end(NULL), _size(size), _io(io), _handle(handle) {
- _begin = (BYTE*)malloc(size);
- if (_begin) {
- _end = _begin + _size;
- _ptr = _end; // will force refill on first access
- }
- }
-
- ~IOCache() {
- if (_begin != NULL) {
- free(_begin);
- }
- }
-
- BOOL isNull() { return _begin == NULL;}
-
- inline
- BYTE getByte() {
- if (_ptr >= _end) {
- // need refill
- _ptr = _begin;
- _io->read_proc(_ptr, sizeof(BYTE), (unsigned)_size, _handle); //### EOF - no problem?
- }
-
- BYTE result = *_ptr;
-
- _ptr++;
-
- return result;
- }
-
- inline
- BYTE* getBytes(size_t count /*must be < _size!*/) {
- if (_ptr + count >= _end) {
-
- // need refill
-
- // 'count' bytes might span two cache bounds,
- // SEEK back to add the remains of the current cache again into the new one
-
- long read = long(_ptr - _begin);
- long remaining = long(_size - read);
-
- _io->seek_proc(_handle, -remaining, SEEK_CUR);
-
- _ptr = _begin;
- _io->read_proc(_ptr, sizeof(BYTE), (unsigned)_size, _handle); //### EOF - no problem?
- }
-
- BYTE *result = _ptr;
-
- _ptr += count;
-
- return result;
- }
-
-private:
- IOCache& operator=(const IOCache& src); // deleted
- IOCache(const IOCache& other); // deleted
-
-private:
- BYTE *_ptr;
- BYTE *_begin;
- BYTE *_end;
- const size_t _size;
- const FreeImageIO *_io;
- const fi_handle _handle;
-};
-
-#ifdef FREEIMAGE_BIGENDIAN
-static void
-SwapHeader(TGAHEADER *header) {
- SwapShort(&header->cm_first_entry);
- SwapShort(&header->cm_length);
- SwapShort(&header->is_xorigin);
- SwapShort(&header->is_yorigin);
- SwapShort(&header->is_width);
- SwapShort(&header->is_height);
-}
-
-static void
-SwapExtensionArea(TGAEXTENSIONAREA *ex) {
- SwapShort(&ex->extension_size);
- SwapShort(&ex->datetime_stamp[0]);
- SwapShort(&ex->datetime_stamp[1]);
- SwapShort(&ex->datetime_stamp[2]);
- SwapShort(&ex->datetime_stamp[3]);
- SwapShort(&ex->datetime_stamp[4]);
- SwapShort(&ex->datetime_stamp[5]);
- SwapShort(&ex->job_time[0]);
- SwapShort(&ex->job_time[1]);
- SwapShort(&ex->job_time[2]);
- SwapLong (&ex->key_color);
- SwapShort(&ex->pixel_aspect_ratio[0]);
- SwapShort(&ex->pixel_aspect_ratio[1]);
- SwapShort(&ex->gamma_value[0]);
- SwapShort(&ex->gamma_value[1]);
- SwapLong (&ex->color_correction_offset);
- SwapLong (&ex->postage_stamp_offset);
- SwapLong (&ex->scan_line_offset);
-}
-
-static void
-SwapFooter(TGAFOOTER *footer) {
- SwapLong(&footer->extension_offset);
- SwapLong(&footer->developer_offset);
-}
-
-#endif // FREEIMAGE_BIGENDIAN
-
-// ==========================================================
-// Plugin Interface
-// ==========================================================
-
-static int s_format_id;
-
-// ==========================================================
-// Plugin Implementation
-// ==========================================================
-
-static const char * DLL_CALLCONV
-Format() {
- return "TARGA";
-}
-
-static const char * DLL_CALLCONV
-Description() {
- return "Truevision Targa";
-}
-
-static const char * DLL_CALLCONV
-Extension() {
- return "tga,targa";
-}
-
-static const char * DLL_CALLCONV
-RegExpr() {
- return NULL;
-}
-
-static const char * DLL_CALLCONV
-MimeType() {
- return "image/x-tga";
-}
-
-static BOOL
-isTARGA20(FreeImageIO *io, fi_handle handle) {
- const unsigned sizeofSig = 18;
- BYTE signature[sizeofSig];
- // tga_signature = "TRUEVISION-XFILE." (TGA 2.0 only)
- BYTE tga_signature[sizeofSig] = { 84, 82, 85, 69, 86, 73, 83, 73, 79, 78, 45, 88, 70, 73, 76, 69, 46, 0 };
- // get the start offset
- const long start_offset = io->tell_proc(handle);
- // get the end-of-file
- io->seek_proc(handle, 0, SEEK_END);
- const long eof = io->tell_proc(handle);
- // read the signature
- io->seek_proc(handle, start_offset + eof - sizeofSig, SEEK_SET);
- io->read_proc(&signature, 1, sizeofSig, handle);
- // rewind
- io->seek_proc(handle, start_offset, SEEK_SET);
-
- return (memcmp(tga_signature, signature, sizeofSig) == 0);
-}
-
-static BOOL DLL_CALLCONV
-Validate(FreeImageIO *io, fi_handle handle) {
- if(isTARGA20(io, handle)) {
- return TRUE;
- }
-
- // not a 2.0 image, try testing if it's a valid TGA anyway (not robust)
- {
- const long start_offset = io->tell_proc(handle);
-
- // get the header
- TGAHEADER header;
- io->read_proc(&header, sizeof(tagTGAHEADER), 1, handle);
-#ifdef FREEIMAGE_BIGENDIAN
- SwapHeader(&header);
-#endif
- // rewind
- io->seek_proc(handle, start_offset, SEEK_SET);
-
- // the color map type should be a 0 or a 1...
- if(header.color_map_type != 0 && header.color_map_type != 1) {
- return FALSE;
- }
- // if the color map type is 1 then we validate the map entry information...
- if(header.color_map_type > 0) {
- // it doesn't make any sense if the first entry is larger than the color map table
- if(header.cm_first_entry >= header.cm_length) {
- return FALSE;
- }
- // check header.cm_size, don't allow 0 or anything bigger than 32
- if(header.cm_size == 0 || header.cm_size > 32) {
- return FALSE;
- }
- }
- // the width/height shouldn't be 0, right ?
- if(header.is_width == 0 || header.is_height == 0) {
- return FALSE;
- }
- // let's now verify all the types that are supported by FreeImage (this is our final verification)
- switch(header.image_type) {
- case TGA_CMAP:
- case TGA_RGB:
- case TGA_MONO:
- case TGA_RLECMAP:
- case TGA_RLERGB:
- case TGA_RLEMONO:
- switch(header.is_pixel_depth) {
- case 8 :
- case 16:
- case 24:
- case 32:
- return TRUE;
- default:
- return FALSE;
- }
- break;
- default:
- return FALSE;
- }
- }
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportDepth(int depth) {
- return (
- (depth == 8) ||
- (depth == 16) ||
- (depth == 24) ||
- (depth == 32)
- );
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportType(FREE_IMAGE_TYPE type) {
- return (type == FIT_BITMAP) ? TRUE : FALSE;
-}
-
-static BOOL DLL_CALLCONV
-SupportsNoPixels() {
- return TRUE;
-}
-
-// ----------------------------------------------------------
-
-/**
-Used for all 32 and 24 bit loading of uncompressed images
-*/
-static void
-loadTrueColor(FIBITMAP* dib, int width, int height, int file_pixel_size, FreeImageIO* io, fi_handle handle, BOOL as24bit) {
- const int pixel_size = as24bit ? 3 : file_pixel_size;
-
- // input line cache
- BYTE* file_line = (BYTE*)malloc( width * file_pixel_size);
-
- if (!file_line) {
- throw FI_MSG_ERROR_MEMORY;
- }
-
- for (int y = 0; y < height; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, y);
- io->read_proc(file_line, file_pixel_size, width, handle);
- BYTE *bgra = file_line;
-
- for (int x = 0; x < width; x++) {
-
- bits[FI_RGBA_BLUE] = bgra[0];
- bits[FI_RGBA_GREEN] = bgra[1];
- bits[FI_RGBA_RED] = bgra[2];
-
- if (!as24bit) {
- bits[FI_RGBA_ALPHA] = bgra[3];
- }
-
- bgra += file_pixel_size;
-
- bits += pixel_size;
- }
- }
-
- free(file_line);
-}
-
-/**
-For the generic RLE loader we need to abstract away the pixel format.
-We use a specific overload based on bits-per-pixel for each type of pixel
-*/
-
-template <int nBITS>
-inline static void
-_assignPixel(BYTE* bits, BYTE* val, BOOL as24bit = FALSE) {
- // static assert should go here
- assert(FALSE);
-}
-
-template <>
-inline void
-_assignPixel<8>(BYTE* bits, BYTE* val, BOOL as24bit) {
- *bits = *val;
-}
-
-template <>
-inline void
-_assignPixel<16>(BYTE* bits, BYTE* val, BOOL as24bit) {
- WORD value(*reinterpret_cast<WORD*>(val));
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapShort(&value);
-#endif
-
- if (as24bit) {
- bits[FI_RGBA_BLUE] = (BYTE)((((value & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
- bits[FI_RGBA_GREEN] = (BYTE)((((value & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
- bits[FI_RGBA_RED] = (BYTE)((((value & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
-
- } else {
- *reinterpret_cast<WORD *>(bits) = 0x7FFF & value;
- }
-}
-
-template <>
-inline void
-_assignPixel<24>(BYTE* bits, BYTE* val, BOOL as24bit) {
- bits[FI_RGBA_BLUE] = val[0];
- bits[FI_RGBA_GREEN] = val[1];
- bits[FI_RGBA_RED] = val[2];
-}
-
-template <>
-inline void
-_assignPixel<32>(BYTE* bits, BYTE* val, BOOL as24bit) {
- if (as24bit) {
- _assignPixel<24>(bits, val, TRUE);
-
- } else {
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- *(reinterpret_cast<unsigned*>(bits)) = *(reinterpret_cast<unsigned*> (val));
-#else // NOTE This is faster then doing reinterpret_cast to int + INPLACESWAP !
- bits[FI_RGBA_BLUE] = val[0];
- bits[FI_RGBA_GREEN] = val[1];
- bits[FI_RGBA_RED] = val[2];
- bits[FI_RGBA_ALPHA] = val[3];
-#endif
- }
-}
-
-/**
-Generic RLE loader
-*/
-template<int bPP>
-static void
-loadRLE(FIBITMAP* dib, int width, int height, FreeImageIO* io, fi_handle handle, long eof, BOOL as24bit) {
- const int file_pixel_size = bPP/8;
- const int pixel_size = as24bit ? 3 : file_pixel_size;
-
- const BYTE bpp = as24bit ? 24 : bPP;
- const int line_size = CalculateLine(width, bpp);
-
- // Note, many of the params can be computed inside the function.
- // However, because this is a template function, it will lead to redundant code duplication.
-
- BYTE rle;
- BYTE *line_bits;
-
- // this is used to guard against writing beyond the end of the image (on corrupted rle block)
- const BYTE* dib_end = FreeImage_GetScanLine(dib, height);//< one-past-end row
-
- // Compute the rough size of a line...
- long pixels_offset = io->tell_proc(handle);
- long sz = ((eof - pixels_offset) / height);
-
- // ...and allocate cache of this size (yields good results)
- IOCache cache(io, handle, sz);
- if(cache.isNull()) {
- FreeImage_Unload(dib);
- dib = NULL;
- return;
- }
-
- int x = 0, y = 0;
-
- line_bits = FreeImage_GetScanLine(dib, y);
-
- while (y < height) {
-
- rle = cache.getByte();
-
- BOOL has_rle = rle & 0x80;
- rle &= ~0x80; // remove type-bit
-
- BYTE packet_count = rle + 1;
-
- //packet_count might be corrupt, test if we are not about to write beyond the last image bit
-
- if ((line_bits+x) + packet_count*pixel_size > dib_end) {
- FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_CORRUPTED);
- // return what is left from the bitmap
- return;
- }
-
- if (has_rle) {
-
- // read a pixel value from file...
- BYTE *val = cache.getBytes(file_pixel_size);
-
- //...and fill packet_count pixels with it
-
- for (int ix = 0; ix < packet_count; ix++) {
- _assignPixel<bPP>((line_bits+x), val, as24bit);
- x += pixel_size;
-
- if (x >= line_size) {
- x = 0;
- y++;
- line_bits = FreeImage_GetScanLine(dib, y);
- }
- }
-
- } else {
- // no rle commpresion
-
- // copy packet_count pixels from file to dib
- for (int ix = 0; ix < packet_count; ix++) {
- BYTE *val = cache.getBytes(file_pixel_size);
- _assignPixel<bPP>((line_bits+x), val, as24bit);
- x += pixel_size;
-
- if (x >= line_size) {
- x = 0;
- y++;
- line_bits = FreeImage_GetScanLine(dib, y);
- }
- } //< packet_count
- } //< has_rle
-
- } //< while height
-
-}
-
-// --------------------------------------------------------------------------
-
-static FIBITMAP * DLL_CALLCONV
-Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
- FIBITMAP *dib = NULL;
-
- if (!handle) {
- return NULL;
- }
-
- try {
-
- const BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
-
- // remember the start offset
- long start_offset = io->tell_proc(handle);
-
- // remember end-of-file (used for RLE cache)
- io->seek_proc(handle, 0, SEEK_END);
- long eof = io->tell_proc(handle);
- io->seek_proc(handle, start_offset, SEEK_SET);
-
- // read and process the bitmap's footer
-
- TargaThumbnail thumbnail;
- if(isTARGA20(io, handle)) {
- TGAFOOTER footer;
- const long footer_offset = start_offset + eof - sizeof(footer);
-
- io->seek_proc(handle, footer_offset, SEEK_SET);
- io->read_proc(&footer, sizeof(tagTGAFOOTER), 1, handle);
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapFooter(&footer);
-#endif
- BOOL hasExtensionArea = footer.extension_offset > 0;
- if(hasExtensionArea) {
- TGAEXTENSIONAREA extensionarea;
- io->seek_proc(handle, footer.extension_offset, SEEK_SET);
- io->read_proc(&extensionarea, sizeof(extensionarea), 1, handle);
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapExtensionArea(&extensionarea);
-#endif
-
- DWORD postage_stamp_offset = extensionarea.postage_stamp_offset;
- BOOL hasThumbnail = (postage_stamp_offset > 0) && (postage_stamp_offset < (DWORD)footer_offset);
- if(hasThumbnail) {
- io->seek_proc(handle, postage_stamp_offset, SEEK_SET);
- thumbnail.read(io, handle, footer_offset - postage_stamp_offset);
- }
- }
- }
-
- // read and process the bitmap's header
-
- TGAHEADER header;
-
- io->seek_proc(handle, start_offset, SEEK_SET);
- io->read_proc(&header, sizeof(tagTGAHEADER), 1, handle);
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapHeader(&header);
-#endif
-
- thumbnail.setDepth(header.is_pixel_depth);
-
- const int line = CalculateLine(header.is_width, header.is_pixel_depth);
- const int pixel_bits = header.is_pixel_depth;
- const int pixel_size = pixel_bits/8;
-
- int fliphoriz = (header.is_image_descriptor & 0x10) ? 1 : 0;
- int flipvert = (header.is_image_descriptor & 0x20) ? 1 : 0;
-
- // skip comment
- io->seek_proc(handle, header.id_length, SEEK_CUR);
-
- switch (header.is_pixel_depth) {
- case 8 : {
- dib = FreeImage_AllocateHeader(header_only, header.is_width, header.is_height, 8);
-
- if (dib == NULL) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
-
- // read the palette (even if header only)
-
- RGBQUAD *palette = FreeImage_GetPalette(dib);
-
- if (header.color_map_type > 0) {
- unsigned count, csize;
-
- // calculate the color map size
- csize = header.cm_length * header.cm_size / 8;
-
- // read the color map
- BYTE *cmap = (BYTE*)malloc(csize * sizeof(BYTE));
- if (cmap == NULL) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
- io->read_proc(cmap, sizeof(BYTE), csize, handle);
-
- // build the palette
-
- switch (header.cm_size) {
- case 16: {
- WORD *rgb555 = (WORD*)&cmap[0];
- unsigned start = (unsigned)header.cm_first_entry;
- unsigned stop = MIN((unsigned)256, (unsigned)header.cm_length);
-
- for (count = start; count < stop; count++) {
- palette[count].rgbRed = (BYTE)((((*rgb555 & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
- palette[count].rgbGreen = (BYTE)((((*rgb555 & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
- palette[count].rgbBlue = (BYTE)((((*rgb555 & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
- rgb555++;
- }
- }
- break;
-
- case 24: {
- FILE_BGR *bgr = (FILE_BGR*)&cmap[0];
- unsigned start = (unsigned)header.cm_first_entry;
- unsigned stop = MIN((unsigned)256, (unsigned)header.cm_length);
-
- for (count = start; count < stop; count++) {
- palette[count].rgbBlue = bgr->b;
- palette[count].rgbGreen = bgr->g;
- palette[count].rgbRed = bgr->r;
- bgr++;
- }
- }
- break;
-
- case 32: {
- BYTE trns[256];
-
- // clear the transparency table
- memset(trns, 0xFF, 256);
-
- FILE_BGRA *bgra = (FILE_BGRA*)&cmap[0];
- unsigned start = (unsigned)header.cm_first_entry;
- unsigned stop = MIN((unsigned)256, (unsigned)header.cm_length);
-
- for (count = start; count < stop; count++) {
- palette[count].rgbBlue = bgra->b;
- palette[count].rgbGreen = bgra->g;
- palette[count].rgbRed = bgra->r;
- // alpha
- trns[count] = bgra->a;
- bgra++;
- }
-
- // set the tranparency table
- FreeImage_SetTransparencyTable(dib, trns, 256);
- }
- break;
-
- } // switch(header.cm_size)
-
- free(cmap);
- }
-
- // handle thumbnail
-
- FIBITMAP* th = thumbnail.toFIBITMAP();
- if(th) {
- RGBQUAD* pal = FreeImage_GetPalette(dib);
- RGBQUAD* dst_pal = FreeImage_GetPalette(th);
- if(dst_pal && pal) {
- for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) {
- dst_pal[i] = pal[i];
- }
- }
-
- FreeImage_SetTransparencyTable(th, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
-
- FreeImage_SetThumbnail(dib, th);
- FreeImage_Unload(th);
- }
-
- if(header_only) {
- return dib;
- }
-
- // read in the bitmap bits
-
- switch (header.image_type) {
- case TGA_CMAP:
- case TGA_MONO: {
- BYTE *bits = NULL;
-
- for (unsigned count = 0; count < header.is_height; count++) {
- bits = FreeImage_GetScanLine(dib, count);
- io->read_proc(bits, sizeof(BYTE), line, handle);
- }
- }
- break;
-
- case TGA_RLECMAP:
- case TGA_RLEMONO: { //(8 bit)
- loadRLE<8>(dib, header.is_width, header.is_height, io, handle, eof, FALSE);
- }
- break;
-
- default :
- FreeImage_Unload(dib);
- return NULL;
- }
- }
- break; // header.is_pixel_depth == 8
-
- case 15 :
-
- case 16 : {
- int pixel_bits = 16;
-
- // allocate the dib
-
- if (TARGA_LOAD_RGB888 & flags) {
- pixel_bits = 24;
- dib = FreeImage_AllocateHeader(header_only, header.is_width, header.is_height, pixel_bits, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
-
- } else {
- dib = FreeImage_AllocateHeader(header_only, header.is_width, header.is_height, pixel_bits, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
- }
-
- if (dib == NULL) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
-
- // handle thumbnail
-
- FIBITMAP* th = thumbnail.toFIBITMAP();
- if(th) {
- if(TARGA_LOAD_RGB888 & flags) {
- FIBITMAP* t = FreeImage_ConvertTo24Bits(th);
- FreeImage_Unload(th);
- th = t;
- }
-
- FreeImage_SetThumbnail(dib, th);
- FreeImage_Unload(th);
- }
-
- if(header_only) {
- return dib;
- }
-
- int line = CalculateLine(header.is_width, pixel_bits);
-
- const unsigned pixel_size = unsigned(pixel_bits) / 8;
- const unsigned src_pixel_size = sizeof(WORD);
-
- // note header.cm_size is a misleading name, it should be seen as header.cm_bits
- // ignore current position in file and set filepointer explicitly from the beginning of the file
-
- int garblen = 0;
-
- if (header.color_map_type != 0) {
- garblen = (int)((header.cm_size + 7) / 8) * header.cm_length; /* should byte align */
-
- } else {
- garblen = 0;
- }
-
- io->seek_proc(handle, start_offset, SEEK_SET);
- io->seek_proc(handle, sizeof(tagTGAHEADER) + header.id_length + garblen, SEEK_SET);
-
- // read in the bitmap bits
-
- switch (header.image_type) {
- case TGA_RGB: { //(16 bit)
- // input line cache
- BYTE *in_line = (BYTE*)malloc(header.is_width * sizeof(WORD));
-
- if (!in_line)
- throw FI_MSG_ERROR_MEMORY;
-
- const int h = header.is_height;
-
- for (int y = 0; y < h; y++) {
-
- BYTE *bits = FreeImage_GetScanLine(dib, y);
- io->read_proc(in_line, src_pixel_size, header.is_width, handle);
-
- BYTE *val = in_line;
- for (int x = 0; x < line; x += pixel_size) {
-
- _assignPixel<16>(bits+x, val, TARGA_LOAD_RGB888 & flags);
-
- val += src_pixel_size;
- }
- }
-
- free(in_line);
- }
- break;
-
- case TGA_RLERGB: { //(16 bit)
- loadRLE<16>(dib, header.is_width, header.is_height, io, handle, eof, TARGA_LOAD_RGB888 & flags);
- }
- break;
-
- default :
- FreeImage_Unload(dib);
- return NULL;
- }
- }
- break; // header.is_pixel_depth == 15 or 16
-
- case 24 : {
-
- dib = FreeImage_AllocateHeader(header_only, header.is_width, header.is_height, pixel_bits, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
-
- if (dib == NULL) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
-
- FIBITMAP* th = thumbnail.toFIBITMAP();
- if(th) {
- FreeImage_SetThumbnail(dib, th);
- FreeImage_Unload(th);
- }
-
- if(header_only) {
- return dib;
- }
-
- // read in the bitmap bits
-
- switch (header.image_type) {
- case TGA_RGB: { //(24 bit)
- //uncompressed
- loadTrueColor(dib, header.is_width, header.is_height, pixel_size,io, handle, TRUE);
- }
- break;
-
- case TGA_RLERGB: { //(24 bit)
- loadRLE<24>(dib, header.is_width, header.is_height, io, handle, eof, TRUE);
- }
- break;
-
- default :
- FreeImage_Unload(dib);
- return NULL;
- }
- }
- break; // header.is_pixel_depth == 24
-
- case 32 : {
- int pixel_bits = 32;
-
- if (TARGA_LOAD_RGB888 & flags) {
- pixel_bits = 24;
- }
-
- dib = FreeImage_AllocateHeader(header_only, header.is_width, header.is_height, pixel_bits, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
-
- if (dib == NULL) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
-
- // handle thumbnail
-
- FIBITMAP* th = thumbnail.toFIBITMAP();
- if(th) {
- if(TARGA_LOAD_RGB888 & flags) {
- FIBITMAP* t = FreeImage_ConvertTo24Bits(th);
- FreeImage_Unload(th);
- th = t;
- }
- FreeImage_SetThumbnail(dib, th);
- FreeImage_Unload(th);
- }
-
- if(header_only) {
- return dib;
- }
-
- // read in the bitmap bits
-
- switch (header.image_type) {
- case TGA_RGB: { //(32 bit)
- // uncompressed
- loadTrueColor(dib, header.is_width, header.is_height, 4 /*file_pixel_size*/, io, handle, TARGA_LOAD_RGB888 & flags);
- }
- break;
-
- case TGA_RLERGB: { //(32 bit)
- loadRLE<32>(dib, header.is_width, header.is_height, io, handle, eof, TARGA_LOAD_RGB888 & flags);
- }
- break;
-
- default :
- FreeImage_Unload(dib);
- return NULL;
- }
- }
- break; // header.is_pixel_depth == 32
-
- } // switch(header.is_pixel_depth)
-
- if (flipvert) {
- FreeImage_FlipVertical(dib);
- }
-
- if (fliphoriz) {
- FreeImage_FlipHorizontal(dib);
- }
-
- return dib;
-
- } catch (const char *message) {
- if (dib) {
- FreeImage_Unload(dib);
- }
-
- FreeImage_OutputMessageProc(s_format_id, message);
-
- return NULL;
- }
-}
-
-// --------------------------------------------------------------------------
-
-static BOOL
-hasValidThumbnail(FIBITMAP* dib) {
- FIBITMAP* thumbnail = FreeImage_GetThumbnail(dib);
-
- return thumbnail
- && SupportsExportType(FreeImage_GetImageType(thumbnail))
- && SupportsExportDepth(FreeImage_GetBPP(thumbnail))
- // Requirements according to the specification:
- && FreeImage_GetBPP(thumbnail) == FreeImage_GetBPP(dib)
- && FreeImage_GetImageType(thumbnail) == FreeImage_GetImageType(dib)
- && FreeImage_GetWidth(thumbnail) <= 255
- && FreeImage_GetHeight(thumbnail) <= 255;
-}
-
-/**
-Writes the ready RLE packet to buffer
-*/
-static inline void
-flushPacket(BYTE*& dest, unsigned pixel_size, BYTE* packet_begin, BYTE*& packet, BYTE& packet_count, BOOL& has_rle) {
- if (packet_count) {
- const BYTE type_bit = has_rle ? 0x80 : 0x0;
- const BYTE write_count = has_rle ? 1 : packet_count;
-
- // build packet header: zero-based count + type bit
- assert(packet_count >= 1);
- BYTE rle = packet_count - 1;
- rle |= type_bit;
-
- // write packet header
- *dest = rle;
- ++dest;
-
- // write packet data
- memcpy(dest, packet_begin, write_count * pixel_size);
- dest += write_count * pixel_size;
-
- // reset state
- packet_count = 0;
- packet = packet_begin;
- has_rle = FALSE;
- }
-}
-
-
-static inline void
-writeToPacket(BYTE* packet, BYTE* pixel, unsigned pixel_size) {
- // Take care of channel and byte order here, because packet will be flushed straight to the file
- switch (pixel_size) {
- case 1:
- *packet = *pixel;
- break;
-
- case 2: {
- WORD val(*(WORD*)pixel);
-#ifdef FREEIMAGE_BIGENDIAN
- SwapShort(&val);
-#endif
- *(WORD*)packet = val;
- }
- break;
-
- case 3: {
- packet[0] = pixel[FI_RGBA_BLUE];
- packet[1] = pixel[FI_RGBA_GREEN];
- packet[2] = pixel[FI_RGBA_RED];
- }
- break;
-
- case 4: {
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- *(reinterpret_cast<unsigned*>(packet)) = *(reinterpret_cast<unsigned*> (pixel));
-#else
- packet[0] = pixel[FI_RGBA_BLUE];
- packet[1] = pixel[FI_RGBA_GREEN];
- packet[2] = pixel[FI_RGBA_RED];
- packet[3] = pixel[FI_RGBA_ALPHA];
-#endif
- }
- break;
-
- default:
- assert(FALSE);
- }
-}
-
-static inline BOOL
-isEqualPixel(BYTE* lhs, BYTE* rhs, unsigned pixel_size) {
- switch (pixel_size) {
- case 1:
- return *lhs == *rhs;
-
- case 2:
- return *(WORD*)lhs == *(WORD*)rhs;
-
- case 3:
- return *(WORD*)lhs == *(WORD*)rhs && lhs[2] == rhs[2];
-
- case 4:
- return *(unsigned*)lhs == *(unsigned*)rhs;
-
- default:
- assert(FALSE);
- return FALSE;
- }
-}
-
-static void
-saveRLE(FIBITMAP* dib, FreeImageIO* io, fi_handle handle) {
- // Image is compressed line by line, packets don't span multiple lines (TGA2.0 recommendation)
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
- const unsigned pixel_size = FreeImage_GetBPP(dib)/8;
- const unsigned line_size = FreeImage_GetLine(dib);
-
- const BYTE max_packet_size = 128;
- BYTE packet_count = 0;
- BOOL has_rle = FALSE;
-
- // packet (compressed or not) to be written to line
-
- BYTE* const packet_begin = (BYTE*)malloc(max_packet_size * pixel_size);
- BYTE* packet = packet_begin;
-
- // line to be written to disk
- // Note: we need some extra bytes for anti-commpressed lines. The worst case is:
- // 8 bit images were every 3th pixel is different.
- // Rle packet becomes two pixels, but nothing is compressed: two byte pixels are transformed into byte header and byte pixel value
- // After every rle packet there is a non-rle packet of one pixel: an extra byte for the header will be added for it
- // In the end we gain no bytes from compression, but also must insert a byte at every 3th pixel
-
- // add extra space for anti-commpressed lines
- size_t extra_space = (size_t)ceil(width / 3.0);
- BYTE* const line_begin = (BYTE*)malloc(width * pixel_size + extra_space);
- BYTE* line = line_begin;
-
- BYTE *current = (BYTE*)malloc(pixel_size);
- BYTE *next = (BYTE*)malloc(pixel_size);
-
- for(unsigned y = 0; y < height; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, y);
-
- // rewind line pointer
- line = line_begin;
-
- for(unsigned x = 0; x < line_size; x += pixel_size) {
-
- AssignPixel(current, (bits + x), pixel_size);
-
- // read next pixel from dib
-
- if( x + 1*pixel_size < line_size) {
- AssignPixel(next, (bits + x + 1*pixel_size), pixel_size);
-
- } else {
- // last pixel in line
-
- // include current pixel and flush
- if(!has_rle) {
-
- writeToPacket(packet, current, pixel_size);
- packet += pixel_size;
-
- }
-
- assert(packet_count < max_packet_size);
-
- ++packet_count;
-
- flushPacket(line, pixel_size, packet_begin, packet, packet_count, has_rle);
-
- // start anew on next line
- break;
- }
-
- if(isEqualPixel(current, next, pixel_size)) {
-
- // has rle
-
- if(!has_rle) {
- // flush non rle packet
-
- flushPacket(line, pixel_size, packet_begin, packet, packet_count, has_rle);
-
- // start a rle packet
-
- has_rle = TRUE;
-
- writeToPacket(packet, current, pixel_size);
- packet += pixel_size;
- }
-
- // otherwise do nothing. We will just increase the count at the end
-
- } else {
-
- // no rle
-
- if(has_rle) {
- // flush rle packet
-
- // include current pixel first
- assert(packet_count < max_packet_size);
- ++packet_count;
-
- flushPacket(line, pixel_size, packet_begin, packet, packet_count, has_rle);
-
- // start anew on the next pixel
- continue;
-
- } else {
-
- writeToPacket(packet, current, pixel_size);
- packet += pixel_size;
- }
-
- }
-
- // increase counter on every pixel
-
- ++packet_count;
-
- if(packet_count == max_packet_size) {
- flushPacket(line, pixel_size, packet_begin, packet, packet_count, has_rle);
- }
-
- }//for width
-
- // write line to disk
- io->write_proc(line_begin, 1, (unsigned)(line - line_begin), handle);
-
- }//for height
-
- free(line_begin);
- free(packet_begin);
- free(current);
- free(next);
-}
-
-static BOOL DLL_CALLCONV
-Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
- if ((dib == NULL) || (handle == NULL)) {
- return FALSE;
- }
-
- RGBQUAD *palette = FreeImage_GetPalette(dib);
- const unsigned bpp = FreeImage_GetBPP(dib);
-
- // write the file header
-
- TGAHEADER header;
-
- header.id_length = 0;
- header.cm_first_entry = 0;
- header.is_xorigin = 0;
- header.is_yorigin = 0;
- header.is_width = (WORD)FreeImage_GetWidth(dib);
- header.is_height = (WORD)FreeImage_GetHeight(dib);
- header.is_pixel_depth = (BYTE)bpp;
- header.is_image_descriptor = (bpp == 32 ? 8 : 0);
-
- if (palette) {
- header.color_map_type = 1;
- header.image_type = (TARGA_SAVE_RLE & flags) ? TGA_RLECMAP : TGA_CMAP;
- header.cm_length = (WORD)(1 << bpp);
-
- if (FreeImage_IsTransparent(dib)) {
- header.cm_size = 32;
- } else {
- header.cm_size = 24;
- }
-
- } else {
- header.color_map_type = 0;
- header.image_type = (TARGA_SAVE_RLE & flags) ? TGA_RLERGB : TGA_RGB;
- header.cm_length = 0;
- header.cm_size = 0;
- }
-
- // write the header
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapHeader(&header);
-#endif
-
- io->write_proc(&header, sizeof(header), 1, handle);
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapHeader(&header);
-#endif
-
- // write the palette
-
- if (palette) {
- if (FreeImage_IsTransparent(dib)) {
- FILE_BGRA *bgra_pal = (FILE_BGRA*)malloc(header.cm_length * sizeof(FILE_BGRA));
-
- // get the transparency table
- BYTE *trns = FreeImage_GetTransparencyTable(dib);
-
- for (unsigned i = 0; i < header.cm_length; i++) {
- bgra_pal[i].b = palette[i].rgbBlue;
- bgra_pal[i].g = palette[i].rgbGreen;
- bgra_pal[i].r = palette[i].rgbRed;
- bgra_pal[i].a = trns[i];
- }
-
- io->write_proc(bgra_pal, sizeof(FILE_BGRA), header.cm_length, handle);
-
- free(bgra_pal);
-
- } else {
- FILE_BGR *bgr_pal = (FILE_BGR*)malloc(header.cm_length * sizeof(FILE_BGR));
-
- for (unsigned i = 0; i < header.cm_length; i++) {
- bgr_pal[i].b = palette[i].rgbBlue;
- bgr_pal[i].g = palette[i].rgbGreen;
- bgr_pal[i].r = palette[i].rgbRed;
- }
-
- io->write_proc(bgr_pal, sizeof(FILE_BGR), header.cm_length, handle);
-
- free(bgr_pal);
- }
- }
-
- // write the data bits
-
-
- if (TARGA_SAVE_RLE & flags) {
-
- saveRLE(dib, io, handle);
-
- } else {
-
- // -- no rle compression --
-
- const unsigned width = header.is_width;
- const unsigned height = header.is_height;
- const unsigned pixel_size = bpp/8;
-
- BYTE *line, *const line_begin = (BYTE*)malloc(width * pixel_size);
- BYTE *line_source = line_begin;
-
- for (unsigned y = 0; y < height; y++) {
- BYTE *scanline = FreeImage_GetScanLine(dib, y);
-
- // rewind the line pointer
- line = line_begin;
-
- switch (bpp) {
- case 8: {
- // don't copy line, read straight from dib
- line_source = scanline;
- }
- break;
-
- case 16: {
- for (unsigned x = 0; x < width; x++) {
- WORD pixel = *(((WORD *)scanline) + x);
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapShort(&pixel);
-#endif
- *(WORD*)line = pixel;
-
- line += pixel_size;
- }
- }
- break;
-
- case 24: {
-
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- line_source = scanline;
-#else
- for (unsigned x = 0; x < width; ++x) {
- RGBTRIPLE* trip = ((RGBTRIPLE *)scanline) + x;
- line[0] = trip->rgbtBlue;
- line[1] = trip->rgbtGreen;
- line[2] = trip->rgbtRed;
-
- line += pixel_size;
- }
-#endif
- }
- break;
-
- case 32: {
-
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- line_source = scanline;
-#else
- for (unsigned x = 0; x < width; ++x) {
- RGBQUAD* quad = ((RGBQUAD *)scanline) + x;
- line[0] = quad->rgbBlue;
- line[1] = quad->rgbGreen;
- line[2] = quad->rgbRed;
- line[3] = quad->rgbReserved;
-
- line += pixel_size;
- }
-#endif
- }
- break;
-
- }//switch(bpp)
-
- // write line to disk
-
- io->write_proc(line_source, pixel_size, width, handle);
-
- }//for height
-
- free(line_begin);
- }
-
-
- long extension_offset = 0 ;
- if(hasValidThumbnail(dib)) {
- // write extension area
-
- extension_offset = io->tell_proc(handle);
-
- TGAEXTENSIONAREA ex;
- memset(&ex, 0, sizeof(ex));
-
- assert(sizeof(ex) == 495);
- ex.extension_size = sizeof(ex);
- ex.postage_stamp_offset = extension_offset + ex.extension_size + 0 /*< no Scan Line Table*/;
- ex.attributes_type = FreeImage_GetBPP(dib) == 32 ? 3 /*< useful Alpha channel data*/ : 0 /*< no Alpha data*/;
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapExtensionArea(&ex);
-#endif
-
- io->write_proc(&ex, sizeof(ex), 1, handle);
-
- // (no Scan Line Table)
-
- // write thumbnail
-
- io->seek_proc(handle, ex.postage_stamp_offset, SEEK_SET);
-
- FIBITMAP* thumbnail = FreeImage_GetThumbnail(dib);
- BYTE width = (BYTE)FreeImage_GetWidth(thumbnail);
- BYTE height = (BYTE)FreeImage_GetHeight(thumbnail);
-
- io->write_proc(&width, 1, 1, handle);
- io->write_proc(&height, 1, 1, handle);
-
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
- SwapRedBlue32(dib);
-#endif
-
-#ifdef FREEIMAGE_BIGENDIAN
- swapShortPixels(dib);
-#endif
-
- const unsigned line_size = FreeImage_GetLine(thumbnail);
-
- for (BYTE h = 0; h < height; ++h) {
- BYTE* src_line = FreeImage_GetScanLine(thumbnail, height - 1 - h);
- io->write_proc(src_line, 1, line_size, handle);
- }
- }
-
- // (no Color Correction Table)
-
- // write the footer
-
- TGAFOOTER footer;
- footer.extension_offset = extension_offset;
- footer.developer_offset = 0;
- strcpy(footer.signature, "TRUEVISION-XFILE.");
-
-
-#ifdef FREEIMAGE_BIGENDIAN
- SwapFooter(&footer);
-#endif
-
- io->write_proc(&footer, sizeof(footer), 1, handle);
-
- return TRUE;
-}
-
-// ==========================================================
-// Init
-// ==========================================================
-
-void DLL_CALLCONV
-InitTARGA(Plugin *plugin, int format_id) {
- s_format_id = format_id;
-
- plugin->format_proc = Format;
- plugin->description_proc = Description;
- plugin->extension_proc = Extension;
- plugin->regexpr_proc = RegExpr;
- plugin->open_proc = NULL;
- plugin->close_proc = NULL;
- plugin->pagecount_proc = NULL;
- plugin->pagecapability_proc = NULL;
- plugin->load_proc = Load;
- plugin->save_proc = Save;
- plugin->validate_proc = Validate;
- plugin->mime_proc = MimeType;
- plugin->supports_export_bpp_proc = SupportsExportDepth;
- plugin->supports_export_type_proc = SupportsExportType;
- plugin->supports_icc_profiles_proc = NULL;
- plugin->supports_no_pixels_proc = SupportsNoPixels;
-}