summaryrefslogtreecommitdiff
path: root/im/src/im_filebuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'im/src/im_filebuffer.cpp')
-rwxr-xr-xim/src/im_filebuffer.cpp695
1 files changed, 695 insertions, 0 deletions
diff --git a/im/src/im_filebuffer.cpp b/im/src/im_filebuffer.cpp
new file mode 100755
index 0000000..09c5ad4
--- /dev/null
+++ b/im/src/im_filebuffer.cpp
@@ -0,0 +1,695 @@
+/** \file
+ * \brief File Access - Buffer Management
+ *
+ * See Copyright Notice in im_lib.h
+ * $Id: im_filebuffer.cpp,v 1.2 2009/08/13 22:34:25 scuri Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "im.h"
+#include "im_format.h"
+#include "im_util.h"
+#include "im_complex.h"
+#include "im_color.h"
+
+
+int imFileLineSizeAligned(int width, int bpp, int align)
+{
+ if (align == 4)
+ return ((width * bpp + 31) / 32) * 4;
+ else if (align == 2)
+ return ((width * bpp + 15) / 16) * 2;
+ else
+ return (width * bpp + 7) / 8;
+}
+
+template <class T>
+static void iDoFillLineBuffer(int width, int height, int line, int plane,
+ int file_color_mode, T* line_buffer,
+ int user_color_mode, const T* data)
+{
+ // (writing) from data to file
+ // will handle packing and alpha
+
+ int file_depth = imColorModeDepth(file_color_mode);
+ int data_depth = imColorModeDepth(user_color_mode);
+ int data_plane_size = width*height; // This will be used in UNpacked data
+
+ if (imColorModeIsPacked(user_color_mode))
+ data += line*width*data_depth;
+ else
+ data += line*width;
+
+ for (int x = 0; x < width; x++)
+ {
+ int x_data_offset = x*data_depth; // This will be used in packed data
+
+ if (imColorModeIsPacked(file_color_mode))
+ {
+ int x_file_offset = x*file_depth; // This will be used in packed data
+
+ // file is packed
+ // NO color space conversion, color_space must match
+ // Ignore alpha if necessary.
+ int depth = IM_MIN(file_depth, data_depth);
+ for (int d = 0; d < depth; d++)
+ {
+ if (imColorModeIsPacked(user_color_mode))
+ line_buffer[x_file_offset + d] = data[x_data_offset + d];
+ else
+ line_buffer[x_file_offset + d] = data[d*data_plane_size + x];
+ }
+ }
+ else
+ {
+ // file NOT packed, copy just one plane
+ // NO color space conversion, color_space must match
+
+ if (plane >= imColorModeDepth(user_color_mode))
+ return;
+
+ if (imColorModeIsPacked(user_color_mode))
+ line_buffer[x] = data[x_data_offset + plane];
+ else
+ line_buffer[x] = data[plane*data_plane_size + x];
+ }
+ }
+}
+
+template <class T>
+static void iDoFillData(int width, int height, int line, int plane,
+ int file_color_mode, const T* line_buffer,
+ int user_color_mode, T* data)
+{
+ // (reading) from file to data
+ // will handle packing and alpha
+
+ int file_depth = imColorModeDepth(file_color_mode);
+ int data_depth = imColorModeDepth(user_color_mode);
+ int data_plane_size = width*height; // This will be used in UNpacked data
+
+ if (imColorModeIsPacked(user_color_mode))
+ data += line*width*data_depth;
+ else
+ data += line*width;
+
+ for (int x = 0; x < width; x++)
+ {
+ int x_data_offset = x*data_depth; // This will be used in packed data
+
+ if (imColorModeIsPacked(file_color_mode))
+ {
+ int x_file_offset = x*file_depth; // This will be used in packed data
+
+ // file is packed
+ // NO color space conversion, color_space must match
+ // ignore alpha if necessary.
+ int depth = IM_MIN(file_depth, data_depth);
+ for (int d = 0; d < depth; d++)
+ {
+ if (imColorModeIsPacked(user_color_mode))
+ data[x_data_offset + d] = line_buffer[x_file_offset + d];
+ else
+ data[d*data_plane_size + x] = line_buffer[x_file_offset + d];
+ }
+ }
+ else
+ {
+ // file NOT packed, copy just one plane
+ // NO color space conversion, color_space must match
+
+ if (plane >= imColorModeDepth(user_color_mode))
+ return;
+
+ if (imColorModeIsPacked(user_color_mode))
+ data[x_data_offset + plane] = line_buffer[x];
+ else
+ data[plane*data_plane_size + x] = line_buffer[x];
+ }
+ }
+}
+
+template <class T>
+static inline void iConvertColor2RGB(T* data, int color_space, int data_type)
+{
+ T zero, max = (T)imColorMax(data_type);
+
+ // These are identical procedures to iDoConvert2RGB in "im_filebuffer.cpp".
+
+ switch (color_space)
+ {
+ case IM_XYZ:
+ {
+ // to increase precision do intermediate conversions in float
+
+ // scale to 0-1
+ float c0 = imColorReconstruct(data[0], max);
+ float c1 = imColorReconstruct(data[1], max);
+ float c2 = imColorReconstruct(data[2], max);
+
+ // result is still 0-1
+ imColorXYZ2RGB(c0, c1, c2,
+ c0, c1, c2, 1.0f);
+
+ // do gamma correction then scale back to 0-max
+ data[0] = imColorQuantize(imColorTransfer2Nonlinear(c0), max);
+ data[1] = imColorQuantize(imColorTransfer2Nonlinear(c1), max);
+ data[2] = imColorQuantize(imColorTransfer2Nonlinear(c2), max);
+ }
+ break;
+ case IM_YCBCR:
+ zero = (T)imColorZero(data_type);
+ imColorYCbCr2RGB(data[0], data[1], data[2],
+ data[0], data[1], data[2], zero, max);
+ break;
+ case IM_CMYK:
+ imColorCMYK2RGB(data[0], data[1], data[2], data[3],
+ data[0], data[1], data[2], max);
+ break;
+ case IM_LUV:
+ case IM_LAB:
+ {
+ // to increase precision do intermediate conversions in float
+ // scale to 0-1 and -0.5/+0.5
+ float c0 = imColorReconstruct(data[0], max);
+ float c1 = imColorReconstruct(data[1], max) - 0.5f;
+ float c2 = imColorReconstruct(data[2], max) - 0.5f;
+
+ if (color_space == IM_LUV)
+ imColorLuv2XYZ(c0, c1, c2, // conversion in-place
+ c0, c1, c2);
+ else
+ imColorLab2XYZ(c0, c1, c2, // conversion in-place
+ c0, c1, c2);
+
+ imColorXYZ2RGB(c0, c1, c2, // conversion in-place
+ c0, c1, c2, 1.0f);
+
+ // do gamma correction then scale back to 0-max
+ data[0] = imColorQuantize(imColorTransfer2Nonlinear(c0), max);
+ data[1] = imColorQuantize(imColorTransfer2Nonlinear(c1), max);
+ data[2] = imColorQuantize(imColorTransfer2Nonlinear(c2), max);
+ }
+ break;
+ }
+}
+
+// These functions will be always converting RGB -> RGB (0-max) -> (0-255)
+
+static inline imbyte iConvertType2Byte(const imbyte& data)
+ { return data; }
+
+static inline imbyte iConvertType2Byte(const imushort& data)
+ { return imColorQuantize(imColorReconstruct(data, (imushort)65535), (imbyte)255); }
+
+static inline imbyte iConvertType2Byte(const int& data)
+ { return imColorQuantize(imColorReconstruct(data, 16777215), (imbyte)255); }
+
+static inline imbyte iConvertType2Byte(const float& data)
+ { return imColorQuantize(data, (imbyte)255); }
+
+// Fake float to avoid erros in the color conversion template rotines.
+// Since the color conversion use the double value, they are invalid,
+// so the automatic conversion to bitmap for complex images works only for RGB.
+static inline imbyte iConvertType2Byte(const double& data)
+{
+ imcfloat* fdata = (imcfloat*)&data;
+ return imColorQuantize(cpxmag(*fdata), (imbyte)255);
+}
+
+template <class T>
+static void iDoFillDataBitmap(int width, int height, int line, int plane, int data_type,
+ int file_color_mode, const T* line_buffer,
+ int user_color_mode, imbyte* data)
+{
+ // (reading) from file to data
+ // will handle packing, alpha, color space conversion to RGB and data_type to BYTE
+
+ int file_depth = imColorModeDepth(file_color_mode);
+ int data_depth = imColorModeDepth(user_color_mode);
+ int copy_alpha = imColorModeHasAlpha(file_color_mode) && imColorModeHasAlpha(user_color_mode);
+ int data_plane_size = width*height; // This will be used in UNpacked data
+
+ if (imColorModeIsPacked(user_color_mode))
+ data += line*width*data_depth;
+ else
+ data += line*width;
+
+ for (int x = 0; x < width; x++)
+ {
+ int x_data_offset = x*data_depth; // This will be used in packed data
+
+ if (imColorModeIsPacked(file_color_mode))
+ {
+ int x_file_offset = x*file_depth; // This will be used in packed data
+
+ if (imColorModeMatch(file_color_mode, user_color_mode))
+ {
+ // file is packed
+ // same color space components (in this case means RGB)
+ // ignore alpha if necessary.
+ int depth = IM_MIN(file_depth, data_depth);
+ for (int d = 0; d < depth; d++)
+ {
+ if (imColorModeIsPacked(user_color_mode))
+ data[x_data_offset + d] = iConvertType2Byte(line_buffer[x_file_offset + d]);
+ else
+ data[d*data_plane_size + x] = iConvertType2Byte(line_buffer[x_file_offset + d]);
+ }
+ }
+ else
+ {
+ // file is packed
+ // but different color space components
+ // only to RGB conversions are accepted
+
+ if (imColorModeSpace(user_color_mode) != IM_RGB)
+ return;
+
+ T src_data[4];
+ src_data[0] = line_buffer[x_file_offset];
+ src_data[1] = line_buffer[x_file_offset + 1];
+ src_data[2] = line_buffer[x_file_offset + 2];
+ if (imColorModeSpace(file_color_mode) == IM_CMYK)
+ src_data[3] = line_buffer[x_file_offset + 3];
+
+ // Do conversion in place
+ iConvertColor2RGB(src_data, imColorModeSpace(file_color_mode), data_type);
+
+ if (imColorModeIsPacked(user_color_mode))
+ {
+ data[x_data_offset] = iConvertType2Byte(src_data[0]);
+ data[x_data_offset + 1] = iConvertType2Byte(src_data[1]);
+ data[x_data_offset + 2] = iConvertType2Byte(src_data[2]);
+
+ if (copy_alpha)
+ {
+ if (imColorModeSpace(file_color_mode) == IM_CMYK)
+ data[x_data_offset + 3] = iConvertType2Byte(line_buffer[x_file_offset + 4]);
+ else
+ data[x_data_offset + 3] = iConvertType2Byte(line_buffer[x_file_offset + 3]);
+ }
+ }
+ else
+ {
+ data[x] = iConvertType2Byte(src_data[0]);
+ data[data_plane_size + x] = iConvertType2Byte(src_data[1]);
+ data[2*data_plane_size + x] = iConvertType2Byte(src_data[2]);
+
+ if (copy_alpha)
+ {
+ if (imColorModeSpace(file_color_mode) == IM_CMYK)
+ data[3*data_plane_size + x] = iConvertType2Byte(line_buffer[x_file_offset + 4]);
+ else
+ data[3*data_plane_size + x] = iConvertType2Byte(line_buffer[x_file_offset + 3]);
+ }
+ }
+ }
+ }
+ else
+ {
+ // file NOT packed, copy just one plane
+ // NO color space conversion possible now
+
+ if (plane >= imColorModeDepth(user_color_mode))
+ return;
+
+ if (imColorModeIsPacked(user_color_mode))
+ data[x_data_offset + plane] = iConvertType2Byte(line_buffer[x]);
+ else
+ data[plane*data_plane_size + x] = iConvertType2Byte(line_buffer[x]);
+ }
+ }
+}
+
+static void iFileExpandBits(imFile* ifile)
+{
+ // conversion will be done in place in backward order (from end to start)
+
+ if (abs(ifile->convert_bpp) < 8)
+ {
+ imbyte* byte_buffer = (imbyte*)ifile->line_buffer;
+ imbyte* bit_buffer = (imbyte*)ifile->line_buffer;
+
+ byte_buffer += ifile->width-1;
+ int bpp = ifile->convert_bpp;
+ int expand_range = imColorModeSpace(ifile->file_color_mode) == IM_GRAY? 1: 0;
+
+ for (int i=ifile->width-1; i >= 0; i--)
+ {
+ if (bpp == 1)
+ *byte_buffer = (imbyte)((bit_buffer[i / 8] >> (7 - i % 8)) & 0x01);
+ else if (bpp == 4)
+ *byte_buffer = (imbyte)((bit_buffer[i / 2] >> ((1 - i % 2) * 4)) & 0x0F);
+ else if (bpp == 2)
+ *byte_buffer = (imbyte)((bit_buffer[i / 4] >> ((3 - i % 4) * 2)) & 0x03);
+
+ if (expand_range) /* if convert_bpp<0 then only expand its range */
+ {
+ if (bpp == 4 || bpp == -4)
+ *byte_buffer *= 17;
+ else if (bpp == 2 || bpp == -2)
+ *byte_buffer *= 85;
+ }
+
+ byte_buffer--;
+ }
+ }
+ else if (ifile->convert_bpp == 12)
+ {
+ imushort* ushort_buffer = (imushort*)ifile->line_buffer;
+ imbyte* bit_buffer = (imbyte*)ifile->line_buffer;
+
+ for (int i=ifile->width-1; i >= 0; i--)
+ {
+ int byte_index = (3*i)/2;
+ if (i%2)
+ ushort_buffer[i] = (bit_buffer[byte_index] << 4) | (bit_buffer[byte_index+1] & 0x0F);
+ else
+ ushort_buffer[i] = ((bit_buffer[byte_index] & 0x0F) << 8) | (bit_buffer[byte_index+1]);
+ }
+ }
+}
+
+static void iFileCompactBits(imFile* ifile)
+{
+ // conversion will be done in place
+ imbyte* byte_buffer = (imbyte*)ifile->line_buffer;
+ imbyte* bit_buffer = (imbyte*)ifile->line_buffer;
+
+ if (ifile->convert_bpp == 1)
+ {
+ for (int i = 0; i < ifile->width; i++)
+ {
+ if (*byte_buffer)
+ bit_buffer[i / 8] |= (0x01 << (7 - (i % 8)));
+ else
+ bit_buffer[i / 8] &= ~(0x01 << (7 - (i % 8)));
+
+ byte_buffer++;
+ }
+ }
+ else // -1 == expand 1 to 255
+ {
+ for (int i = 0; i < ifile->width; i++)
+ {
+ if (*byte_buffer)
+ *byte_buffer = 255;
+
+ byte_buffer++;
+ }
+ }
+}
+
+template <class SRC, class DST>
+static void iDoSwitchInt(int count, const SRC* src_data, DST* dst_data, int offset)
+{
+ for (int i = 0; i < count; i++)
+ {
+ *dst_data++ = (DST)((int)*src_data++ + offset);
+ }
+}
+
+template <class SRC, class DST>
+static void iDoSwitchReal(int count, const SRC* src_data, DST* dst_data)
+{
+ for (int i = 0; i < count; i++)
+ {
+ *dst_data++ = (DST)(*src_data++);
+ }
+}
+
+static void iFileSwitchFromType(imFile* ifile)
+{
+ int line_count = imImageLineCount(ifile->width, ifile->file_color_mode);
+ switch(ifile->file_data_type)
+ {
+ case IM_BYTE: // Source is char
+ iDoSwitchInt(line_count, (const char*)ifile->line_buffer, (imbyte*)ifile->line_buffer, 128);
+ break;
+ case IM_USHORT: // Source is short
+ iDoSwitchInt(line_count, (const short*)ifile->line_buffer, (imushort*)ifile->line_buffer, 32768);
+ break;
+ case IM_INT: // Source is uint
+ iDoSwitchInt(line_count, (const unsigned int*)ifile->line_buffer, (int*)ifile->line_buffer, -8388608);
+ break;
+ case IM_FLOAT: // Source is double
+ iDoSwitchReal(line_count, (const double*)ifile->line_buffer, (float*)ifile->line_buffer);
+ break;
+ case IM_CFLOAT: // Source is complex double
+ iDoSwitchReal(2*line_count, (const double*)ifile->line_buffer, (float*)ifile->line_buffer);
+ break;
+ }
+}
+
+static void iFileSwitchToType(imFile* ifile)
+{
+ int line_count = imImageLineCount(ifile->width, ifile->file_color_mode);
+ switch(ifile->file_data_type)
+ {
+ case IM_BYTE: // Destiny is char
+ iDoSwitchInt(line_count, (const imbyte*)ifile->line_buffer, (char*)ifile->line_buffer, -128);
+ break;
+ case IM_USHORT: // Destiny is short
+ iDoSwitchInt(line_count, (const imushort*)ifile->line_buffer, (short*)ifile->line_buffer, -32768);
+ break;
+ case IM_INT: // Destiny is uint
+ iDoSwitchInt(line_count, (const int*)ifile->line_buffer, (unsigned int*)ifile->line_buffer, 8388608);
+ break;
+ case IM_FLOAT: // Destiny is double
+ iDoSwitchReal(line_count, (const float*)ifile->line_buffer, (double*)ifile->line_buffer);
+ break;
+ case IM_CFLOAT: // Destiny is complex double
+ iDoSwitchReal(2*line_count, (const float*)ifile->line_buffer, (double*)ifile->line_buffer);
+ break;
+ }
+}
+
+void imFileLineBufferWrite(imFile* ifile, const void* data, int line, int plane)
+{
+ // (writing) from data to file
+
+ if (imColorModeIsTopDown(ifile->file_color_mode) != imColorModeIsTopDown(ifile->user_color_mode))
+ line = ifile->height-1 - line;
+
+ if ((ifile->file_color_mode & 0x3FF) ==
+ (ifile->user_color_mode & 0x3FF)) // compare only packing, alpha and color space
+ {
+ int data_offset = line*ifile->line_buffer_size;
+ if (plane != 0)
+ data_offset += plane*ifile->height*ifile->line_buffer_size;
+
+ memcpy(ifile->line_buffer, (unsigned char*)data + data_offset, ifile->line_buffer_size);
+ }
+ else
+ {
+ switch(ifile->file_data_type)
+ {
+ case IM_BYTE:
+ iDoFillLineBuffer(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (imbyte*)ifile->line_buffer,
+ ifile->user_color_mode, (const imbyte*)data);
+ break;
+ case IM_USHORT:
+ iDoFillLineBuffer(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (imushort*)ifile->line_buffer,
+ ifile->user_color_mode, (const imushort*)data);
+ break;
+ case IM_INT:
+ iDoFillLineBuffer(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (int*)ifile->line_buffer,
+ ifile->user_color_mode, (const int*)data);
+ break;
+ case IM_FLOAT:
+ iDoFillLineBuffer(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (float*)ifile->line_buffer,
+ ifile->user_color_mode, (const float*)data);
+ break;
+ case IM_CFLOAT:
+ iDoFillLineBuffer(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (imcfloat*)ifile->line_buffer,
+ ifile->user_color_mode, (const imcfloat*)data);
+ break;
+ }
+ }
+
+ if (ifile->convert_bpp)
+ iFileCompactBits(ifile);
+
+ if (ifile->switch_type)
+ iFileSwitchToType(ifile);
+}
+
+void imFileLineBufferRead(imFile* ifile, void* data, int line, int plane)
+{
+ // (reading) from file to data
+
+ if (imColorModeIsTopDown(ifile->file_color_mode) != imColorModeIsTopDown(ifile->user_color_mode))
+ line = ifile->height-1 - line;
+
+ if (ifile->convert_bpp)
+ iFileExpandBits(ifile);
+
+ if (ifile->switch_type)
+ iFileSwitchFromType(ifile);
+
+ if ((ifile->file_color_mode & 0x3FF) == (ifile->user_color_mode & 0x3FF) && // compare only packing, alpha and color space, ignore bottom up.
+ ifile->file_data_type == ifile->user_data_type) // compare data type when reading
+ {
+ int data_offset = line*ifile->line_buffer_size;
+ if (plane != 0)
+ data_offset += plane*ifile->height*ifile->line_buffer_size;
+
+ memcpy((unsigned char*)data + data_offset, ifile->line_buffer, ifile->line_buffer_size);
+ }
+ else
+ {
+ // now we have 2 conversions groups
+ // one to convert only packing and alpha
+ // and the other to convert packing, alpha, color space and data type
+ int convert2bitmap = 0;
+ if (imColorModeSpace(ifile->user_color_mode) != imColorModeSpace(ifile->file_color_mode) ||
+ ifile->file_data_type != IM_BYTE)
+ convert2bitmap = 1;
+
+ switch(ifile->file_data_type)
+ {
+ case IM_BYTE:
+ if (convert2bitmap)
+ iDoFillDataBitmap(ifile->width, ifile->height, line, plane, ifile->file_data_type,
+ ifile->file_color_mode, (const imbyte*)ifile->line_buffer,
+ ifile->user_color_mode, (imbyte*)data);
+ else
+ iDoFillData(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (const imbyte*)ifile->line_buffer,
+ ifile->user_color_mode, (imbyte*)data);
+ break;
+ case IM_USHORT:
+ if (convert2bitmap)
+ iDoFillDataBitmap(ifile->width, ifile->height, line, plane, ifile->file_data_type,
+ ifile->file_color_mode, (const imushort*)ifile->line_buffer,
+ ifile->user_color_mode, (imbyte*)data);
+ else
+ iDoFillData(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (const imushort*)ifile->line_buffer,
+ ifile->user_color_mode, (imushort*)data);
+ break;
+ case IM_INT:
+ if (convert2bitmap)
+ iDoFillDataBitmap(ifile->width, ifile->height, line, plane, ifile->file_data_type,
+ ifile->file_color_mode, (const int*)ifile->line_buffer,
+ ifile->user_color_mode, (imbyte*)data);
+ else
+ iDoFillData(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (const int*)ifile->line_buffer,
+ ifile->user_color_mode, (int*)data);
+ break;
+ case IM_FLOAT:
+ if (convert2bitmap)
+ iDoFillDataBitmap(ifile->width, ifile->height, line, plane, ifile->file_data_type,
+ ifile->file_color_mode, (const float*)ifile->line_buffer,
+ ifile->user_color_mode, (imbyte*)data);
+ else
+ iDoFillData(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (const float*)ifile->line_buffer,
+ ifile->user_color_mode, (float*)data);
+ break;
+ case IM_CFLOAT:
+ if (convert2bitmap)
+ iDoFillDataBitmap(ifile->width, ifile->height, line, plane, ifile->file_data_type,
+ ifile->file_color_mode, (const double*)ifile->line_buffer,
+ ifile->user_color_mode, (imbyte*)data);
+ else
+ iDoFillData(ifile->width, ifile->height, line, plane,
+ ifile->file_color_mode, (const imcfloat*)ifile->line_buffer,
+ ifile->user_color_mode, (imcfloat*)data);
+ break;
+ }
+ }
+}
+
+void imFileLineBufferInit(imFile* ifile)
+{
+ ifile->line_buffer_size = imImageLineSize(ifile->width, ifile->file_color_mode, ifile->file_data_type);
+
+ if (ifile->switch_type && (ifile->file_data_type == IM_FLOAT || ifile->file_data_type == IM_CFLOAT))
+ ifile->line_buffer_extra += ifile->line_buffer_size; // double the size at least
+
+ if (ifile->line_buffer_size + ifile->line_buffer_extra > ifile->line_buffer_alloc)
+ {
+ ifile->line_buffer_alloc = ifile->line_buffer_size + ifile->line_buffer_extra;
+ ifile->line_buffer = realloc(ifile->line_buffer, ifile->line_buffer_alloc);
+ }
+}
+
+int imFileLineBufferCount(imFile* ifile)
+{
+ int count = ifile->height;
+ if (!imColorModeIsPacked(ifile->file_color_mode))
+ {
+ if (imColorModeHasAlpha(ifile->file_color_mode) && imColorModeHasAlpha(ifile->user_color_mode))
+ count *= imColorModeDepth(ifile->file_color_mode);
+ else
+ count *= imColorModeDepth(imColorModeSpace(ifile->file_color_mode));
+ }
+ return count;
+}
+
+void imFileLineBufferInc(imFile* ifile, int *row, int *plane)
+{
+ if (!imColorModeIsPacked(ifile->file_color_mode))
+ {
+ if (*row == ifile->height-1)
+ {
+ *row = 0;
+ (*plane)++;
+ return;
+ }
+ }
+
+ (*row)++;
+}
+
+int imFileCheckConversion(imFile* ifile)
+{
+ if ((ifile->file_color_mode & 0x3FF) == (ifile->user_color_mode & 0x3FF) && // compare only packing, alpha and color space
+ ifile->file_data_type == ifile->user_data_type)
+ return 1;
+
+ int user_color_space = imColorModeSpace(ifile->user_color_mode);
+ int file_color_space = imColorModeSpace(ifile->file_color_mode);
+
+ // NO color space conversion if file is not packed.
+ if(user_color_space != file_color_space &&
+ imColorModeDepth(file_color_space) > 1 &&
+ !imColorModeIsPacked(ifile->file_color_mode))
+ return 0;
+
+ if (ifile->is_new)
+ {
+ // (writing) from data to file
+
+ // NO data type conversions when writing.
+ if (ifile->file_data_type != ifile->user_data_type)
+ return 0;
+
+ // NO color space conversions when writing.
+ // If there is a necessary conversion the format driver will do it.
+ if (user_color_space != file_color_space)
+ return 0;
+ }
+ else
+ {
+ // (reading) from file to data
+
+ // Data type conversions only to byte
+ if (ifile->file_data_type != ifile->user_data_type &&
+ ifile->user_data_type != IM_BYTE)
+ return 0;
+ }
+
+ return 1;
+}