Path: blob/master/src/java.desktop/share/native/liblcms/cmsalpha.c
41152 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324// This file is available under and governed by the GNU General Public25// License version 2 only, as published by the Free Software Foundation.26// However, the following notice accompanied the original version of this27// file:28//29//---------------------------------------------------------------------------------30//31// Little Color Management System32// Copyright (c) 1998-2020 Marti Maria Saguer33//34// Permission is hereby granted, free of charge, to any person obtaining35// a copy of this software and associated documentation files (the "Software"),36// to deal in the Software without restriction, including without limitation37// the rights to use, copy, modify, merge, publish, distribute, sublicense,38// and/or sell copies of the Software, and to permit persons to whom the Software39// is furnished to do so, subject to the following conditions:40//41// The above copyright notice and this permission notice shall be included in42// all copies or substantial portions of the Software.43//44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,45// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO46// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND47// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE48// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION49// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION50// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.51//52//---------------------------------------------------------------------------------53//5455#include "lcms2_internal.h"5657// Alpha copy ------------------------------------------------------------------------------------------------------------------5859// This macro return words stored as big endian60#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))616263// Floor to byte, taking care of saturation64cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)65{66d += 0.5;67if (d <= 0) return 0;68if (d >= 255.0) return 255;6970return (cmsUInt8Number) _cmsQuickFloorWord(d);71}727374// Return the size in bytes of a given formatter75static76cmsUInt32Number trueBytesSize(cmsUInt32Number Format)77{78cmsUInt32Number fmt_bytes = T_BYTES(Format);7980// For double, the T_BYTES field returns zero81if (fmt_bytes == 0)82return sizeof(double);8384// Otherwise, it is already correct for all formats85return fmt_bytes;86}878889// Several format converters9091typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src);929394// From 89596static97void copy8(void* dst, const void* src)98{99memmove(dst, src, 1);100}101102static103void from8to16(void* dst, const void* src)104{105cmsUInt8Number n = *(cmsUInt8Number*)src;106*(cmsUInt16Number*) dst = (cmsUInt16Number) FROM_8_TO_16(n);107}108109static110void from8to16SE(void* dst, const void* src)111{112cmsUInt8Number n = *(cmsUInt8Number*)src;113*(cmsUInt16Number*)dst = CHANGE_ENDIAN(FROM_8_TO_16(n));114}115116static117void from8toFLT(void* dst, const void* src)118{119*(cmsFloat32Number*)dst = (cmsFloat32Number) (*(cmsUInt8Number*)src) / 255.0f;120}121122static123void from8toDBL(void* dst, const void* src)124{125*(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt8Number*)src) / 255.0;126}127128static129void from8toHLF(void* dst, const void* src)130{131#ifndef CMS_NO_HALF_SUPPORT132cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f;133*(cmsUInt16Number*)dst = _cmsFloat2Half(n);134#else135cmsUNUSED_PARAMETER(dst);136cmsUNUSED_PARAMETER(src);137#endif138}139140// From 16141142static143void from16to8(void* dst, const void* src)144{145cmsUInt16Number n = *(cmsUInt16Number*)src;146*(cmsUInt8Number*) dst = FROM_16_TO_8(n);147}148149static150void from16SEto8(void* dst, const void* src)151{152cmsUInt16Number n = *(cmsUInt16Number*)src;153*(cmsUInt8Number*)dst = FROM_16_TO_8(CHANGE_ENDIAN(n));154}155156static157void copy16(void* dst, const void* src)158{159memmove(dst, src, 2);160}161162static163void from16to16(void* dst, const void* src)164{165cmsUInt16Number n = *(cmsUInt16Number*)src;166*(cmsUInt16Number*)dst = CHANGE_ENDIAN(n);167}168169static170void from16toFLT(void* dst, const void* src)171{172*(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;173}174175static176void from16SEtoFLT(void* dst, const void* src)177{178*(cmsFloat32Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;179}180181static182void from16toDBL(void* dst, const void* src)183{184*(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt16Number*)src) / 65535.0;185}186187static188void from16SEtoDBL(void* dst, const void* src)189{190*(cmsFloat64Number*)dst = (cmsFloat64Number) (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0;191}192193static194void from16toHLF(void* dst, const void* src)195{196#ifndef CMS_NO_HALF_SUPPORT197cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f;198*(cmsUInt16Number*)dst = _cmsFloat2Half(n);199#else200cmsUNUSED_PARAMETER(dst);201cmsUNUSED_PARAMETER(src);202#endif203}204205static206void from16SEtoHLF(void* dst, const void* src)207{208#ifndef CMS_NO_HALF_SUPPORT209cmsFloat32Number n = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;210*(cmsUInt16Number*)dst = _cmsFloat2Half(n);211#else212cmsUNUSED_PARAMETER(dst);213cmsUNUSED_PARAMETER(src);214#endif215}216// From Float217218static219void fromFLTto8(void* dst, const void* src)220{221cmsFloat32Number n = *(cmsFloat32Number*)src;222*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);223}224225static226void fromFLTto16(void* dst, const void* src)227{228cmsFloat32Number n = *(cmsFloat32Number*)src;229*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);230}231232static233void fromFLTto16SE(void* dst, const void* src)234{235cmsFloat32Number n = *(cmsFloat32Number*)src;236cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);237238*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);239}240241static242void copy32(void* dst, const void* src)243{244memmove(dst, src, sizeof(cmsFloat32Number));245}246247static248void fromFLTtoDBL(void* dst, const void* src)249{250cmsFloat32Number n = *(cmsFloat32Number*)src;251*(cmsFloat64Number*)dst = (cmsFloat64Number)n;252}253254static255void fromFLTtoHLF(void* dst, const void* src)256{257#ifndef CMS_NO_HALF_SUPPORT258cmsFloat32Number n = *(cmsFloat32Number*)src;259*(cmsUInt16Number*)dst = _cmsFloat2Half(n);260#else261cmsUNUSED_PARAMETER(dst);262cmsUNUSED_PARAMETER(src);263#endif264}265266267// From HALF268269static270void fromHLFto8(void* dst, const void* src)271{272#ifndef CMS_NO_HALF_SUPPORT273cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);274*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);275#else276cmsUNUSED_PARAMETER(dst);277cmsUNUSED_PARAMETER(src);278#endif279280}281282static283void fromHLFto16(void* dst, const void* src)284{285#ifndef CMS_NO_HALF_SUPPORT286cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);287*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);288#else289cmsUNUSED_PARAMETER(dst);290cmsUNUSED_PARAMETER(src);291#endif292}293294static295void fromHLFto16SE(void* dst, const void* src)296{297#ifndef CMS_NO_HALF_SUPPORT298cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);299cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);300*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);301#else302cmsUNUSED_PARAMETER(dst);303cmsUNUSED_PARAMETER(src);304#endif305}306307static308void fromHLFtoFLT(void* dst, const void* src)309{310#ifndef CMS_NO_HALF_SUPPORT311*(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);312#else313cmsUNUSED_PARAMETER(dst);314cmsUNUSED_PARAMETER(src);315#endif316}317318static319void fromHLFtoDBL(void* dst, const void* src)320{321#ifndef CMS_NO_HALF_SUPPORT322*(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);323#else324cmsUNUSED_PARAMETER(dst);325cmsUNUSED_PARAMETER(src);326#endif327}328329// From double330static331void fromDBLto8(void* dst, const void* src)332{333cmsFloat64Number n = *(cmsFloat64Number*)src;334*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);335}336337static338void fromDBLto16(void* dst, const void* src)339{340cmsFloat64Number n = *(cmsFloat64Number*)src;341*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);342}343344static345void fromDBLto16SE(void* dst, const void* src)346{347cmsFloat64Number n = *(cmsFloat64Number*)src;348cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);349*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);350}351352static353void fromDBLtoFLT(void* dst, const void* src)354{355cmsFloat64Number n = *(cmsFloat64Number*)src;356*(cmsFloat32Number*)dst = (cmsFloat32Number) n;357}358359static360void fromDBLtoHLF(void* dst, const void* src)361{362#ifndef CMS_NO_HALF_SUPPORT363cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;364*(cmsUInt16Number*)dst = _cmsFloat2Half(n);365#else366cmsUNUSED_PARAMETER(dst);367cmsUNUSED_PARAMETER(src);368#endif369}370371static372void copy64(void* dst, const void* src)373{374memmove(dst, src, sizeof(cmsFloat64Number));375}376377378// Returns the position (x or y) of the formatter in the table of functions379static380int FormatterPos(cmsUInt32Number frm)381{382cmsUInt32Number b = T_BYTES(frm);383384if (b == 0 && T_FLOAT(frm))385return 5; // DBL386#ifndef CMS_NO_HALF_SUPPORT387if (b == 2 && T_FLOAT(frm))388return 3; // HLF389#endif390if (b == 4 && T_FLOAT(frm))391return 4; // FLT392if (b == 2 && !T_FLOAT(frm))393{394if (T_ENDIAN16(frm))395return 2; // 16SE396else397return 1; // 16398}399if (b == 1 && !T_FLOAT(frm))400return 0; // 8401return -1; // not recognized402}403404// Obtains an alpha-to-alpha function formatter405static406cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)407{408static cmsFormatterAlphaFn FormattersAlpha[6][6] = {409410/* from 8 */ { copy8, from8to16, from8to16SE, from8toHLF, from8toFLT, from8toDBL },411/* from 16*/ { from16to8, copy16, from16to16, from16toHLF, from16toFLT, from16toDBL },412/* from 16SE*/{ from16SEto8, from16to16, copy16, from16SEtoHLF,from16SEtoFLT, from16SEtoDBL },413/* from HLF*/ { fromHLFto8, fromHLFto16, fromHLFto16SE, copy16, fromHLFtoFLT, fromHLFtoDBL },414/* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTto16SE, fromFLTtoHLF, copy32, fromFLTtoDBL },415/* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLto16SE, fromDBLtoHLF, fromDBLtoFLT, copy64 }};416417int in_n = FormatterPos(in);418int out_n = FormatterPos(out);419420if (in_n < 0 || out_n < 0 || in_n > 5 || out_n > 5) {421422cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width");423return NULL;424}425426return FormattersAlpha[in_n][out_n];427}428429430431// This function computes the distance from each component to the next one in bytes.432static433void ComputeIncrementsForChunky(cmsUInt32Number Format,434cmsUInt32Number ComponentStartingOrder[],435cmsUInt32Number ComponentPointerIncrements[])436{437cmsUInt32Number channels[cmsMAXCHANNELS];438cmsUInt32Number extra = T_EXTRA(Format);439cmsUInt32Number nchannels = T_CHANNELS(Format);440cmsUInt32Number total_chans = nchannels + extra;441cmsUInt32Number i;442cmsUInt32Number channelSize = trueBytesSize(Format);443cmsUInt32Number pixelSize = channelSize * total_chans;444445// Sanity check446if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)447return;448449memset(channels, 0, sizeof(channels));450451// Separation is independent of starting point and only depends on channel size452for (i = 0; i < extra; i++)453ComponentPointerIncrements[i] = pixelSize;454455// Handle do swap456for (i = 0; i < total_chans; i++)457{458if (T_DOSWAP(Format)) {459channels[i] = total_chans - i - 1;460}461else {462channels[i] = i;463}464}465466// Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012467if (T_SWAPFIRST(Format) && total_chans > 1) {468469cmsUInt32Number tmp = channels[0];470for (i = 0; i < total_chans-1; i++)471channels[i] = channels[i + 1];472473channels[total_chans - 1] = tmp;474}475476// Handle size477if (channelSize > 1)478for (i = 0; i < total_chans; i++) {479channels[i] *= channelSize;480}481482for (i = 0; i < extra; i++)483ComponentStartingOrder[i] = channels[i + nchannels];484}485486487488// On planar configurations, the distance is the stride added to any non-negative489static490void ComputeIncrementsForPlanar(cmsUInt32Number Format,491cmsUInt32Number BytesPerPlane,492cmsUInt32Number ComponentStartingOrder[],493cmsUInt32Number ComponentPointerIncrements[])494{495cmsUInt32Number channels[cmsMAXCHANNELS];496cmsUInt32Number extra = T_EXTRA(Format);497cmsUInt32Number nchannels = T_CHANNELS(Format);498cmsUInt32Number total_chans = nchannels + extra;499cmsUInt32Number i;500cmsUInt32Number channelSize = trueBytesSize(Format);501502// Sanity check503if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)504return;505506memset(channels, 0, sizeof(channels));507508// Separation is independent of starting point and only depends on channel size509for (i = 0; i < extra; i++)510ComponentPointerIncrements[i] = channelSize;511512// Handle do swap513for (i = 0; i < total_chans; i++)514{515if (T_DOSWAP(Format)) {516channels[i] = total_chans - i - 1;517}518else {519channels[i] = i;520}521}522523// Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012524if (T_SWAPFIRST(Format) && total_chans > 0) {525526cmsUInt32Number tmp = channels[0];527for (i = 0; i < total_chans - 1; i++)528channels[i] = channels[i + 1];529530channels[total_chans - 1] = tmp;531}532533// Handle size534for (i = 0; i < total_chans; i++) {535channels[i] *= BytesPerPlane;536}537538for (i = 0; i < extra; i++)539ComponentStartingOrder[i] = channels[i + nchannels];540}541542543544// Dispatcher por chunky and planar RGB545static546void ComputeComponentIncrements(cmsUInt32Number Format,547cmsUInt32Number BytesPerPlane,548cmsUInt32Number ComponentStartingOrder[],549cmsUInt32Number ComponentPointerIncrements[])550{551if (T_PLANAR(Format)) {552553ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);554}555else {556ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements);557}558559}560561562563// Handles extra channels copying alpha if requested by the flags564void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,565void* out,566cmsUInt32Number PixelsPerLine,567cmsUInt32Number LineCount,568const cmsStride* Stride)569{570cmsUInt32Number i, j, k;571cmsUInt32Number nExtra;572cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];573cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];574cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];575cmsUInt32Number DestIncrements[cmsMAXCHANNELS];576577cmsFormatterAlphaFn copyValueFn;578579// Make sure we need some copy580if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA))581return;582583// Exit early if in-place color-management is occurring - no need to copy extra channels to themselves.584if (p->InputFormat == p->OutputFormat && in == out)585return;586587// Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time.588nExtra = T_EXTRA(p->InputFormat);589if (nExtra != T_EXTRA(p->OutputFormat))590return;591592// Anything to do?593if (nExtra == 0)594return;595596// Compute the increments597ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements);598ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements);599600// Check for conversions 8, 16, half, float, dbl601copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);602if (copyValueFn == NULL)603return;604605if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly606607cmsUInt8Number* SourcePtr;608cmsUInt8Number* DestPtr;609610cmsUInt32Number SourceStrideIncrement = 0;611cmsUInt32Number DestStrideIncrement = 0;612613// The loop itself614for (i = 0; i < LineCount; i++) {615616// Prepare pointers for the loop617SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement;618DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement;619620for (j = 0; j < PixelsPerLine; j++) {621622copyValueFn(DestPtr, SourcePtr);623624SourcePtr += SourceIncrements[0];625DestPtr += DestIncrements[0];626}627628SourceStrideIncrement += Stride->BytesPerLineIn;629DestStrideIncrement += Stride->BytesPerLineOut;630}631632}633else { // General case with more than one extra channel634635cmsUInt8Number* SourcePtr[cmsMAXCHANNELS];636cmsUInt8Number* DestPtr[cmsMAXCHANNELS];637638cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS];639cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS];640641memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements));642memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements));643644// The loop itself645for (i = 0; i < LineCount; i++) {646647// Prepare pointers for the loop648for (j = 0; j < nExtra; j++) {649650SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j];651DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j];652}653654for (j = 0; j < PixelsPerLine; j++) {655656for (k = 0; k < nExtra; k++) {657658copyValueFn(DestPtr[k], SourcePtr[k]);659660SourcePtr[k] += SourceIncrements[k];661DestPtr[k] += DestIncrements[k];662}663}664665for (j = 0; j < nExtra; j++) {666667SourceStrideIncrements[j] += Stride->BytesPerLineIn;668DestStrideIncrements[j] += Stride->BytesPerLineOut;669}670}671}672}673674675676677