summaryrefslogtreecommitdiff
path: root/plugins/fast_float/src/fast_float_15bits.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/fast_float/src/fast_float_15bits.c')
-rw-r--r--plugins/fast_float/src/fast_float_15bits.c568
1 files changed, 568 insertions, 0 deletions
diff --git a/plugins/fast_float/src/fast_float_15bits.c b/plugins/fast_float/src/fast_float_15bits.c
new file mode 100644
index 0000000..5186466
--- /dev/null
+++ b/plugins/fast_float/src/fast_float_15bits.c
@@ -0,0 +1,568 @@
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System, fast floating point extensions
+// Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved
+//
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+//---------------------------------------------------------------------------------
+
+#include "fast_float_internal.h"
+
+
+//---------------------------------------------------------------------------------
+
+// The internal photoshop 16 bit format range is 1.15 fixed point, which goes 0..32768
+// (NOT 32767) that means:
+//
+// 16 bits encoding 15 bit Photoshop encoding
+// ================ =========================
+//
+// 0x0000 0x0000
+// 0xFFFF 0x8000
+//
+// A nice (and fast) way to implement conversions is by using 64 bit values, which are
+// native CPU word size in most today architectures.
+// In CMYK, internal Photoshop format comes inverted, and this inversion happens after
+// the resizing, so values 32769 to 65535 are never used in PhotoShop.
+
+//---------------------------------------------------------------------------------
+
+// This macro converts 16 bits to 15 bits by using a 64 bits value
+cmsINLINE cmsUInt16Number From16To15(cmsUInt16Number x16)
+{
+ cmsUInt64Number r64 = (((cmsUInt64Number)x16 << 15)) / 0xFFFFL;
+ return (cmsUInt16Number)r64;
+}
+
+// This macro converts 15 bits to 16 bits by using a 64 bit value. It is based in fixed 1.15 math
+cmsINLINE cmsUInt16Number From15To16(cmsUInt16Number x15)
+{
+ cmsUInt64Number r64 = ((cmsUInt64Number) x15 * 0xFFFF + 0x4000L) >> 15;
+ return (cmsUInt16Number)r64;
+}
+
+// Specialized 1-channel formatters
+static
+cmsUInt8Number* Unroll15bitsGray(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ Values[0] = From15To16(*(cmsUInt16Number*)Buffer);
+
+ return Buffer + 2;
+}
+
+
+static
+cmsUInt8Number* Pack15bitsGray(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ *(cmsUInt16Number*)Buffer = From16To15(Values[0]);
+ return Buffer + 2;
+}
+
+// Specialized 3-channels formatters
+static
+cmsUInt8Number* Unroll15bitsRGB(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ Values[0] = From15To16(*(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[1] = From15To16(*(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[2] = From15To16(*(cmsUInt16Number*)Buffer);
+
+ return Buffer + 2;
+}
+
+
+static
+cmsUInt8Number* Pack15bitsRGB(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ *(cmsUInt16Number*)Buffer = From16To15(Values[0]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = From16To15(Values[1]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = From16To15(Values[2]);
+
+ return Buffer + 2;
+}
+
+
+static
+cmsUInt8Number* Unroll15bitsRGBA(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ Values[0] = From15To16(*(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[1] = From15To16(*(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[2] = From15To16(*(cmsUInt16Number*)Buffer);
+
+ return Buffer + 4;
+}
+
+
+static
+cmsUInt8Number* Pack15bitsRGBA(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ *(cmsUInt16Number*)Buffer = From16To15(Values[0]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = From16To15(Values[1]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = From16To15(Values[2]);
+
+ return Buffer + 4;
+}
+
+
+// Specialized 3 channels reversed formatters
+static
+cmsUInt8Number* Unroll15bitsBGR(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ Values[2] = From15To16(*(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[1] = From15To16(*(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[0] = From15To16(*(cmsUInt16Number*)Buffer);
+
+ return Buffer + 2;
+}
+
+
+static
+cmsUInt8Number* Pack15bitsBGR(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ *(cmsUInt16Number*)Buffer = From16To15(Values[2]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = From16To15(Values[1]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = From16To15(Values[0]);
+
+ return Buffer+2;
+}
+
+// Specialized 4 channels CMYK formatters. Note Photoshop stores CMYK reversed
+static
+cmsUInt8Number* Unroll15bitsCMYK(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ Values[0] = From15To16(0x8000 - *(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[1] = From15To16(0x8000 - *(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[2] = From15To16(0x8000 - *(cmsUInt16Number*)Buffer);
+ Buffer += 2;
+ Values[3] = From15To16(0x8000 - *(cmsUInt16Number*)Buffer);
+
+ return Buffer + 2;
+}
+
+static
+cmsUInt8Number* Pack15bitsCMYK(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ UNUSED_PARAMETER(CMMcargo);
+ UNUSED_PARAMETER(Stride);
+
+ *(cmsUInt16Number*)Buffer = 0x8000U - From16To15(Values[0]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = 0x8000U - From16To15(Values[1]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = 0x8000U - From16To15(Values[2]);
+ Buffer += 2;
+ *(cmsUInt16Number*)Buffer = 0x8000U - From16To15(Values[3]);
+
+ return Buffer + 2;
+}
+
+
+// This macros does all handling for fallthrough cases
+cmsINLINE cmsUInt16Number UnrollOne(cmsUInt16Number x, cmsBool Reverse, cmsBool SwapEndian)
+{
+ if (SwapEndian)
+ x = (x << 8) | (x >> 8);
+
+ if (Reverse)
+ x = 0xffff - x;
+
+ return From15To16(x);
+}
+
+cmsINLINE cmsUInt16Number PackOne(cmsUInt16Number x, cmsBool Reverse, cmsBool SwapEndian)
+{
+ x = From16To15(x);
+
+ if (Reverse)
+ x = 0xffff - x;
+
+ if (SwapEndian)
+ x = (x << 8) | (x >> 8);
+
+ return x;
+}
+
+// Generic planar support
+static
+cmsUInt8Number* Unroll15bitsPlanar(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ _xform_head* head = (_xform_head*) CMMcargo;
+ int nChan = T_CHANNELS(head->InputFormat);
+ int DoSwap = T_DOSWAP(head->InputFormat);
+ int Reverse = T_FLAVOR(head->InputFormat);
+ int SwapEndian = T_ENDIAN16(head->InputFormat);
+ int i;
+ cmsUInt8Number* Init = accum;
+
+ UNUSED_PARAMETER(Stride);
+
+ if (DoSwap) {
+ accum += T_EXTRA(head->InputFormat) * Stride * 2;
+ }
+
+ for (i = 0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ wIn[index] = UnrollOne(*(cmsUInt16Number*)accum, Reverse, SwapEndian);
+
+ accum += Stride * 2;
+ }
+
+ return (Init + 2);
+}
+
+
+static
+cmsUInt8Number* Pack15bitsPlanar(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ _xform_head* head = (_xform_head*)CMMcargo;
+ int nChan = T_CHANNELS(head->OutputFormat);
+ int DoSwap = T_DOSWAP(head->OutputFormat);
+ int Reverse = T_FLAVOR(head->OutputFormat);
+ int SwapEndian = T_ENDIAN16(head->OutputFormat);
+ register int i;
+ cmsUInt8Number* Init = output;
+
+
+ if (DoSwap) {
+ output += T_EXTRA(head->OutputFormat) * Stride * 2;
+ }
+
+ for (i = 0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ *(cmsUInt16Number*)output = PackOne(wOut[index], Reverse, SwapEndian);
+ output += (Stride * sizeof(cmsUInt16Number));
+ }
+
+ return (Init + sizeof(cmsUInt16Number));
+}
+
+
+
+// Generic falltrough
+static
+cmsUInt8Number* Unroll15bitsChunky(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ _xform_head* head = (_xform_head*) CMMcargo;
+
+ int nChan = T_CHANNELS(head->InputFormat);
+ int DoSwap = T_DOSWAP(head->InputFormat);
+ int Reverse = T_FLAVOR(head->InputFormat);
+ int SwapEndian = T_ENDIAN16(head->InputFormat);
+
+ register int i;
+
+ UNUSED_PARAMETER(Stride);
+
+ if (DoSwap) {
+ Buffer += T_EXTRA(head->OutputFormat) * 2;
+ }
+
+ for (i = 0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ Values[index] = UnrollOne(*(cmsUInt16Number*)Buffer, Reverse, SwapEndian);
+
+ Buffer += 2;
+ }
+
+
+ return Buffer;
+}
+
+
+static
+cmsUInt8Number* Pack15bitsChunky(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ _xform_head* head = (_xform_head*)CMMcargo;
+
+ int nChan = T_CHANNELS(head->OutputFormat);
+ int DoSwap = T_DOSWAP(head->OutputFormat);
+ int Reverse = T_FLAVOR(head->OutputFormat);
+ int SwapEndian = T_ENDIAN16(head->OutputFormat);
+
+ register int i;
+
+ UNUSED_PARAMETER(Stride);
+
+ if (DoSwap) {
+ Buffer += T_EXTRA(head->OutputFormat) * 2;
+ }
+
+ for (i = 0; i < nChan; i++) {
+
+ int index = DoSwap ? (nChan - i - 1) : i;
+
+ *(cmsUInt16Number*)Buffer = PackOne(Values[index], Reverse, SwapEndian);
+
+ Buffer += 2;
+ }
+
+ return Buffer;
+}
+
+
+
+// Generic N-bytes plus dither 16-to-8 conversion.
+static int err[cmsMAXCHANNELS];
+
+static
+cmsUInt8Number* PackNBytesDither(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ _xform_head* info = (_xform_head*)CMMcargo;
+
+ int nChan = T_CHANNELS(info->OutputFormat);
+ register int i;
+ unsigned int n, pe, pf;
+
+ UNUSED_PARAMETER(Stride);
+
+ for (i = 0; i < nChan; i++) {
+
+ n = Values[i] + err[i]; // Value
+
+ pe = (n / 257); // Whole part
+ pf = (n % 257); // Fractional part
+
+ err[i] = pf; // Store it for next pixel
+
+ *Buffer++ = (cmsUInt8Number) pe;
+ }
+
+ return Buffer + T_EXTRA(info->OutputFormat);
+}
+
+
+static
+cmsUInt8Number* PackNBytesSwapDither(register struct _cmstransform_struct* CMMcargo,
+ register cmsUInt16Number Values[],
+ register cmsUInt8Number* Buffer,
+ register cmsUInt32Number Stride)
+{
+ _xform_head* info = (_xform_head*)CMMcargo;
+
+ int nChan = T_CHANNELS(info->OutputFormat);
+ register int i;
+ unsigned int n, pe, pf;
+
+ UNUSED_PARAMETER(Stride);
+
+ for (i = nChan - 1; i >= 0; --i) {
+
+ n = Values[i] + err[i]; // Value
+
+ pe = (n / 257); // Whole part
+ pf = (n % 257); // Fractional part
+
+ err[i] = pf; // Store it for next pixel
+
+ *Buffer++ = (cmsUInt8Number)pe;
+ }
+
+
+ return Buffer + T_EXTRA(info->OutputFormat);
+}
+
+
+// The factory for 15 bits. This function returns a pointer to specialized function
+// that would deal with the asked format. It return a pointer to NULL if the format
+// is not supported. This is tha basis of formatter plug-in for 15 bit formats.
+cmsFormatter Formatter_15Bit_Factory(cmsUInt32Number Type,
+ cmsFormatterDirection Dir,
+ cmsUInt32Number dwFlags)
+{
+ cmsFormatter Result = { NULL };
+
+ UNUSED_PARAMETER(dwFlags);
+
+ switch (Type) {
+
+ // Simple Gray
+ case TYPE_GRAY_15:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsGray : Pack15bitsGray;
+ break;
+
+ // 3 channels
+ case TYPE_CMY_15:
+ case TYPE_RGB_15:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsRGB : Pack15bitsRGB;
+ break;
+
+ // 3 channels reversed
+ case TYPE_YMC_15:
+ case TYPE_BGR_15:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsBGR : Pack15bitsBGR;
+ break;
+
+ // 3 Channels plus one alpha
+ case TYPE_RGBA_15:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsRGBA : Pack15bitsRGBA;
+ break;
+
+ // 4 channels
+ case TYPE_CMYK_15:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsCMYK : Pack15bitsCMYK;
+ break;
+
+ // Planar versions
+ case TYPE_GRAYA_15_PLANAR:
+ case TYPE_RGB_15_PLANAR:
+ case TYPE_BGR_15_PLANAR:
+ case TYPE_RGBA_15_PLANAR:
+ case TYPE_ABGR_15_PLANAR:
+ case TYPE_CMY_15_PLANAR:
+ case TYPE_CMYK_15_PLANAR:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsPlanar : Pack15bitsPlanar;
+ break;
+
+ // Falltrough for remaining (corner) cases
+ case TYPE_GRAY_15_REV:
+ case TYPE_GRAY_15_SE:
+ case TYPE_GRAYA_15:
+ case TYPE_GRAYA_15_SE:
+ case TYPE_RGB_15_SE:
+ case TYPE_BGR_15_SE:
+ case TYPE_RGBA_15_SE:
+ case TYPE_ARGB_15:
+ case TYPE_ABGR_15:
+ case TYPE_ABGR_15_SE:
+ case TYPE_BGRA_15:
+ case TYPE_BGRA_15_SE:
+ case TYPE_CMY_15_SE:
+ case TYPE_CMYK_15_REV:
+ case TYPE_CMYK_15_SE:
+ case TYPE_KYMC_15:
+ case TYPE_KYMC_15_SE:
+ case TYPE_KCMY_15:
+ case TYPE_KCMY_15_REV:
+ case TYPE_KCMY_15_SE:
+ Result.Fmt16 = (Dir == cmsFormatterInput) ? Unroll15bitsChunky : Pack15bitsChunky;
+ break;
+
+ case TYPE_GRAY_8_DITHER:
+ case TYPE_RGB_8_DITHER:
+ case TYPE_RGBA_8_DITHER:
+ case TYPE_CMYK_8_DITHER:
+ if (Dir == cmsFormatterOutput) {
+ Result.Fmt16 = PackNBytesDither;
+ }
+ break;
+
+ case TYPE_ABGR_8_DITHER:
+ case TYPE_BGR_8_DITHER:
+ case TYPE_KYMC_8_DITHER:
+ if (Dir == cmsFormatterOutput) {
+ Result.Fmt16 = PackNBytesSwapDither;
+ }
+ break;
+
+ default:;
+ }
+
+ return Result;
+}
+
+
+