diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt new file mode 100644 index 00000000..6a3e435d --- /dev/null +++ b/library/CMakeLists.txt @@ -0,0 +1,16 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + + +add_subdirectory(src/main/cpp/icc) +add_subdirectory(src/main/cpp/jpeg) +add_subdirectory(src/main/cpp/jbig2) diff --git a/library/build.gradle b/library/build.gradle index cf32ac47..42d6935a 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -18,6 +18,18 @@ android { targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-proguard-rules.txt' + + externalNativeBuild { + cmake{ + abiFilters "armeabi-v7a" ,"arm64-v8a" + } + } + } + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } } buildTypes { diff --git a/library/src/main/assets/com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc b/library/src/main/assets/com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc new file mode 100644 index 00000000..71faa91f Binary files /dev/null and b/library/src/main/assets/com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc differ diff --git a/library/src/main/cpp/icc/CMakeLists.txt b/library/src/main/cpp/icc/CMakeLists.txt new file mode 100644 index 00000000..0bdf690f --- /dev/null +++ b/library/src/main/cpp/icc/CMakeLists.txt @@ -0,0 +1,47 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +set(TARGET iccUse) +set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/ + # opencv/include +) + +#add_library(libopencv_java4 SHARED IMPORTED) +#set_target_properties(libopencv_java4 PROPERTIES IMPORTED_LOCATION +# ${CMAKE_CURRENT_SOURCE_DIR}/opencv/${ANDROID_ABI}/libopencv_java4.so) + + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +aux_source_directory(${SRC_DIR} DIR_LIB_SOURCE) + +add_library(${TARGET} SHARED ${DIR_LIB_SOURCE}) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +target_link_libraries(${TARGET} log android) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +#if(${ANDROID_ABI} STREQUAL x86 OR ${ANDROID_ABI} STREQUAL x86_64) +#target_link_libraries(${TARGET} opencv_imgproc opencv_core ippiw ippicv ittnotify tbb cpufeatures) +#else() +#target_link_libraries(${TARGET}) +#endif() + diff --git a/library/src/main/cpp/icc/IccApplyBPC.cpp b/library/src/main/cpp/icc/IccApplyBPC.cpp new file mode 100644 index 00000000..9da173e6 --- /dev/null +++ b/library/src/main/cpp/icc/IccApplyBPC.cpp @@ -0,0 +1,621 @@ +/** @file +File: IccApplyBPC.cpp + +Contains: Implementation of Black Point Compensation calculations. + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2003-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Rohit Patil 12-10-2008 +// +////////////////////////////////////////////////////////////////////// + +#include "IccApplyBPC.h" +#include + +#define IsSpacePCS(x) ((x)==icSigXYZData || (x)==icSigLabData) + +/** +************************************************************************** +* Name: CIccApplyBPCHint::GetNewAdjustPCSXform +* +* Purpose: +* Returns a new CIccApplyBPC object. Returned object should be deleted +* by the caller. +* +************************************************************************** +*/ +IIccAdjustPCSXform* CIccApplyBPCHint::GetNewAdjustPCSXform() const +{ + return new CIccApplyBPC(); +} + +////////////////////////////////////////////////////////////////////// +// CIccApplyBPC utility functions +////////////////////////////////////////////////////////////////////// + +// converts lab to pcs +void CIccApplyBPC::lab2pcs(icFloatNumber* pixel, const CIccProfile* pProfile) const +{ + switch (pProfile->m_Header.pcs) + { + case icSigLabData: + icLabToPcs(pixel); + break; + + case icSigXYZData: + icLabtoXYZ(pixel); + icXyzToPcs(pixel); + break; + + default: + break; + } +} + +// converts pcs to lab +void CIccApplyBPC::pcs2lab(icFloatNumber* pixel, const CIccProfile* pProfile) const +{ + switch (pProfile->m_Header.pcs) + { + case icSigLabData: + icLabFromPcs(pixel); + break; + + case icSigXYZData: + icXyzFromPcs(pixel); + icXYZtoLab(pixel); + break; + + default: + break; + } +} + +// calculates sum of product of x^j and y^k polynomials +icFloatNumber CIccApplyBPC::calcsum(icFloatNumber* x, icFloatNumber* y, int n, int j, int k) const +{ + icFloatNumber dSum = 0.0; + + int i; + if (j && k) { + for (i=0; i2) { // need at least three points to solve three linear equations + icFloatNumber s00, s10, s20, s30, s40, s01, s11, s21, denom; + s00 = calcsum(x, y, n, 0, 0); + s10 = calcsum(x, y, n, 1, 0); + s20 = calcsum(x, y, n, 2, 0); + s30 = calcsum(x, y, n, 3, 0); + s40 = calcsum(x, y, n, 4, 0); + s01 = calcsum(x, y, n, 0, 1); + s11 = calcsum(x, y, n, 1, 1); + s21 = calcsum(x, y, n, 2, 1); + denom = (icFloatNumber)(s00*s20*s40 - s10*s10*s40 - s00*s30*s30 + 2.0*s10*s20*s30 - s20*s20*s20); + if (fabs(denom)>0.0) { + // t and u are the coefficients of the quadratic equation y = tx^2 + ux + c + // the three equations with 3 unknowns can be written as + // [s40 s30 s20][t] [s21] + // [s30 s20 s10][u] = [s11] + // [s20 s10 s00][c] [s01] + icFloatNumber t = (s01*s10*s30 - s11*s00*s30 - s01*s20*s20 + s11*s10*s20 + s21*s00*s20 - s21*s10*s10)/denom; + + icFloatNumber u = (s11*s00*s40 - s01*s10*s40 + s01*s20*s30 - s21*s00*s30 - s11*s20*s20 + s21*s10*s20)/denom; + + icFloatNumber c = (s01*s20*s40 - s11*s10*s40 - s01*s30*s30 + s11*s20*s30 + s21*s10*s30 - s21*s20*s20)/denom; + + // vertex is (-u + sqrt(u^2 - 4tc))/2t + vert = (icFloatNumber)((-1.0 * u + sqrt(u*u - 4*t*c)) / (2.0 * t)); + } + } + + return vert; +} + +/** +************************************************************************** +* Name: CIccApplyBPC::CalculateFactors +* +* Purpose: +* This function does the suitable calculations to setup black point +* compensation. +* +* Args: +* pXform = pointer to the Xform object that calls this function +* +* Return: +* true = all calculations done +* false = an error occurred +************************************************************************** +*/ +bool CIccApplyBPC::CalcFactors(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* Scale, icFloatNumber* Offset) const +{ + if (!pProfile || !pXform) + return false; + + if (pXform->GetIntent()==icAbsoluteColorimetric) { // black point compensation not supported + return false; + } + + switch (pProfile->m_Header.deviceClass) + { // These profile classes not supported + case icSigLinkClass: + case icSigAbstractClass: + //case icSigColorSpaceClass: + case icSigNamedColorClass: + return false; + default: + break; + } + + icFloatNumber XYZbp[3]; // storage for black point XYZ + + // calculate the black point + if (!calcBlackPoint(pProfile, pXform, XYZbp)) { + return false; + } + + // calculate the scale and offset + if (pXform->IsInput()) { // use PRM black as destination black + Scale[0] = (icFloatNumber)((1.0 - icPerceptualRefBlackY)/(1.0 - XYZbp[1])); + } + else { // use PRM black as source black + Scale[0] = (icFloatNumber)((1.0 - XYZbp[1])/(1.0 - icPerceptualRefBlackY)); + } + + Scale[1] = Scale[0]; + Scale[2] = Scale[0]; + + Offset[0] = (icFloatNumber)((1.0 - Scale[0]) * icPerceptualRefWhiteX); + Offset[1] = (icFloatNumber)((1.0 - Scale[1]) * icPerceptualRefWhiteY); + Offset[2] = (icFloatNumber)((1.0 - Scale[2]) * icPerceptualRefWhiteZ); + + icXyzToPcs(Offset); + + return true; +} + +/** +************************************************************************** +* Name: CIccApplyBPC::calcBlackPoint +* +* Purpose: +* Calculates the black point of a profile +* +************************************************************************** +*/ +bool CIccApplyBPC::calcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const +{ + if (pXform->IsInput()) { // profile used as input/source profile + return calcSrcBlackPoint(pProfile, pXform, XYZb); + } + else { // profile used as output profile + return calcDstBlackPoint(pProfile, pXform, XYZb); + } + + return true; +} + +/** +************************************************************************** +* Name: CIccApplyBPC::calcSrcBlackPoint +* +* Purpose: +* Calculates the black point of a source profile +* +************************************************************************** +*/ +bool CIccApplyBPC::calcSrcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const +{ + icFloatNumber Pixel[16]; + if ((pProfile->m_Header.colorSpace == icSigCmykData) && (pProfile->m_Header.deviceClass == icSigOutputClass)) { + + // calculate intermediate CMYK + XYZb[0] = XYZb[1] = XYZb[2] = 0.0; + + // convert the Lab of 0,0,0 to relevant PCS + lab2pcs(XYZb, pProfile); + + //convert the PCS value to CMYK + if (!pixelXfm(Pixel, XYZb, pProfile->m_Header.pcs, icPerceptual, pProfile)) { + return false; + } + } + else { + switch (pProfile->m_Header.colorSpace) { + case icSigRgbData: + Pixel[0] = 0.0; + Pixel[1] = 0.0; + Pixel[2] = 0.0; + break; + + case icSigGrayData: + Pixel[0] = 0.0; + break; + + case icSigCmykData: + case icSigCmyData: + case icSig2colorData: + case icSig3colorData: + case icSig4colorData: + case icSig5colorData: + case icSig6colorData: + case icSig7colorData: + case icSig8colorData: + case icSig9colorData: + case icSig10colorData: + case icSig11colorData: + case icSig12colorData: + case icSig13colorData: + case icSig14colorData: + case icSig15colorData: + { + icUInt32Number nSamples = icGetSpaceSamples(pProfile->m_Header.colorSpace); + for (icUInt32Number i=0; im_Header.colorSpace, pXform->GetIntent(), pProfile)) { + return false; + } + + // convert PCS to Lab + pcs2lab(XYZb, pProfile); + + // set a* b* to zero for cmyk profiles + if (pProfile->m_Header.colorSpace == icSigCmykData) { + XYZb[1] = XYZb[2] = 0.0; + } + + // clip L* to 50 + if (XYZb[0]>50.0) { + XYZb[0] = 50.0; + } + + // convert Lab to XYZ + icLabtoXYZ(XYZb); + return true; +} + +/** +************************************************************************** +* Name: CIccApplyBPC::calcDstBlackPoint +* +* Purpose: +* Calculates the black point of a destination profile +* +************************************************************************** +*/ +bool CIccApplyBPC::calcDstBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const +{ + icRenderingIntent nIntent = pXform->GetIntent(); + icFloatNumber Pixel[3]; + icFloatNumber pcsPixel[3]; + + // check if the profile is lut based gray, rgb or cmyk + if (pProfile->IsTagPresent(icSigBToA0Tag) && + (pProfile->m_Header.colorSpace==icSigGrayData || pProfile->m_Header.colorSpace==icSigRgbData || pProfile->m_Header.colorSpace==icSigCmykData)) + { // do the complicated and lengthy black point estimation + + // get the black transform + CIccCmm* pCmm = getBlackXfm(nIntent, pProfile); + if (!pCmm) { + return false; + } + + // set the initial Lab + icFloatNumber iniLab[3] = {0.0, 0.0, 0.0}; + + // calculate minL + pcsPixel[0] = 0.0; + pcsPixel[1] = iniLab[1]; + pcsPixel[2] = iniLab[2]; + lab2pcs(pcsPixel, pProfile); + if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) { + delete pCmm; + return false; + } + pcs2lab(Pixel, pProfile); + icFloatNumber MinL = Pixel[0]; + + // calculate MaxL + pcsPixel[0] = 100.0; + pcsPixel[1] = iniLab[1]; + pcsPixel[2] = iniLab[2]; + lab2pcs(pcsPixel, pProfile); + if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) { + delete pCmm; + return false; + } + pcs2lab(Pixel, pProfile); + icFloatNumber MaxL = Pixel[0]; + + // check if quadratic estimation needs to be done + bool bStraightMidRange = false; + + // if the intent is relative + if (nIntent==icRelativeColorimetric) + { + // calculate initial Lab as source black point + if (!calcSrcBlackPoint(pProfile, pXform, iniLab)) { + delete pCmm; + return false; + } + + // convert the XYZ to lab + icXYZtoLab(iniLab); + + // check mid range L* values + icFloatNumber lcnt=0.0, roundtripL; + bStraightMidRange = true; + while (lcnt<100.1) + { + pcsPixel[0] = icFloatNumber(lcnt); + pcsPixel[1] = iniLab[1]; + pcsPixel[2] = iniLab[2]; + lab2pcs(pcsPixel, pProfile); + if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) { + delete pCmm; + return false; + } + pcs2lab(Pixel, pProfile); + roundtripL = Pixel[0]; + + if (roundtripL>(MinL + 0.2 * (MaxL - MinL))) { + if (fabs(roundtripL - lcnt)>4.0) { + bStraightMidRange = false; + break; + } + } + + lcnt += 1.0; + } + } + + // quadratic estimation is not needed + if (bStraightMidRange) { // initial Lab is the destination black point + XYZb[0] = iniLab[0]; + XYZb[1] = iniLab[1]; + XYZb[2] = iniLab[2]; + icLabtoXYZ(XYZb); + delete pCmm; + return true; + } + + // find the black point using the least squares error quadratic curve fitting + + // calculate y values + icFloatNumber x[101], y[101]; + icFloatNumber lo=0.03f, hi=0.25f; + int i, n; + if (nIntent==icRelativeColorimetric) { + lo = 0.1f; + hi = 0.5f; + } + + for (i=0; i<101; i++) { + x[i] = icFloatNumber(i); + pcsPixel[0] = x[i]; + pcsPixel[1] = iniLab[1]; + pcsPixel[2] = iniLab[2]; + lab2pcs(pcsPixel, pProfile); + if (pCmm->Apply(Pixel, pcsPixel)!=icCmmStatOk) { + delete pCmm; + return false; + } + pcs2lab(Pixel, pProfile); + y[i] = (Pixel[0] - MinL)/(MaxL - MinL); + } + + // check for y values in the range and rearrange + n = 0; + for (i=0; i<101; i++) { + if (y[i]>=lo && y[i] PCS round trip transform, always uses relative intent on the device -> pcs transform +* +************************************************************************** +*/ +CIccCmm* CIccApplyBPC::getBlackXfm(icRenderingIntent nIntent, const CIccProfile *pProfile) const +{ + // create the cmm object + CIccCmm* pCmm = new CIccCmm(pProfile->m_Header.pcs, icSigUnknownData, false); + if (!pCmm) return NULL; + + // first create a copy of the profile because the copy will be owned by the cmm + CIccProfile* pICC1 = new CIccProfile(*pProfile); + if (!pICC1) { + delete pCmm; + return NULL; + } + + // add the xform + if (pCmm->AddXform(pICC1, nIntent, icInterpTetrahedral)!=icCmmStatOk) { + delete pICC1; + delete pCmm; + return NULL; + } + + // create another copy of the profile because the copy will be owned by the cmm + CIccProfile* pICC2 = new CIccProfile(*pProfile); + if (!pICC2) { + delete pCmm; + return NULL; + } + + // add the xform + if (pCmm->AddXform(pICC2, icRelativeColorimetric, icInterpTetrahedral)!=icCmmStatOk) { // uses the relative intent on the device to Lab side + delete pICC2; + delete pCmm; + return NULL; + } + + // get the cmm ready to do transforms + if (pCmm->Begin()!=icCmmStatOk) { + delete pCmm; + return NULL; + } + + return pCmm; +} diff --git a/library/src/main/cpp/icc/IccApplyBPC.h b/library/src/main/cpp/icc/IccApplyBPC.h new file mode 100644 index 00000000..6e82a16a --- /dev/null +++ b/library/src/main/cpp/icc/IccApplyBPC.h @@ -0,0 +1,135 @@ +/** @file +File: IccApplyBPC.h + +Contains: Header file for implementation of Black Point Compensation calculations. + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2003-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Rohit Patil 12-8-2008 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCAPPLYBPC_H) +#define _ICCAPPLYBPC_H + +#include "IccCmm.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** +************************************************************************** +* Type: Class +* +* Purpose: +* Interface and hint for creating a BPC xform object +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyBPCHint : public CIccCreateAdjustPCSXformHint +{ +public: + virtual const char *GetAdjustPCSType() const { return "CIccApplyBPCHint"; } + virtual IIccAdjustPCSXform* GetNewAdjustPCSXform() const; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: This is the hint for applying black point compensation. + * Also does the calculations to setup actual application of BPC. + * + ************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyBPC : public IIccAdjustPCSXform +{ +public: + // virtual IIccAdjustPCSXform functions + // does all the calculations for BPC and returns the scale and offset in the arguments passed + virtual bool CalcFactors(const CIccProfile* pProfile, const CIccXform* pXfm, icFloatNumber* Scale, icFloatNumber* Offset) const; + +private: + // utility functions + void lab2pcs(icFloatNumber* pixel, const CIccProfile* pProfile) const; + void pcs2lab(icFloatNumber* pixel, const CIccProfile* pProfile) const; + icFloatNumber calcsum(icFloatNumber* x, icFloatNumber* y, int n, int j, int k) const; + icFloatNumber calcQuadraticVertex(icFloatNumber* x, icFloatNumber* y, int n) const; + + // worker functions + bool calcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const; + bool calcSrcBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const; + bool calcDstBlackPoint(const CIccProfile* pProfile, const CIccXform* pXform, icFloatNumber* XYZb) const; + + bool pixelXfm(icFloatNumber *DstPixel, icFloatNumber *SrcPixel, icColorSpaceSignature SrcSpace, + icRenderingIntent nIntent, const CIccProfile *pProfile) const; + + // PCS -> PCS round trip transform, always uses relative intent on the device -> pcs transform + CIccCmm* getBlackXfm(icRenderingIntent nIntent, const CIccProfile *pProfile) const; +}; + +#ifdef USESAMPLEICCNAMESPACE +}; //namespace sampleICC +#endif + +#endif // _ICCAPPLYBPC_H + diff --git a/library/src/main/cpp/icc/IccCmm.cpp b/library/src/main/cpp/icc/IccCmm.cpp new file mode 100644 index 00000000..8b639cc9 --- /dev/null +++ b/library/src/main/cpp/icc/IccCmm.cpp @@ -0,0 +1,6158 @@ +/** @file + File: IccCmm.cpp + + Contains: Implementation of the CIccCmm class. + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// -Added support for Monochrome ICC profile apply by Rohit Patil 12-03-2008 +// -Integrated changes for PCS adjustment by George Pawle 12-09-2008 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) +#pragma warning( disable: 4786) //disable warning in +#endif + +#include "IccXformFactory.h" +#include "IccTag.h" +#include "IccIO.h" +#include "IccApplyBPC.h" +#include + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +//// +// Useful Macros +//// + +#define IsSpacePCS(x) ((x)==icSigXYZData || (x)==icSigLabData) +#define IsSpaceCMYK(x) ((x)==icSigCmykData || (x)==icSig4colorData) + +#define IsCompatSpace(x, y) ((x)==(y) || (IsSpacePCS(x) && IsSpacePCS(y)) || (IsSpaceCMYK(x) && IsSpaceCMYK(y))) + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +/** + ************************************************************************** + * Class CIccPCS Constructor + * + * Purpose: + * This is a class constructor. + * + ************************************************************************** + */ +CIccPCS::CIccPCS() +{ + m_bIsV2Lab = false; + m_Space = icSigUnknownData; +} + +/** +************************************************************************** +* Name: CIccPCS::Reset +* +* Purpose: +* This is called with the initial color space and a bool +* argument which is true if the PCS is version 2. +* +* Args: +* Startpsace = Starting Colorspace +* bUseLegacyPCS = legacy PCS flag +************************************************************************** +*/ +void CIccPCS::Reset(icColorSpaceSignature StartSpace, bool bUseLegacyPCS) +{ + m_bIsV2Lab = IsSpacePCS(StartSpace) && bUseLegacyPCS; + m_Space = StartSpace; +} + +/** + ************************************************************************** + * Name: CIccPCS::Check + * + * Purpose: + * This is called before the apply of each profile's xform to adjust the PCS + * to the xform's needed PCS. + * + * Args: + * SrcPixel = source pixel data (this may need adjusting), + * pXform = the xform that who's Apply function will shortly be called + * + * Return: + * SrcPixel or ptr to adjusted pixel data (we dont want to modify the source data). + ************************************************************************** + */ +const icFloatNumber *CIccPCS::Check(const icFloatNumber *SrcPixel, const CIccXform *pXform) +{ + icColorSpaceSignature NextSpace = pXform->GetSrcSpace(); + bool bIsV2 = pXform->UseLegacyPCS(); + bool bIsNextV2Lab = bIsV2 && (NextSpace == icSigLabData); + const icFloatNumber *rv; + bool bNoClip = pXform->NoClipPCS(); + + if (m_bIsV2Lab && !bIsNextV2Lab) { + Lab2ToLab4(m_Convert, SrcPixel, bNoClip); + if (NextSpace==icSigXYZData) { + LabToXyz(m_Convert, m_Convert, bNoClip); + } + rv = m_Convert; + } + else if (!m_bIsV2Lab && bIsNextV2Lab) { + if (m_Space==icSigXYZData) { + XyzToLab(m_Convert, SrcPixel, bNoClip); + SrcPixel = m_Convert; + } + Lab4ToLab2(m_Convert, SrcPixel); + rv = m_Convert; + } + else if (m_Space==NextSpace) { + rv = SrcPixel; + } + else if (m_Space==icSigXYZData && NextSpace==icSigLabData) { + XyzToLab(m_Convert, SrcPixel, bNoClip); + rv = m_Convert; + } + else if (m_Space==icSigLabData && NextSpace==icSigXYZData) { + LabToXyz(m_Convert, SrcPixel, bNoClip); + rv = m_Convert; + } + else { + rv = SrcPixel; + } + + m_Space = pXform->GetDstSpace(); + m_bIsV2Lab = bIsV2 && (m_Space == icSigLabData); + + return rv; +} + +/** + ************************************************************************** + * Name: CIccPCS::CheckLast + * + * Purpose: + * Called after all xforms are applied to adjust PCS to final space if needed + * Note: space will always be V4. + * + * Args: + * Pixel = Pixel data, + * DestSpace = destination color space + * bNoClip = indicates whether PCS should be clipped + ************************************************************************** + */ +void CIccPCS::CheckLast(icFloatNumber *Pixel, icColorSpaceSignature DestSpace, bool bNoClip) +{ + if (m_bIsV2Lab) { + Lab2ToLab4(Pixel, Pixel, bNoClip); + if (DestSpace==icSigXYZData) { + LabToXyz(Pixel, Pixel, bNoClip); + } + } + else if (m_Space==DestSpace) { + return; + } + else if (m_Space==icSigXYZData) { + XyzToLab(Pixel, Pixel, bNoClip); + } + else if (m_Space==icSigLabData) { + LabToXyz(Pixel, Pixel, bNoClip); + } +} + +/** + ************************************************************************** + * Name: CIccPCS::UnitClip + * + * Purpose: + * Convert a double to an icUInt16Number with clipping + ************************************************************************** + */ +icFloatNumber CIccPCS::UnitClip(icFloatNumber v) +{ + if (v<0) + v = 0; + if (v>1.0) + v = 1.0; + + return v; +} + +/** + ************************************************************************** + * Name: CIccPCS::NegClip + * + * Purpose: + * Convert a double to an icUInt16Number with clipping of negative numbers + ************************************************************************** + */ +icFloatNumber CIccPCS::NegClip(icFloatNumber v) +{ + if (v<0) + v=0; + + return v; +} + +/** + ************************************************************************** + * Name: CIccPCS::LabToXyz + * + * Purpose: + * Convert Lab to XYZ + ************************************************************************** + */ +void CIccPCS::LabToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) +{ + icFloatNumber Lab[3]; + + memcpy(&Lab,Src,sizeof(Lab)); + + icLabFromPcs(Lab); + + icLabtoXYZ(Lab); + + icXyzToPcs(Lab); + + if (!bNoClip) { + Dst[0] = UnitClip(Lab[0]); + Dst[1] = UnitClip(Lab[1]); + Dst[2] = UnitClip(Lab[2]); + } + else { + Dst[0] = Lab[0]; + Dst[1] = Lab[1]; + Dst[2] = Lab[2]; + } +} + + +/** + ************************************************************************** + * Name: CIccPCS::XyzToLab + * + * Purpose: + * Convert XYZ to Lab + ************************************************************************** + */ +void CIccPCS::XyzToLab(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) +{ + icFloatNumber XYZ[3]; + + + if (!bNoClip) { + XYZ[0] = UnitClip(Src[0]); + XYZ[1] = UnitClip(Src[1]); + XYZ[2] = UnitClip(Src[2]); + } + else { + XYZ[0] = Src[0]; + XYZ[1] = Src[1]; + XYZ[2] = Src[2]; + } + + icXyzFromPcs(XYZ); + + icXYZtoLab(XYZ); + + icLabToPcs(XYZ); + + if (!bNoClip) { + Dst[0] = UnitClip(XYZ[0]); + Dst[1] = UnitClip(XYZ[1]); + Dst[2] = UnitClip(XYZ[2]); + } + else { + Dst[0] = XYZ[0]; + Dst[1] = XYZ[1]; + Dst[2] = XYZ[2]; + } +} + + +/** + ************************************************************************** + * Name: CIccPCS::Lab2ToXyz + * + * Purpose: + * Convert version 2 Lab to XYZ + ************************************************************************** + */ +void CIccPCS::Lab2ToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) +{ + Lab2ToLab4(Dst, Src, bNoClip); + LabToXyz(Dst, Dst, bNoClip); +} + + +/** + ************************************************************************** + * Name: CIccPCS::XyzToLab2 + * + * Purpose: + * Convert XYZ to version 2 Lab + ************************************************************************** + */ +void CIccPCS::XyzToLab2(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) +{ + XyzToLab(Dst, Src, bNoClip); + Lab4ToLab2(Dst, Dst); +} + + +/** + ************************************************************************** + * Name: CIccPCS::Lab2ToLab4 + * + * Purpose: + * Convert version 2 Lab to version 4 Lab + ************************************************************************** + */ +void CIccPCS::Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) +{ + if (bNoClip) { + Dst[0] = (icFloatNumber)(Src[0] * 65535.0f / 65280.0f); + Dst[1] = (icFloatNumber)(Src[1] * 65535.0f / 65280.0f); + Dst[2] = (icFloatNumber)(Src[2] * 65535.0f / 65280.0f); + } + else { + Dst[0] = UnitClip((icFloatNumber)(Src[0] * 65535.0f / 65280.0f)); + Dst[1] = UnitClip((icFloatNumber)(Src[1] * 65535.0f / 65280.0f)); + Dst[2] = UnitClip((icFloatNumber)(Src[2] * 65535.0f / 65280.0f)); + } +} + +/** + ************************************************************************** + * Name: CIccPCS::Lab4ToLab2 + * + * Purpose: + * Convert version 4 Lab to version 2 Lab + ************************************************************************** + */ +void CIccPCS::Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src) +{ + Dst[0] = (icFloatNumber)(Src[0] * 65280.0f / 65535.0f); + Dst[1] = (icFloatNumber)(Src[1] * 65280.0f / 65535.0f); + Dst[2] = (icFloatNumber)(Src[2] * 65280.0f / 65535.0f); +} + +/** +************************************************************************** +* Name: CIccCreateXformHintManager::CIccCreateXformHintManager +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccCreateXformHintManager::~CIccCreateXformHintManager() +{ + if (m_pList) { + IIccCreateXformHintList::iterator i; + + for (i=m_pList->begin(); i!=m_pList->end(); i++) { + if (i->ptr) + delete i->ptr; + } + + delete m_pList; + } +} + +/** +************************************************************************** +* Name: CIccCreateXformHintManager::AddHint +* +* Purpose: +* Adds and owns the passed named hint to it's list. +* +* Args: +* pHint = pointer to the hint object to be added +* +* Return: +* true = hint added to the list +* false = hint not added +************************************************************************** +*/ +bool CIccCreateXformHintManager::AddHint(IIccCreateXformHint* pHint) +{ + if (!m_pList) { + m_pList = new IIccCreateXformHintList; + } + + if (pHint) { + if (GetHint(pHint->GetHintType())) { + delete pHint; + return false; + } + IIccCreateXformHintPtr Hint; + Hint.ptr = pHint; + m_pList->push_back(Hint); + return true; + } + + return false; +} + +/** +************************************************************************** +* Name: CIccCreateXformHintManager::DeleteHint +* +* Purpose: +* Deletes the object referenced by the passed named hint pointer +* and removes it from the list. +* +* Args: +* pHint = pointer to the hint object to be deleted +* +* Return: +* true = hint found and deleted +* false = hint not found +************************************************************************** +*/ +bool CIccCreateXformHintManager::DeleteHint(IIccCreateXformHint* pHint) +{ + if (m_pList && pHint) { + IIccCreateXformHintList::iterator i; + for (i=m_pList->begin(); i!=m_pList->end(); i++) { + if (i->ptr) { + if (i->ptr == pHint) { + delete pHint; + pHint = NULL; + m_pList->erase(i); + return true; + } + } + } + } + + return false; +} + +/** +************************************************************************** +* Name: CIccCreateXformHintManager::GetHint +* +* Purpose: +* Finds and returns a pointer to the named hint. +* +* Args: +* hintName = name of the desired hint +* +* Return: +* Appropriate IIccCreateXformHint pointer +************************************************************************** +*/ +IIccCreateXformHint* CIccCreateXformHintManager::GetHint(const char* hintName) +{ + IIccCreateXformHint* pHint=NULL; + + if (m_pList) { + IIccCreateXformHintList::iterator i; + for (i=m_pList->begin(); i!=m_pList->end(); i++) { + if (i->ptr) { + if (!strcmp(i->ptr->GetHintType(), hintName)) { + pHint = i->ptr; + break; + } + } + } + } + + return pHint; +} + +/** + ************************************************************************** + * Name: CIccXform::CIccXform + * + * Purpose: + * Constructor + ************************************************************************** + */ +CIccXform::CIccXform() +{ + m_pProfile = NULL; + m_bInput = true; + m_nIntent = icUnknownIntent; + m_pAdjustPCS = NULL; + m_bAdjustPCS = false; +} + + +/** + ************************************************************************** + * Name: CIccXform::~CIccXform + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccXform::~CIccXform() +{ + if (m_pProfile) + delete m_pProfile; + + if (m_pAdjustPCS) { + delete m_pAdjustPCS; + } + +} + + +/** + ************************************************************************** + * Name: CIccXform::Create + * + * Purpose: + * This is a static Creation function that creates derived CIccXform objects and + * initializes them. + * + * Args: + * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will + * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile + * object needs to be allocated on the heap. + * bInput = flag to indicate whether to use the input or output side of the profile, + * nIntent = the rendering intent to apply to the profile, + * nInterp = the interpolation algorithm to use for N-D luts. + * nLutType = selection of which transform lut to use + * bUseMpeTags = flag to indicate the use MPE flags if available + * pHintManager = pointer to object that contains xform creation hints + * + * Return: + * A suitable pXform object + ************************************************************************** + */ +CIccXform *CIccXform::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */, + icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */, + bool bUseMpeTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */) +{ + CIccXform *rv = NULL; + icRenderingIntent nTagIntent = nIntent; + + if (pProfile->m_Header.deviceClass==icSigLinkClass && nIntent==icAbsoluteColorimetric) { + nIntent = icPerceptual; + } + + if (nTagIntent == icUnknownIntent) + nTagIntent = icPerceptual; + + switch (nLutType) { + case icXformLutColor: + if (bInput) { + CIccTag *pTag = NULL; + if (bUseMpeTags) { + pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); + + if (!pTag && nTagIntent ==icAbsoluteColorimetric) { + pTag = pProfile->FindTag(icSigDToB1Tag); + if (pTag) + nTagIntent = icRelativeColorimetric; + } + + //Apparently Using DtoB0 is not prescribed here by the ICC Specification + //if (!pTag) { + // pTag = pProfile->FindTag(icSigDToB0Tag); + //} + + //Unsupported elements cause fall back behavior + if (pTag && !pTag->IsSupported()) + pTag = NULL; + } + + if (!pTag) { + if (nTagIntent == icAbsoluteColorimetric) + nTagIntent = icRelativeColorimetric; + pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent); + } + + if (!pTag) { + pTag = pProfile->FindTag(icSigAToB0Tag); + } + + if (!pTag) { + if (pProfile->m_Header.colorSpace == icSigRgbData) { + rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, NULL, pHintManager); + } + else if (pProfile->m_Header.colorSpace == icSigGrayData) { + rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL, pHintManager); + } + else + return NULL; + } + else if (pTag->GetType()==icSigMultiProcessElementType) { + rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); + } + else { + switch(pProfile->m_Header.colorSpace) { + case icSigXYZData: + case icSigLabData: + case icSigLuvData: + case icSigYCbCrData: + case icSigYxyData: + case icSigRgbData: + case icSigHsvData: + case icSigHlsData: + case icSigCmyData: + case icSig3colorData: + rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); + break; + + case icSigCmykData: + case icSig4colorData: + rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager); + break; + + default: + rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager); + break; + } + } + } + else { + CIccTag *pTag = NULL; + + if (bUseMpeTags) { + pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent); + + if (!pTag && nTagIntent ==icAbsoluteColorimetric) { + pTag = pProfile->FindTag(icSigBToD1Tag); + if (pTag) + nTagIntent = icRelativeColorimetric; + } + + //Apparently Using BtoD0 is not prescribed here by the ICC Specification + //if (!pTag) { + // pTag = pProfile->FindTag(icSigBToD0Tag); + //} + + //Unsupported elements cause fall back behavior + if (pTag && !pTag->IsSupported()) + pTag = NULL; + } + + if (!pTag) { + if (nTagIntent == icAbsoluteColorimetric) + nTagIntent = icRelativeColorimetric; + pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent); + } + + if (!pTag) { + pTag = pProfile->FindTag(icSigBToA0Tag); + } + + if (!pTag) { + if (pProfile->m_Header.colorSpace == icSigRgbData) { + rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, pTag, pHintManager); + } + else if (pProfile->m_Header.colorSpace == icSigGrayData) { + rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL, pHintManager); + } + else + return NULL; + } + else if (pTag->GetType()==icSigMultiProcessElementType) { + rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); + } + else { + switch(pProfile->m_Header.pcs) { + case icSigXYZData: + case icSigLabData: + rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); + break; + + default: + break; + } + } + } + break; + + case icXformLutNamedColor: + { + CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); + if (!pTag) + return NULL; + + CIccCreateNamedColorXformHint* pNamedColorHint = new CIccCreateNamedColorXformHint(); + pNamedColorHint->csPcs = pProfile->m_Header.pcs; + pNamedColorHint->csDevice = pProfile->m_Header.colorSpace; + if (pHintManager) { + pHintManager->AddHint(pNamedColorHint); + rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, pHintManager); + pHintManager->DeleteHint(pNamedColorHint); + } + else { + CIccCreateXformHintManager HintManager; + HintManager.AddHint(pNamedColorHint); + rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, &HintManager); + } + } + break; + + case icXformLutPreview: + { + bInput = false; + CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent); + if (!pTag) { + pTag = pProfile->FindTag(icSigPreview0Tag); + } + if (!pTag) { + return NULL; + } + else { + switch(pProfile->m_Header.pcs) { + case icSigXYZData: + case icSigLabData: + rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); + + default: + break; + } + } + } + break; + + case icXformLutGamut: + { + bInput = false; + CIccTag *pTag = pProfile->FindTag(icSigGamutTag); + if (!pTag) { + return NULL; + } + else { + switch(pProfile->m_Header.pcs) { + case icSigXYZData: + case icSigLabData: + rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); + + default: + break; + } + } + } + break; + } + + if (rv) { + rv->SetParams(pProfile, bInput, nIntent, nInterp, pHintManager); + } + + return rv; +} + +/** + ****************************************************************************** + * Name: CIccXform::SetParams + * + * Purpose: + * This is an accessor function to set private values. + * + * Args: + * pProfile = pointer to profile associated with transform + * bInput = indicates whether profile is input profile + * nIntent = rendering intent to apply to the profile + * nInterp = the interpolation algorithm to use for N-D luts + ******************************************************************************/ +void CIccXform::SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent, + icXformInterp nInterp, CIccCreateXformHintManager *pHintManager/* =NULL */) +{ + m_pProfile = pProfile; + m_bInput = bInput; + m_nIntent = nIntent; + m_nInterp = nInterp; + m_pAdjustPCS = NULL; + + IIccCreateXformHint *pHint=NULL; + if (pHintManager && (pHint = pHintManager->GetHint("CIccCreateAdjustPCSXformHint"))){ + CIccCreateAdjustPCSXformHint *pAdjustPCSHint = (CIccCreateAdjustPCSXformHint*)pHint; + m_pAdjustPCS = pAdjustPCSHint->GetNewAdjustPCSXform(); + } +} + +/** + ************************************************************************** + * Name: CIccXform::Create + * + * Purpose: + * This is a static Creation function that creates derived CIccXform objects and + * initializes them. + * + * Args: + * Profile = reference to a CIccProfile object that will be used to create the transform. + * A copy of the CIccProfile object will be created and passed to the pointer based Create(). + * The copied object will be destroyed when the returned CIccXform object is destroyed. + * bInput = flag to indicate whether to use the input or output side of the profile, + * nIntent = the rendering intent to apply to the profile, + * nInterp = the interpolation algorithm to use for N-D luts. + * nLutType = selection of which transform lut to use + * bUseMpeTags = flag to indicate the use MPE flags if available + * pHint = pointer to object passed to CIccXform creation functionality + * + * Return: + * A suitable pXform object + ************************************************************************** + */ +CIccXform *CIccXform::Create(CIccProfile &Profile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */, + icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */, + bool bUseMpeTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */) +{ + CIccProfile *pProfile = new CIccProfile(Profile); + CIccXform *pXform = Create(pProfile, bInput, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (!pXform) + delete pProfile; + + return pXform; +} + + +/** + ************************************************************************** + * Name: CIccXform::Begin + * + * Purpose: + * This function will be called before the xform is applied. Derived objects + * should also call this base class function to initialize for Absolute Colorimetric + * Intent handling which is performed through the use of the CheckSrcAbs and + * CheckDstAbs functions. + ************************************************************************** + */ +icStatusCMM CIccXform::Begin() +{ + if (m_nIntent==icAbsoluteColorimetric) { + CIccTag *pTag = m_pProfile->FindTag(icSigMediaWhitePointTag); + + if (!pTag || pTag->GetType()!=icSigXYZType) + return icCmmStatInvalidProfile; + + CIccTagXYZ *pXyzTag = (CIccTagXYZ*)pTag; + + m_MediaXYZ = (*pXyzTag)[0]; + } + + // set up for any needed PCS adjustment + if (m_nIntent == icAbsoluteColorimetric && + (m_MediaXYZ.X != m_pProfile->m_Header.illuminant.X || + m_MediaXYZ.Y != m_pProfile->m_Header.illuminant.Y || + m_MediaXYZ.Z != m_pProfile->m_Header.illuminant.Z)) { + + icColorSpaceSignature Space = m_pProfile->m_Header.pcs; + + if (IsSpacePCS(Space)) { + m_bAdjustPCS = true; // turn ON PCS adjustment + + // scale factors depend upon media white point + // set up for input transform + m_PCSScale[0] = (icFloatNumber) m_MediaXYZ.X / m_pProfile->m_Header.illuminant.X; // convert to icFloat to avoid precision errors + m_PCSScale[1] = (icFloatNumber) m_MediaXYZ.Y / m_pProfile->m_Header.illuminant.Y; + m_PCSScale[2] = (icFloatNumber) m_MediaXYZ.Z / m_pProfile->m_Header.illuminant.Z; + + if (!m_bInput) { + m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // inverse for output transform + m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1]; + m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2]; + } + + m_PCSOffset[0] = 0.0; + m_PCSOffset[1] = 0.0; + m_PCSOffset[2] = 0.0; + } + } + else if (m_nIntent == icPerceptual && (IsVersion2() || !HasPerceptualHandling())) { + icColorSpaceSignature Space = m_pProfile->m_Header.pcs; + + if (IsSpacePCS(Space) && m_pProfile->m_Header.deviceClass!=icSigAbstractClass) { + m_bAdjustPCS = true; // turn ON PCS adjustment + + // set up for input transform, which needs version 2 black point to version 4 + m_PCSScale[0] = (icFloatNumber) (1.0 - icPerceptualRefBlackX / icPerceptualRefWhiteX); // scale factors + m_PCSScale[1] = (icFloatNumber) (1.0 - icPerceptualRefBlackY / icPerceptualRefWhiteY); + m_PCSScale[2] = (icFloatNumber) (1.0 - icPerceptualRefBlackZ / icPerceptualRefWhiteZ); + + m_PCSOffset[0] = (icFloatNumber) (icPerceptualRefBlackX * 32768.0 / 65535.0); // offset factors + m_PCSOffset[1] = (icFloatNumber) (icPerceptualRefBlackY * 32768.0 / 65535.0); + m_PCSOffset[2] = (icFloatNumber) (icPerceptualRefBlackZ * 32768.0 / 65535.0); + + if (!m_bInput) { // output transform must convert version 4 black point to version 2 + m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // invert scale factors + m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1]; + m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2]; + + m_PCSOffset[0] = - m_PCSOffset[0] * m_PCSScale[0]; // negate offset factors + m_PCSOffset[1] = - m_PCSOffset[1] * m_PCSScale[1]; + m_PCSOffset[2] = - m_PCSOffset[2] * m_PCSScale[2]; + } + } + } + + + if (m_pAdjustPCS) { + CIccProfile ProfileCopy(*m_pProfile); + + // need to read in all the tags, so that a copy of the profile can be made + if (!ProfileCopy.ReadTags(m_pProfile)) { + return icCmmStatInvalidProfile; + } + + if (!m_pAdjustPCS->CalcFactors(&ProfileCopy, this, m_PCSScale, m_PCSOffset)) { + return icCmmStatIncorrectApply; + } + + m_bAdjustPCS = true; + delete m_pAdjustPCS; + m_pAdjustPCS = NULL; + } + + return icCmmStatOk; +} + +/** +************************************************************************** +* Name: CIccXform::GetNewApply +* +* Purpose: +* This Factory function allocates data specific for the application of the xform. +* This allows multiple threads to simultaneously use the same xform. +************************************************************************** +*/ +CIccApplyXform *CIccXform::GetNewApply(icStatusCMM &status) +{ + CIccApplyXform *rv = new CIccApplyXform(this); + + if (!rv) { + status = icCmmStatAllocErr; + return NULL; + } + + status = icCmmStatOk; + return rv; +} + +/** + ************************************************************************** +* Name: CIccXform::AdjustPCS + * + * Purpose: +* This function will take care of any PCS adjustments +* needed by the xform (the PCS is always version 4 relative). + * + * Args: +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. + * + ************************************************************************** + */ +void CIccXform::AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + icColorSpaceSignature Space = m_pProfile->m_Header.pcs; + + if (Space==icSigLabData) { + if (UseLegacyPCS()) { + CIccPCS::Lab2ToXyz(DstPixel, SrcPixel, true); + } + else { + CIccPCS::LabToXyz(DstPixel, SrcPixel, true); + } + } + else { + DstPixel[0] = SrcPixel[0]; + DstPixel[1] = SrcPixel[1]; + DstPixel[2] = SrcPixel[2]; + } + + DstPixel[0] = (icFloatNumber)(DstPixel[0] * m_PCSScale[0] + m_PCSOffset[0]); + DstPixel[1] = (icFloatNumber)(DstPixel[1] * m_PCSScale[1] + m_PCSOffset[1]); + DstPixel[2] = (icFloatNumber)(DstPixel[2] * m_PCSScale[2] + m_PCSOffset[2]); + + if (Space==icSigLabData) { + if (UseLegacyPCS()) { + CIccPCS::XyzToLab2(DstPixel, DstPixel, true); + } + else { + CIccPCS::XyzToLab(DstPixel, DstPixel, true); + } + } +#ifndef SAMPLEICC_NOCLIPLABTOXYZ + else { + DstPixel[0] = CIccPCS::NegClip(DstPixel[0]); + DstPixel[1] = CIccPCS::NegClip(DstPixel[1]); + DstPixel[2] = CIccPCS::NegClip(DstPixel[2]); + } +#endif +} + +/** + ************************************************************************** + * Name: CIccXform::CheckSrcAbs + * + * Purpose: + * This function will be called by a derived CIccXform object's Apply() function + * BEFORE the actual xform is performed to take care of Absolute to Relative + * adjustments needed by the xform (IE the PCS is always version 4 relative). + * + * Args: + * Pixel = src pixel data (will not be modified) + * + * Return: + * returns Pixel or adjusted pixel data. + ************************************************************************** + */ +const icFloatNumber *CIccXform::CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const +{ + icFloatNumber *pAbsLab = pApply->m_AbsLab; + if (m_bAdjustPCS && !m_bInput) { + AdjustPCS(pAbsLab, Pixel); + return pAbsLab; + } + + return Pixel; +} + +/** + ************************************************************************** + * Name: CIccXform::CheckDstAbs + * + * Purpose: + * This function will be called by a derived CIccXform object's Apply() function + * AFTER the actual xform is performed to take care of Absolute to Relative + * adjustments needed by the xform (IE the PCS is always version 4 relative). + * + * Args: + * Pixel = source pixel data which will be modified + * + ************************************************************************** + */ +void CIccXform::CheckDstAbs(icFloatNumber *Pixel) const +{ + if (m_bAdjustPCS && m_bInput) { + AdjustPCS(Pixel, Pixel); + } + } + +/** +************************************************************************** +* Name: CIccXformMatrixTRC::GetSrcSpace +* +* Purpose: +* Return the color space that is input to the transform. +* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid +* confusion with PCS encoding of these spaces. Device encoding of XYZ +* and Lab spaces left to the device. +************************************************************************** +*/ +icColorSpaceSignature CIccXform::GetSrcSpace() const +{ + icColorSpaceSignature rv; + icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass; + + if (m_bInput) { + rv = m_pProfile->m_Header.colorSpace; + + if (deviceClass != icSigAbstractClass) { + //convert signature to device colorspace signature (avoid confusion about encoding). + if (rv==icSigXYZData) { + rv = icSigDevXYZData; + } + else if (rv==icSigLabData) { + rv = icSigDevLabData; + } + } + } + else { + rv = m_pProfile->m_Header.pcs; + } + + return rv; +} + +/** +************************************************************************** +* Name: CIccXformMatrixTRC::GetDstSpace +* +* Purpose: +* Return the color space that is output by the transform. +* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid +* confusion with PCS encoding of these spaces. Device encoding of XYZ +* and Lab spaces left to the device. +************************************************************************** +*/ +icColorSpaceSignature CIccXform::GetDstSpace() const +{ + icColorSpaceSignature rv; + icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass; + + if (m_bInput) { + rv = m_pProfile->m_Header.pcs; + } + else { + rv = m_pProfile->m_Header.colorSpace; + + //convert signature to device colorspace signature (avoid confusion about encoding). + if (deviceClass != icSigAbstractClass) { + if (rv==icSigXYZData) { + rv = icSigDevXYZData; + } + else if (rv==icSigLabData) { + rv = icSigDevLabData; + } + } + } + + return rv; +} + +/** +************************************************************************** +* Name: CIccApplyXform::CIccApplyXform +* +* Purpose: +* Constructor +************************************************************************** +*/ +CIccApplyXform::CIccApplyXform(CIccXform *pXform) +{ + m_pXform = pXform; +} + +/** +************************************************************************** +* Name: CIccApplyXform::CIccApplyXform +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccApplyXform::~CIccApplyXform() +{ +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::CIccXformMonochrome +* +* Purpose: +* Constructor +************************************************************************** +*/ +CIccXformMonochrome::CIccXformMonochrome() +{ + m_Curve = NULL; + m_ApplyCurvePtr = NULL; + m_bFreeCurve = false; +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::~CIccXformMonochrome +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccXformMonochrome::~CIccXformMonochrome() +{ + if (m_bFreeCurve && m_Curve) { + delete m_Curve; + } +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::Begin +* +* Purpose: +* Does the initialization of the Xform before Apply() is called. +* Must be called before Apply(). +* +************************************************************************** +*/ +icStatusCMM CIccXformMonochrome::Begin() +{ + icStatusCMM status; + + status = CIccXform::Begin(); + if (status != icCmmStatOk) + return status; + + m_ApplyCurvePtr = NULL; + + if (m_bInput) { + m_Curve = GetCurve(icSigGrayTRCTag); + + if (!m_Curve) { + return icCmmStatProfileMissingTag; + } + } + else { + m_Curve = GetInvCurve(icSigGrayTRCTag); + m_bFreeCurve = true; + + if (!m_Curve) { + return icCmmStatProfileMissingTag; + } + } + + m_Curve->Begin(); + if (!m_Curve->IsIdentity()) { + m_ApplyCurvePtr = m_Curve; + } + + return icCmmStatOk; +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::Apply +* +* Purpose: +* Does the actual application of the Xform. +* +* Args: +* pApply = ApplyXform object containing temporary storage used during Apply +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +void CIccXformMonochrome::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + icFloatNumber Pixel[3]; + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + + if (m_bInput) { + Pixel[0] = SrcPixel[0]; + + if (m_ApplyCurvePtr) { + Pixel[0] = m_ApplyCurvePtr->Apply(Pixel[0]); + } + + DstPixel[0] = icFloatNumber(icPerceptualRefWhiteX); + DstPixel[1] = icFloatNumber(icPerceptualRefWhiteY); + DstPixel[2] = icFloatNumber(icPerceptualRefWhiteZ); + + icXyzToPcs(DstPixel); + + if (m_pProfile->m_Header.pcs==icSigLabData) { + if (UseLegacyPCS()) { + CIccPCS::XyzToLab2(DstPixel, DstPixel, true); + } + else { + CIccPCS::XyzToLab(DstPixel, DstPixel, true); + } + } + + DstPixel[0] *= Pixel[0]; + DstPixel[1] *= Pixel[0]; + DstPixel[2] *= Pixel[0]; + } + else { + Pixel[0] = icFloatNumber(icPerceptualRefWhiteX); + Pixel[1] = icFloatNumber(icPerceptualRefWhiteY); + Pixel[2] = icFloatNumber(icPerceptualRefWhiteZ); + + icXyzToPcs(Pixel); + + if (m_pProfile->m_Header.pcs==icSigLabData) { + if (UseLegacyPCS()) { + CIccPCS::XyzToLab2(Pixel, Pixel, true); + } + else { + CIccPCS::XyzToLab(Pixel, Pixel, true); + } + DstPixel[0] = SrcPixel[0]/Pixel[0]; + } + else { + DstPixel[0] = SrcPixel[1]/Pixel[1]; + } + + if (m_ApplyCurvePtr) { + DstPixel[0] = m_ApplyCurvePtr->Apply(DstPixel[0]); + } + } + + CheckDstAbs(DstPixel); +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::GetCurve +* +* Purpose: +* Gets the curve having the passed signature, from the profile. +* +* Args: +* sig = signature of the curve to be found +* +* Return: +* Pointer to the curve. +************************************************************************** +*/ +CIccCurve *CIccXformMonochrome::GetCurve(icSignature sig) const +{ + CIccTag *pTag = m_pProfile->FindTag(sig); + + if (pTag && (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType)) { + return (CIccCurve*)pTag; + } + + return NULL; +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::GetInvCurve +* +* Purpose: +* Gets the inverted curve having the passed signature, from the profile. +* +* Args: +* sig = signature of the curve to be inverted +* +* Return: +* Pointer to the inverted curve. +************************************************************************** +*/ +CIccCurve *CIccXformMonochrome::GetInvCurve(icSignature sig) const +{ + CIccCurve *pCurve; + CIccTagCurve *pInvCurve; + + if (!(pCurve = GetCurve(sig))) + return NULL; + + pCurve->Begin(); + + pInvCurve = new CIccTagCurve(2048); + + int i; + icFloatNumber x; + icFloatNumber *Lut = &(*pInvCurve)[0]; + + for (i=0; i<2048; i++) { + x=(icFloatNumber)i / 2047; + + Lut[i] = pCurve->Find(x); + } + + return pInvCurve; +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::ExtractInputCurves +* +* Purpose: +* Gets the input curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the input curves. +************************************************************************** +*/ +LPIccCurve* CIccXformMonochrome::ExtractInputCurves() +{ + if (m_bInput) { + if (m_Curve) { + LPIccCurve* Curve = new LPIccCurve[1]; + Curve[0] = (LPIccCurve)(m_Curve->NewCopy()); + m_ApplyCurvePtr = NULL; + return Curve; + } + } + + return NULL; +} + +/** +************************************************************************** +* Name: CIccXformMonochrome::ExtractOutputCurves +* +* Purpose: +* Gets the output curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the output curves. +************************************************************************** +*/ +LPIccCurve* CIccXformMonochrome::ExtractOutputCurves() +{ + if (!m_bInput) { + if (m_Curve) { + LPIccCurve* Curve = new LPIccCurve[1]; + Curve[0] = (LPIccCurve)(m_Curve->NewCopy()); + m_ApplyCurvePtr = NULL; + return Curve; + } + } + + return NULL; +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::CIccXformMatrixTRC + * + * Purpose: + * Constructor + ************************************************************************** + */ +CIccXformMatrixTRC::CIccXformMatrixTRC() +{ + m_Curve[0] = m_Curve[1] = m_Curve[2] = NULL; + m_ApplyCurvePtr = NULL; + m_bFreeCurve = false; +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::~CIccXformMatrixTRC + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccXformMatrixTRC::~CIccXformMatrixTRC() +{ + if (m_bFreeCurve) { + if (m_Curve[0]) + delete m_Curve[0]; + if (m_Curve[1]) + delete m_Curve[1]; + if (m_Curve[2]) + delete m_Curve[2]; + } +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::Begin + * + * Purpose: + * Does the initialization of the Xform before Apply() is called. + * Must be called before Apply(). + * + ************************************************************************** + */ +icStatusCMM CIccXformMatrixTRC::Begin() +{ + icStatusCMM status; + const CIccTagXYZ *pXYZ; + + status = CIccXform::Begin(); + if (status != icCmmStatOk) + return status; + + pXYZ = GetColumn(icSigRedMatrixColumnTag); + if (!pXYZ) { + return icCmmStatProfileMissingTag; + } + + m_e[0] = icFtoD((*pXYZ)[0].X); + m_e[3] = icFtoD((*pXYZ)[0].Y); + m_e[6] = icFtoD((*pXYZ)[0].Z); + + pXYZ = GetColumn(icSigGreenMatrixColumnTag); + if (!pXYZ) { + return icCmmStatProfileMissingTag; + } + + m_e[1] = icFtoD((*pXYZ)[0].X); + m_e[4] = icFtoD((*pXYZ)[0].Y); + m_e[7] = icFtoD((*pXYZ)[0].Z); + + pXYZ = GetColumn(icSigBlueMatrixColumnTag); + if (!pXYZ) { + return icCmmStatProfileMissingTag; + } + + m_e[2] = icFtoD((*pXYZ)[0].X); + m_e[5] = icFtoD((*pXYZ)[0].Y); + m_e[8] = icFtoD((*pXYZ)[0].Z); + + m_ApplyCurvePtr = NULL; + + if (m_bInput) { + m_Curve[0] = GetCurve(icSigRedTRCTag); + m_Curve[1] = GetCurve(icSigGreenTRCTag); + m_Curve[2] = GetCurve(icSigBlueTRCTag); + + if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) { + return icCmmStatProfileMissingTag; + } + + } + else { + if (m_pProfile->m_Header.pcs!=icSigXYZData) { + return icCmmStatBadSpaceLink; + } + + m_Curve[0] = GetInvCurve(icSigRedTRCTag); + m_Curve[1] = GetInvCurve(icSigGreenTRCTag); + m_Curve[2] = GetInvCurve(icSigBlueTRCTag); + + m_bFreeCurve = true; + + if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) { + return icCmmStatProfileMissingTag; + } + + if (!icMatrixInvert3x3(m_e)) { + return icCmmStatInvalidProfile; + } + } + + m_Curve[0]->Begin(); + m_Curve[1]->Begin(); + m_Curve[2]->Begin(); + + if (!m_Curve[0]->IsIdentity() || !m_Curve[1]->IsIdentity() || !m_Curve[2]->IsIdentity()) { + m_ApplyCurvePtr = m_Curve; + } + + return icCmmStatOk; +} + + +static icFloatNumber XYZScale(icFloatNumber v) +{ + v = (icFloatNumber)(v * 32768.0 / 65535.0); + return v; +} + +static icFloatNumber XYZDescale(icFloatNumber v) +{ + return (icFloatNumber)(v * 65535.0 / 32768.0); +} + +static icFloatNumber RGBClip(icFloatNumber v, CIccCurve *pCurve) +{ + if (v<=0) + return(pCurve->Apply(0)); + else if (v>=1.0) + return (pCurve->Apply(1.0)); + + return pCurve->Apply(v); +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::Apply + * + * Purpose: + * Does the actual application of the Xform. + * + * Args: + * pApply = ApplyXform object containging temporary storage used during Apply + * DstPixel = Destination pixel where the result is stored, + * SrcPixel = Source pixel which is to be applied. + ************************************************************************** + */ +void CIccXformMatrixTRC::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + icFloatNumber Pixel[3]; + + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + Pixel[0] = SrcPixel[0]; + Pixel[1] = SrcPixel[1]; + Pixel[2] = SrcPixel[2]; + + if (m_bInput) { + + double LinR, LinG, LinB; + if (m_ApplyCurvePtr) { + LinR = m_ApplyCurvePtr[0]->Apply(Pixel[0]); + LinG = m_ApplyCurvePtr[1]->Apply(Pixel[1]); + LinB = m_ApplyCurvePtr[2]->Apply(Pixel[2]); + } + else { + LinR = Pixel[0]; + LinG = Pixel[1]; + LinB = Pixel[2]; + } + + DstPixel[0] = XYZScale((icFloatNumber)(m_e[0] * LinR + m_e[1] * LinG + m_e[2] * LinB)); + DstPixel[1] = XYZScale((icFloatNumber)(m_e[3] * LinR + m_e[4] * LinG + m_e[5] * LinB)); + DstPixel[2] = XYZScale((icFloatNumber)(m_e[6] * LinR + m_e[7] * LinG + m_e[8] * LinB)); + } + else { + double X = XYZDescale(Pixel[0]); + double Y = XYZDescale(Pixel[1]); + double Z = XYZDescale(Pixel[2]); + + if (m_ApplyCurvePtr) { + DstPixel[0] = RGBClip((icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z), m_ApplyCurvePtr[0]); + DstPixel[1] = RGBClip((icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z), m_ApplyCurvePtr[1]); + DstPixel[2] = RGBClip((icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z), m_ApplyCurvePtr[2]); + } + else { + DstPixel[0] = (icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z); + DstPixel[1] = (icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z); + DstPixel[2] = (icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z); + } + } + + CheckDstAbs(DstPixel); +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::GetCurve + * + * Purpose: + * Gets the curve having the passed signature, from the profile. + * + * Args: + * sig = signature of the curve to be found + * + * Return: + * Pointer to the curve. + ************************************************************************** + */ +CIccCurve *CIccXformMatrixTRC::GetCurve(icSignature sig) const +{ + CIccTag *pTag = m_pProfile->FindTag(sig); + + if (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType) { + return (CIccCurve*)pTag; + } + + return NULL; +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::GetColumn + * + * Purpose: + * Gets the XYZ tag from the profile. + * + * Args: + * sig = signature of the XYZ tag to be found. + * + * Return: + * Pointer to the XYZ tag. + ************************************************************************** + */ +CIccTagXYZ *CIccXformMatrixTRC::GetColumn(icSignature sig) const +{ + CIccTag *pTag = m_pProfile->FindTag(sig); + + if (!pTag || pTag->GetType()!=icSigXYZType) { + return NULL; + } + + return (CIccTagXYZ*)pTag; +} + +/** + ************************************************************************** + * Name: CIccXformMatrixTRC::GetInvCurve + * + * Purpose: + * Gets the inverted curve having the passed signature, from the profile. + * + * Args: + * sig = signature of the curve to be inverted + * + * Return: + * Pointer to the inverted curve. + ************************************************************************** + */ +CIccCurve *CIccXformMatrixTRC::GetInvCurve(icSignature sig) const +{ + CIccCurve *pCurve; + CIccTagCurve *pInvCurve; + + if (!(pCurve = GetCurve(sig))) + return NULL; + + pCurve->Begin(); + + pInvCurve = new CIccTagCurve(2048); + + int i; + icFloatNumber x; + icFloatNumber *Lut = &(*pInvCurve)[0]; + + for (i=0; i<2048; i++) { + x=(icFloatNumber)i / 2047; + + Lut[i] = pCurve->Find(x); + } + + return pInvCurve; +} + +/** +************************************************************************** +* Name: CIccXformMatrixTRC::ExtractInputCurves +* +* Purpose: +* Gets the input curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the input curves. +************************************************************************** +*/ +LPIccCurve* CIccXformMatrixTRC::ExtractInputCurves() +{ + if (m_bInput) { + if (m_Curve[0]) { + LPIccCurve* Curve = new LPIccCurve[3]; + Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy()); + Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy()); + Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy()); + m_ApplyCurvePtr = NULL; + return Curve; + } + } + + return NULL; +} + +/** +************************************************************************** +* Name: CIccXformMatrixTRC::ExtractOutputCurves +* +* Purpose: +* Gets the output curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the output curves. +************************************************************************** +*/ +LPIccCurve* CIccXformMatrixTRC::ExtractOutputCurves() +{ + if (!m_bInput) { + if (m_Curve[0]) { + LPIccCurve* Curve = new LPIccCurve[3]; + Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy()); + Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy()); + Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy()); + m_ApplyCurvePtr = NULL; + return Curve; + } + } + + return NULL; +} + +/** + ************************************************************************** + * Name: CIccXform3DLut::CIccXform3DLut + * + * Purpose: + * Constructor + * + * Args: + * pTag = Pointer to the tag of type CIccMBB + ************************************************************************** + */ +CIccXform3DLut::CIccXform3DLut(CIccTag *pTag) +{ + if (pTag && pTag->IsMBBType()) { + m_pTag = (CIccMBB*)pTag; + } + else + m_pTag = NULL; + + m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL; + m_ApplyMatrixPtr = NULL; +} + +/** + ************************************************************************** + * Name: CIccXform3DLut::~CIccXform3DLut + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccXform3DLut::~CIccXform3DLut() +{ +} + +/** + ************************************************************************** + * Name: CIccXform3DLut::Begin + * + * Purpose: + * Does the initialization of the Xform before Apply() is called. + * Must be called before Apply(). + * + ************************************************************************** + */ + icStatusCMM CIccXform3DLut::Begin() +{ + icStatusCMM status; + CIccCurve **Curve; + int i; + + status = CIccXform::Begin(); + if (status != icCmmStatOk) + return status; + + if (!m_pTag || + m_pTag->InputChannels()!=3) { + return icCmmStatInvalidLut; + } + + m_ApplyCurvePtrA = NULL; + m_ApplyCurvePtrB = NULL; + m_ApplyCurvePtrM = NULL; + + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesB) { + Curve = m_pTag->m_CurvesB; + + Curve[0]->Begin(); + Curve[1]->Begin(); + Curve[2]->Begin(); + + if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { + m_ApplyCurvePtrB = Curve; + } + } + + if (m_pTag->m_CurvesM) { + Curve = m_pTag->m_CurvesM; + + Curve[0]->Begin(); + Curve[1]->Begin(); + Curve[2]->Begin(); + + if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { + m_ApplyCurvePtrM = Curve; + } + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Begin(); + } + + if (m_pTag->m_CurvesA) { + Curve = m_pTag->m_CurvesA; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrA = Curve; + break; + } + } + } + + } + else { + if (m_pTag->m_CurvesA) { + Curve = m_pTag->m_CurvesA; + + Curve[0]->Begin(); + Curve[1]->Begin(); + Curve[2]->Begin(); + + if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { + m_ApplyCurvePtrA = Curve; + } + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Begin(); + } + + if (m_pTag->m_CurvesM) { + Curve = m_pTag->m_CurvesM; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrM = Curve; + break; + } + } + } + + if (m_pTag->m_CurvesB) { + Curve = m_pTag->m_CurvesB; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrB = Curve; + break; + } + } + } + } + + m_ApplyMatrixPtr = NULL; + if (m_pTag->m_Matrix) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_nInput!=3) { + return icCmmStatInvalidProfile; + } + } + else { + if (m_pTag->m_nOutput!=3) { + return icCmmStatInvalidProfile; + } + } + + if (!m_pTag->m_Matrix->IsIdentity()) { + m_ApplyMatrixPtr = m_pTag->m_Matrix; + } + } + + return icCmmStatOk; +} + +/** + ************************************************************************** + * Name: CIccXform3DLut::Apply + * + * Purpose: + * Does the actual application of the Xform. + * + * Args: + * pApply = ApplyXform object containging temporary storage used during Apply + * DstPixel = Destination pixel where the result is stored, + * SrcPixel = Source pixel which is to be applied. + ************************************************************************** + */ +void CIccXform3DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + icFloatNumber Pixel[16]; + int i; + + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + Pixel[0] = SrcPixel[0]; + Pixel[1] = SrcPixel[1]; + Pixel[2] = SrcPixel[2]; + + if (m_pTag->m_bInputMatrix) { + if (m_ApplyCurvePtrB) { + Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]); + Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]); + Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]); + } + + if (m_ApplyMatrixPtr) { + m_ApplyMatrixPtr->Apply(Pixel); + } + + if (m_ApplyCurvePtrM) { + Pixel[0] = m_ApplyCurvePtrM[0]->Apply(Pixel[0]); + Pixel[1] = m_ApplyCurvePtrM[1]->Apply(Pixel[1]); + Pixel[2] = m_ApplyCurvePtrM[2]->Apply(Pixel[2]); + } + + if (m_pTag->m_CLUT) { + if (m_nInterp==icInterpLinear) + m_pTag->m_CLUT->Interp3d(Pixel, Pixel); + else + m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel); + } + + if (m_ApplyCurvePtrA) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); + } + } + + } + else { + if (m_ApplyCurvePtrA) { + Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]); + Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]); + Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]); + } + + if (m_pTag->m_CLUT) { + if (m_nInterp==icInterpLinear) + m_pTag->m_CLUT->Interp3d(Pixel, Pixel); + else + m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel); + } + + if (m_ApplyCurvePtrM) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); + } + } + + if (m_ApplyMatrixPtr) { + m_ApplyMatrixPtr->Apply(Pixel); + } + + if (m_ApplyCurvePtrB) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); + } + } + } + + for (i=0; im_nOutput; i++) { + DstPixel[i] = Pixel[i]; + } + + CheckDstAbs(DstPixel); +} + +/** +************************************************************************** +* Name: CIccXform3DLut::ExtractInputCurves +* +* Purpose: +* Gets the input curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the input curves. +************************************************************************** +*/ +LPIccCurve* CIccXform3DLut::ExtractInputCurves() +{ + if (m_bInput) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesB) { + LPIccCurve* Curve = new LPIccCurve[3]; + Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy()); + Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy()); + Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy()); + m_ApplyCurvePtrB = NULL; + return Curve; + } + } + else { + if (m_pTag->m_CurvesA) { + LPIccCurve* Curve = new LPIccCurve[3]; + Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy()); + Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy()); + Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy()); + m_ApplyCurvePtrA = NULL; + return Curve; + } + } + } + + return NULL; +} + +/** +************************************************************************** +* Name: CIccXform3DLut::ExtractOutputCurves +* +* Purpose: +* Gets the output curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the output curves. +************************************************************************** +*/ +LPIccCurve* CIccXform3DLut::ExtractOutputCurves() +{ + if (!m_bInput) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesA) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; + for (int i=0; im_nOutput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); + } + m_ApplyCurvePtrA = NULL; + return Curve; + } + } + else { + if (m_pTag->m_CurvesB) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; + for (int i=0; im_nOutput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); + } + m_ApplyCurvePtrB = NULL; + return Curve; + } + } + } + + return NULL; +} + +/** + ************************************************************************** + * Name: CIccXform4DLut::CIccXform4DLut + * + * Purpose: + * Constructor + * + * Args: + * pTag = Pointer to the tag of type CIccMBB + ************************************************************************** + */ +CIccXform4DLut::CIccXform4DLut(CIccTag *pTag) +{ + if (pTag && pTag->IsMBBType()) { + m_pTag = (CIccMBB*)pTag; + } + else + m_pTag = NULL; + + m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL; + m_ApplyMatrixPtr = NULL; +} + + +/** + ************************************************************************** + * Name: CIccXform4DLut::~CIccXform4DLut + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccXform4DLut::~CIccXform4DLut() +{ +} + + +/** + ************************************************************************** + * Name: CIccXform4DLut::Begin + * + * Purpose: + * Does the initialization of the Xform before Apply() is called. + * Must be called before Apply(). + * + ************************************************************************** + */ +icStatusCMM CIccXform4DLut::Begin() +{ + icStatusCMM status; + CIccCurve **Curve; + int i; + + status = CIccXform::Begin(); + if (status != icCmmStatOk) { + return status; + } + + if (!m_pTag || + m_pTag->InputChannels()!=4) { + return icCmmStatInvalidLut; + } + + m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL; + + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesB) { + Curve = m_pTag->m_CurvesB; + + Curve[0]->Begin(); + Curve[1]->Begin(); + Curve[2]->Begin(); + Curve[3]->Begin(); + + if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || + !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity()) + { + m_ApplyCurvePtrB = Curve; + } + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Begin(); + } + + if (m_pTag->m_CurvesA) { + Curve = m_pTag->m_CurvesA; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrA = Curve; + break; + } + } + } + + } + else { + if (m_pTag->m_CurvesA) { + Curve = m_pTag->m_CurvesA; + + Curve[0]->Begin(); + Curve[1]->Begin(); + Curve[2]->Begin(); + Curve[3]->Begin(); + + if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || + !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity()) + { + m_ApplyCurvePtrA = Curve; + } + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Begin(); + } + + if (m_pTag->m_CurvesM) { + Curve = m_pTag->m_CurvesM; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrM = Curve; + break; + } + } + } + + if (m_pTag->m_CurvesB) { + Curve = m_pTag->m_CurvesB; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrB = Curve; + break; + } + } + } + } + + m_ApplyMatrixPtr = NULL; + if (m_pTag->m_Matrix) { + if (m_pTag->m_bInputMatrix) { + return icCmmStatInvalidProfile; + } + else { + if (m_pTag->m_nOutput!=3) { + return icCmmStatInvalidProfile; + } + } + + if (!m_pTag->m_Matrix->IsIdentity()) { + m_ApplyMatrixPtr = m_pTag->m_Matrix; + } + } + + return icCmmStatOk; +} + + +/** + ************************************************************************** + * Name: CIccXform4DLut::Apply + * + * Purpose: + * Does the actual application of the Xform. + * + * Args: + * pApply = ApplyXform object containging temporary storage used during Apply + * DstPixel = Destination pixel where the result is stored, + * SrcPixel = Source pixel which is to be applied. + ************************************************************************** + */ +void CIccXform4DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + icFloatNumber Pixel[16]; + int i; + + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + Pixel[0] = SrcPixel[0]; + Pixel[1] = SrcPixel[1]; + Pixel[2] = SrcPixel[2]; + Pixel[3] = SrcPixel[3]; + + if (m_pTag->m_bInputMatrix) { + if (m_ApplyCurvePtrB) { + Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]); + Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]); + Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]); + Pixel[3] = m_ApplyCurvePtrB[3]->Apply(Pixel[3]); + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Interp4d(Pixel, Pixel); + } + + if (m_ApplyCurvePtrA) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); + } + } + + } + else { + if (m_ApplyCurvePtrA) { + Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]); + Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]); + Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]); + Pixel[3] = m_ApplyCurvePtrA[3]->Apply(Pixel[3]); + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Interp4d(Pixel, Pixel); + } + + if (m_ApplyCurvePtrM) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); + } + } + + if (m_ApplyMatrixPtr) { + m_ApplyMatrixPtr->Apply(Pixel); + } + + if (m_ApplyCurvePtrB) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); + } + } + } + + for (i=0; im_nOutput; i++) { + DstPixel[i] = Pixel[i]; + } + + CheckDstAbs(DstPixel); +} + +/** +************************************************************************** +* Name: CIccXform4DLut::ExtractInputCurves +* +* Purpose: +* Gets the input curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the input curves. +************************************************************************** +*/ +LPIccCurve* CIccXform4DLut::ExtractInputCurves() +{ + if (m_bInput) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesB) { + LPIccCurve* Curve = new LPIccCurve[4]; + Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy()); + Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy()); + Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy()); + Curve[3] = (LPIccCurve)(m_pTag->m_CurvesB[3]->NewCopy()); + m_ApplyCurvePtrB = NULL; + return Curve; + } + } + else { + if (m_pTag->m_CurvesA) { + LPIccCurve* Curve = new LPIccCurve[4]; + Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy()); + Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy()); + Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy()); + Curve[3] = (LPIccCurve)(m_pTag->m_CurvesA[3]->NewCopy()); + m_ApplyCurvePtrA = NULL; + return Curve; + } + } + } + + return NULL; +} + +/** +************************************************************************** +* Name: CIccXform4DLut::ExtractOutputCurves +* +* Purpose: +* Gets the output curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the output curves. +************************************************************************** +*/ +LPIccCurve* CIccXform4DLut::ExtractOutputCurves() +{ + if (!m_bInput) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesA) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; + for (int i=0; im_nOutput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); + } + m_ApplyCurvePtrA = NULL; + return Curve; + } + } + else { + if (m_pTag->m_CurvesB) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; + for (int i=0; im_nOutput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); + } + m_ApplyCurvePtrB = NULL; + return Curve; + } + } + } + + return NULL; +} + + +/** + ************************************************************************** + * Name: CIccXformNDLut::CIccXformNDLut + * + * Purpose: + * Constructor + * + * Args: + * pTag = Pointer to the tag of type CIccMBB + ************************************************************************** + */ +CIccXformNDLut::CIccXformNDLut(CIccTag *pTag) +{ + if (pTag && pTag->IsMBBType()) { + m_pTag = (CIccMBB*)pTag; + } + else + m_pTag = NULL; + + m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL; + m_ApplyMatrixPtr = NULL; +} + + +/** + ************************************************************************** + * Name: CIccXformNDLut::~CIccXformNDLut + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccXformNDLut::~CIccXformNDLut() +{ +} + + +/** + ************************************************************************** + * Name: CIccXformNDLut::Begin + * + * Purpose: + * Does the initialization of the Xform before Apply() is called. + * Must be called before Apply(). + * + ************************************************************************** + */ +icStatusCMM CIccXformNDLut::Begin() +{ + icStatusCMM status; + CIccCurve **Curve; + int i; + + status = CIccXform::Begin(); + if (status != icCmmStatOk) { + return status; + } + + if (!m_pTag || (m_pTag->InputChannels()>2 && m_pTag->InputChannels()<5)) { + return icCmmStatInvalidLut; + } + + m_nNumInput = m_pTag->m_nInput; + + m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL; + + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesB) { + Curve = m_pTag->m_CurvesB; + + for (i=0; iBegin(); + + for (i=0; iIsIdentity()) { + m_ApplyCurvePtrB = Curve; + break; + } + } + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Begin(); + } + + if (m_pTag->m_CurvesA) { + Curve = m_pTag->m_CurvesA; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrA = Curve; + break; + } + } + } + + } + else { + if (m_pTag->m_CurvesA) { + Curve = m_pTag->m_CurvesA; + + for (i=0; iBegin(); + + for (i=0; iIsIdentity()) { + m_ApplyCurvePtrA = Curve; + break; + } + } + } + + if (m_pTag->m_CLUT) { + m_pTag->m_CLUT->Begin(); + } + + if (m_pTag->m_CurvesM) { + Curve = m_pTag->m_CurvesM; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrM = Curve; + break; + } + } + } + + if (m_pTag->m_CurvesB) { + Curve = m_pTag->m_CurvesB; + + for (i=0; im_nOutput; i++) { + Curve[i]->Begin(); + } + + for (i=0; im_nOutput; i++) { + if (!Curve[i]->IsIdentity()) { + m_ApplyCurvePtrB = Curve; + break; + } + } + } + } + + m_ApplyMatrixPtr = NULL; + if (m_pTag->m_Matrix) { + if (m_pTag->m_bInputMatrix) { + return icCmmStatInvalidProfile; + } + else { + if (m_pTag->m_nOutput!=3) { + return icCmmStatInvalidProfile; + } + } + + if (!m_pTag->m_Matrix->IsIdentity()) { + m_ApplyMatrixPtr = m_pTag->m_Matrix; + } + } + + return icCmmStatOk; +} + + +/** + ************************************************************************** + * Name: CIccXformNDLut::Apply + * + * Purpose: + * Does the actual application of the Xform. + * + * Args: + * pApply = ApplyXform object containging temporary storage used during Apply + * DstPixel = Destination pixel where the result is stored, + * SrcPixel = Source pixel which is to be applied. + ************************************************************************** + */ +void CIccXformNDLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + icFloatNumber Pixel[16]; + int i; + + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + for (i=0; im_bInputMatrix) { + if (m_ApplyCurvePtrB) { + for (i=0; iApply(Pixel[i]); + } + + if (m_pTag->m_CLUT) { + switch(m_nNumInput) { + case 5: + m_pTag->m_CLUT->Interp5d(Pixel, Pixel); + break; + case 6: + m_pTag->m_CLUT->Interp6d(Pixel, Pixel); + break; + default: + m_pTag->m_CLUT->InterpND(Pixel, Pixel); + break; + } + } + + if (m_ApplyCurvePtrA) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); + } + } + + } + else { + if (m_ApplyCurvePtrA) { + for (i=0; iApply(Pixel[i]); + } + + if (m_pTag->m_CLUT) { + switch(m_nNumInput) { + case 5: + m_pTag->m_CLUT->Interp5d(Pixel, Pixel); + break; + case 6: + m_pTag->m_CLUT->Interp6d(Pixel, Pixel); + break; + default: + m_pTag->m_CLUT->InterpND(Pixel, Pixel); + break; + } + } + + if (m_ApplyCurvePtrM) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); + } + } + + if (m_ApplyMatrixPtr) { + m_ApplyMatrixPtr->Apply(Pixel); + } + + if (m_ApplyCurvePtrB) { + for (i=0; im_nOutput; i++) { + Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); + } + } + } + + for (i=0; im_nOutput; i++) { + DstPixel[i] = Pixel[i]; + } + + CheckDstAbs(DstPixel); +} + +/** +************************************************************************** +* Name: CIccXformNDLut::ExtractInputCurves +* +* Purpose: +* Gets the input curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the input curves. +************************************************************************** +*/ +LPIccCurve* CIccXformNDLut::ExtractInputCurves() +{ + if (m_bInput) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesB) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput]; + for (int i=0; im_nInput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); + } + m_ApplyCurvePtrB = NULL; + return Curve; + } + } + else { + if (m_pTag->m_CurvesA) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput]; + for (int i=0; im_nInput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); + } + m_ApplyCurvePtrA = NULL; + return Curve; + } + } + } + + return NULL; +} + +/** +************************************************************************** +* Name: CIccXformNDLut::ExtractOutputCurves +* +* Purpose: +* Gets the output curves. Should be called only after Begin() +* has been called. Once the curves are extracted, they will +* not be used by the Apply() function. +* WARNING: caller owns the curves and must be deleted by the caller. +* +* Return: +* Pointer to the output curves. +************************************************************************** +*/ +LPIccCurve* CIccXformNDLut::ExtractOutputCurves() +{ + if (!m_bInput) { + if (m_pTag->m_bInputMatrix) { + if (m_pTag->m_CurvesA) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; + for (int i=0; im_nOutput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); + } + m_ApplyCurvePtrA = NULL; + return Curve; + } + } + else { + if (m_pTag->m_CurvesB) { + LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; + for (int i=0; im_nOutput; i++) { + Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); + } + m_ApplyCurvePtrB = NULL; + return Curve; + } + } + } + + return NULL; +} + +/** + ************************************************************************** + * Name: CIccXformNamedColor::CIccXformNamedColor + * + * Purpose: + * Constructor + * + * Args: + * pTag = Pointer to the tag of type CIccTagNamedColor2, + * csPCS = PCS color space, + * csDevice = Device color space + ************************************************************************** + */ +CIccXformNamedColor::CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPCS, icColorSpaceSignature csDevice) +{ + if (pTag && pTag->GetType()==icSigNamedColor2Type) { + m_pTag = (CIccTagNamedColor2*)pTag; + m_pTag->SetColorSpaces(csPCS, csDevice); + } + else + m_pTag = NULL; + + m_nSrcSpace = icSigUnknownData; + m_nDestSpace = icSigUnknownData; +} + + +/** + ************************************************************************** + * Name: CIccXformNamedColor::CIccXformNamedColor + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccXformNamedColor::~CIccXformNamedColor() +{ +} + +/** + ************************************************************************** + * Name: CIccXformNamedColor::Begin + * + * Purpose: + * Does the initialization of the Xform before Apply() is called. + * Must be called before Apply(). + * + ************************************************************************** + */ +icStatusCMM CIccXformNamedColor::Begin() +{ + icStatusCMM status; + + status = CIccXform::Begin(); + if (status != icCmmStatOk) + return status; + + if (m_pTag == NULL) { + return icCmmStatProfileMissingTag; + } + + if (m_nSrcSpace==icSigUnknownData || + m_nDestSpace==icSigUnknownData) { + return icCmmStatIncorrectApply; + } + + if (m_nSrcSpace != icSigNamedData) { + if (m_nDestSpace != icSigNamedData) { + m_nApplyInterface = icApplyPixel2Pixel; + } + else { + m_nApplyInterface = icApplyPixel2Named; + } + } + else { + if (m_nDestSpace != icSigNamedData) { + m_nApplyInterface = icApplyNamed2Pixel; + } + else { + return icCmmStatIncorrectApply; + } + } + + if (!m_pTag->InitFindCachedPCSColor()) + return icCmmStatAllocErr; + + return icCmmStatOk; +} + + + +/** + ************************************************************************** + * Name: CIccXformNamedColor::Apply + * + * Purpose: + * Does the actual application of the Xform. + * + * Args: + * pApply = ApplyXform object containging temporary storage used during Apply + * DstColorName = Destination string where the color name result is stored, + * SrcPixel = Source pixel which is to be applied. + ************************************************************************** + */ +icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icChar *DstColorName, const icFloatNumber *SrcPixel) const +{ + const CIccTagNamedColor2 *pTag = m_pTag; + if (pTag == NULL) + return icCmmStatBadXform; + + icFloatNumber DevicePix[16], PCSPix[3]; + std::string NamedColor; + icUInt32Number i, j; + + if (IsSrcPCS()) { + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + for(i=0; i<3; i++) + PCSPix[i] = SrcPixel[i]; + + j = pTag->FindCachedPCSColor(PCSPix); + pTag->GetColorName(NamedColor, j); + } + else { + for(i=0; iGetDeviceCoords(); i++) + DevicePix[i] = SrcPixel[i]; + + j = pTag->FindDeviceColor(DevicePix); + pTag->GetColorName(NamedColor, j); + } + + sprintf(DstColorName, "%s", NamedColor.c_str()); + + return icCmmStatOk; +} + + +/** +************************************************************************** +* Name: CIccXformNamedColor::Apply +* +* Purpose: +* Does the actual application of the Xform. +* +* Args: +* pApply = ApplyXform object containging temporary storage used during Apply +* DstPixel = Destination pixel where the result is stored, +* SrcColorName = Source color name which is to be applied. +************************************************************************** +*/ +icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icChar *SrcColorName) const +{ + const CIccTagNamedColor2 *pTag = m_pTag; + + if (pTag == NULL) + return icCmmStatProfileMissingTag; + + icUInt32Number j; + + if (m_nSrcSpace != icSigNamedData) + return icCmmStatBadSpaceLink; + + if (IsDestPCS()) { + + j = pTag->FindColor(SrcColorName); + if (j<0) + return icCmmStatColorNotFound; + + if (m_nDestSpace == icSigLabData) { + memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber)); + } + else { + memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber)); + } + CheckDstAbs(DstPixel); + } + else { + j = pTag->FindColor(SrcColorName); + if (j<0) + return icCmmStatColorNotFound; + memcpy(DstPixel, pTag->GetEntry(j)->deviceCoords, pTag->GetDeviceCoords()*sizeof(icFloatNumber)); + } + + return icCmmStatOk; +} + +/** + ************************************************************************** + * Name: CIccXformNamedColor::SetSrcSpace + * + * Purpose: + * Sets the source space of the Xform + * + * Args: + * nSrcSpace = signature of the color space to be set + ************************************************************************** + */ +icStatusCMM CIccXformNamedColor::SetSrcSpace(icColorSpaceSignature nSrcSpace) +{ + if (nSrcSpace!=m_pTag->GetPCS()) + if (nSrcSpace!=m_pTag->GetDeviceSpace()) + if (nSrcSpace!=icSigNamedData) + return icCmmStatBadSpaceLink; + + m_nSrcSpace = nSrcSpace; + + return icCmmStatOk; +} + +/** + ************************************************************************** + * Name: CIccXformNamedColor::SetSrcSpace + * + * Purpose: + * Sets the destination space of the Xform + * + * Args: + * nDestSpace = signature of the color space to be set + ************************************************************************** + */ +icStatusCMM CIccXformNamedColor::SetDestSpace(icColorSpaceSignature nDestSpace) +{ + if (m_nSrcSpace == nDestSpace) + return icCmmStatBadSpaceLink; + + if (nDestSpace!=m_pTag->GetPCS()) + if (nDestSpace!=m_pTag->GetDeviceSpace()) + if (nDestSpace!=icSigNamedData) + return icCmmStatBadSpaceLink; + + m_nDestSpace = nDestSpace; + + return icCmmStatOk; +} + + +/** +************************************************************************** +* Name: CIccXformMPE::CIccXformMPE +* +* Purpose: +* Constructor +************************************************************************** +*/ +CIccXformMpe::CIccXformMpe(CIccTag *pTag) +{ + if (pTag && pTag->GetType()==icSigMultiProcessElementType) + m_pTag = (CIccTagMultiProcessElement*)pTag; + else + m_pTag = NULL; + + m_bUsingAcs = false; +} + +/** +************************************************************************** +* Name: CIccXformMPE::~CIccXformMPE +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccXformMpe::~CIccXformMpe() +{ +} + +/** +************************************************************************** +* Name: CIccXformMPE::Create +* +* Purpose: +* This is a static Creation function that creates derived CIccXform objects and +* initializes them. +* +* Args: +* pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will +* be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile +* object needs to be allocated on the heap. +* bInput = flag to indicate whether to use the input or output side of the profile, +* nIntent = the rendering intent to apply to the profile, +* nInterp = the interpolation algorithm to use for N-D luts. +* nLutType = selection of which transform lut to use +* pHintManager = hints for creating the xform +* +* Return: +* A suitable pXform object +************************************************************************** +*/ +CIccXform *CIccXformMpe::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */, + icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */, + CIccCreateXformHintManager *pHintManager/* =NULL */) +{ + CIccXform *rv = NULL; + icRenderingIntent nTagIntent = nIntent; + + if (nTagIntent == icUnknownIntent) + nTagIntent = icPerceptual; + + switch (nLutType) { + case icXformLutColor: + if (bInput) { + CIccTag *pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); + + if (!pTag && nTagIntent ==icAbsoluteColorimetric) { + pTag = pProfile->FindTag(icSigDToB1Tag); + if (pTag) + nTagIntent = icRelativeColorimetric; + } + + if (!pTag) { + pTag = pProfile->FindTag(icSigDToB0Tag); + } + + //Unsupported elements cause fall back behavior + if (pTag && !pTag->IsSupported()) + pTag = NULL; + + if (!pTag) { + if (nTagIntent == icAbsoluteColorimetric) + nTagIntent = icRelativeColorimetric; + pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent); + } + + if (!pTag) { + pTag = pProfile->FindTag(icSigAToB0Tag); + } + + if (!pTag) { + if (pProfile->m_Header.colorSpace == icSigRgbData) { + rv = new CIccXformMatrixTRC(); + } + else + return NULL; + } + else if (pTag->GetType()==icSigMultiProcessElementType) { + rv = new CIccXformMpe(pTag); + } + else { + switch(pProfile->m_Header.colorSpace) { + case icSigXYZData: + case icSigLabData: + case icSigLuvData: + case icSigYCbCrData: + case icSigYxyData: + case icSigRgbData: + case icSigHsvData: + case icSigHlsData: + case icSigCmyData: + case icSig3colorData: + rv = new CIccXform3DLut(pTag); + break; + + case icSigCmykData: + case icSig4colorData: + rv = new CIccXform4DLut(pTag); + break; + + default: + rv = new CIccXformNDLut(pTag); + break; + } + } + } + else { + CIccTag *pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent); + + if (!pTag && nTagIntent ==icAbsoluteColorimetric) { + pTag = pProfile->FindTag(icSigBToD1Tag); + if (pTag) + nTagIntent = icRelativeColorimetric; + } + + if (!pTag) { + pTag = pProfile->FindTag(icSigBToD0Tag); + } + + //Unsupported elements cause fall back behavior + if (pTag && !pTag->IsSupported()) + pTag = NULL; + + if (!pTag) { + if (nTagIntent == icAbsoluteColorimetric) + nTagIntent = icRelativeColorimetric; + pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent); + } + + if (!pTag) { + pTag = pProfile->FindTag(icSigBToA0Tag); + } + + if (!pTag) { + if (pProfile->m_Header.colorSpace == icSigRgbData) { + rv = new CIccXformMatrixTRC(); + } + else + return NULL; + } + if (pTag->GetType()==icSigMultiProcessElementType) { + rv = new CIccXformMpe(pTag); + } + else { + switch(pProfile->m_Header.pcs) { + case icSigXYZData: + case icSigLabData: + rv = new CIccXform3DLut(pTag); + + default: + break; + } + } + } + break; + + case icXformLutNamedColor: + { + CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); + if (!pTag) + return NULL; + + rv = new CIccXformNamedColor(pTag, pProfile->m_Header.pcs, pProfile->m_Header.colorSpace); + } + break; + + case icXformLutPreview: + { + bInput = false; + CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent); + if (!pTag) { + pTag = pProfile->FindTag(icSigPreview0Tag); + } + if (!pTag) { + return NULL; + } + else { + switch(pProfile->m_Header.pcs) { + case icSigXYZData: + case icSigLabData: + rv = new CIccXform3DLut(pTag); + + default: + break; + } + } + } + break; + + case icXformLutGamut: + { + bInput = false; + CIccTag *pTag = pProfile->FindTag(icSigGamutTag); + if (!pTag) { + return NULL; + } + else { + switch(pProfile->m_Header.pcs) { + case icSigXYZData: + case icSigLabData: + rv = new CIccXform3DLut(pTag); + + default: + break; + } + } + } + break; + } + + if (rv) { + rv->SetParams(pProfile, bInput, nIntent, nInterp, pHintManager); + } + + return rv; +} + + +/** +************************************************************************** +* Name: CIccXformMPE::Begin +* +* Purpose: +* This function will be called before the xform is applied. Derived objects +* should also call the base class function to initialize for Absolute Colorimetric +* Intent handling which is performed through the use of the CheckSrcAbs and +* CheckDstAbs functions. +************************************************************************** +*/ +icStatusCMM CIccXformMpe::Begin() +{ + icStatusCMM status; + status = CIccXform::Begin(); + + if (status != icCmmStatOk) + return status; + + if (!m_pTag) { + return icCmmStatInvalidLut; + } + + if (!m_pTag->Begin()) { + return icCmmStatInvalidProfile; + } + + return icCmmStatOk; +} + + +/** +************************************************************************** +* Name: CIccXformMpe::GetNewApply +* +* Purpose: +* This Factory function allocates data specific for the application of the xform. +* This allows multiple threads to simultaneously use the same xform. +************************************************************************** +*/ +CIccApplyXform *CIccXformMpe::GetNewApply(icStatusCMM &status) +{ + if (!m_pTag) + return NULL; + + CIccApplyXformMpe *rv= new CIccApplyXformMpe(this); + + if (!rv) { + status = icCmmStatAllocErr; + return NULL; + } + + rv->m_pApply = m_pTag->GetNewApply(); + if (!rv->m_pApply) { + status = icCmmStatAllocErr; + delete rv; + return NULL; + } + + status = icCmmStatOk; + return rv; +} + + +/** +************************************************************************** +* Name: CIccXformMPE::Apply +* +* Purpose: +* Does the actual application of the Xform. +* +* Args: +* pApply = ApplyXform object containging temporary storage used during Apply +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +void CIccXformMpe::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const +{ + const CIccTagMultiProcessElement *pTag = m_pTag; + + if (!m_bInput) { //PCS comming in? + if (m_nIntent != icAbsoluteColorimetric) //B2D3 tags don't need abs conversion + SrcPixel = CheckSrcAbs(pApply, SrcPixel); + + //Since MPE tags use "real" values for PCS we need to convert from + //internal encoding used by IccProfLib + icFloatNumber temp[3]; + switch (GetSrcSpace()) { + case icSigXYZData: + memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber)); + icXyzFromPcs(temp); + SrcPixel = &temp[0]; + break; + + case icSigLabData: + memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber)); + icLabFromPcs(temp); + SrcPixel = &temp[0]; + break; + + default: + break; + } + } + + //Note: pApply should be a CIccApplyXformMpe type here + CIccApplyXformMpe *pApplyMpe = (CIccApplyXformMpe *)pApply; + + pTag->Apply(pApplyMpe->m_pApply, DstPixel, SrcPixel); + + if (m_bInput) { //PCS going out? + //Since MPE tags use "real" values for PCS we need to convert to + //internal encoding used by IccProfLib + switch(GetDstSpace()) { + case icSigXYZData: + icXyzToPcs(DstPixel); + break; + + case icSigLabData: + icLabToPcs(DstPixel); + break; + + default: + break; + } + + if (m_nIntent != icAbsoluteColorimetric) { //D2B3 tags don't need abs conversion + CheckDstAbs(DstPixel); + } + } +} + +/** +************************************************************************** +* Name: CIccApplyXformMpe::CIccApplyXformMpe +* +* Purpose: +* Constructor +************************************************************************** +*/ +CIccApplyXformMpe::CIccApplyXformMpe(CIccXformMpe *pXform) : CIccApplyXform(pXform) +{ +} + +/** +************************************************************************** +* Name: CIccApplyXformMpe::~CIccApplyXformMpe +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccApplyXformMpe::~CIccApplyXformMpe() +{ +} + + +/** +************************************************************************** +* Name: CIccApplyCmm::CIccApplyCmm +* +* Purpose: +* Constructor +* +* Args: +* pCmm = ptr to CMM to apply against +************************************************************************** +*/ +CIccApplyCmm::CIccApplyCmm(CIccCmm *pCmm) +{ + m_pCmm = pCmm; + m_pPCS = m_pCmm->GetPCS(); + + m_Xforms = new CIccApplyXformList; + m_Xforms->clear(); +} + +/** +************************************************************************** +* Name: CIccApplyCmm::~CIccApplyCmm +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccApplyCmm::~CIccApplyCmm() +{ + if (m_Xforms) { + CIccApplyXformList::iterator i; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + if (i->ptr) + delete i->ptr; + } + + delete m_Xforms; + } + + if (m_pPCS) + delete m_pPCS; +} + + +/** +************************************************************************** +* Name: CIccApplyCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + const CIccXform *pLastXform; + int j, n = (int)m_Xforms->size(); + bool bNoClip; + if (!n) + return icCmmStatBadXform; + m_pPCS->Reset(m_pCmm->m_nSrcSpace); + pSrc = SrcPixel; + pDst = Pixel; + + if (n>1) { + for (j=0, i=m_Xforms->begin(); jend(); i++, j++) { + + i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform())); + pSrc = pDst; + } + + pLastXform = i->ptr->GetXform(); + i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, pLastXform)); + bNoClip = pLastXform->NoClipPCS(); + } + else if (n==1) { + i = m_Xforms->begin(); + pLastXform = i->ptr->GetXform(); +// pri_debug("测试第一步4444"); + i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, pLastXform)); +// pri_debug("测试第一步3333"); + bNoClip = pLastXform->NoClipPCS(); +// pri_debug("测试第一步2222"); + } + else { + bNoClip = true; + } + + m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace, bNoClip); + + return icCmmStatOk; +} + +/** +************************************************************************** +* Name: CIccApplyCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + int j, n = (int)m_Xforms->size(); + icUInt32Number k; + + if (!n) + return icCmmStatBadXform; + + for (k=0; kReset(m_pCmm->m_nSrcSpace); + + pSrc = SrcPixel; + pDst = Pixel; + + if (n>1) { + for (j=0, i=m_Xforms->begin(); jend(); i++, j++) { + + i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform())); + pSrc = pDst; + } + + i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, i->ptr->GetXform())); + } + else if (n==1) { + i = m_Xforms->begin(); + i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, i->ptr->GetXform())); + } + + m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace); + + DstPixel += m_pCmm->GetDestSamples(); + SrcPixel += m_pCmm->GetSourceSamples(); + } + + return icCmmStatOk; +} + +void CIccApplyCmm::AppendApplyXform(CIccApplyXform *pApplyXform) +{ + CIccApplyXformPtr ptr; + ptr.ptr = pApplyXform; + + m_Xforms->push_back(ptr); +} + +/** + ************************************************************************** + * Name: CIccCmm::CIccCmm + * + * Purpose: + * Constructor + * + * Args: + * nSrcSpace = signature of the source color space, + * nDestSpace = signature of the destination color space, + * bFirstInput = true if the first profile added is an input profile + ************************************************************************** + */ +CIccCmm::CIccCmm(icColorSpaceSignature nSrcSpace /*=icSigUnknownData*/, + icColorSpaceSignature nDestSpace /*=icSigUnknownData*/, + bool bFirstInput /*=true*/) +{ + m_bValid = false; + + m_bLastInput = !bFirstInput; + m_nSrcSpace = nSrcSpace; + m_nDestSpace = nDestSpace; + + m_nLastSpace = nSrcSpace; + m_nLastIntent = icUnknownIntent; + + m_Xforms = new CIccXformList; + m_Xforms->clear(); + + m_pApply = NULL; +} + +/** + ************************************************************************** + * Name: CIccCmm::~CIccCmm + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccCmm::~CIccCmm() +{ + if (m_Xforms) { + CIccXformList::iterator i; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + if (i->ptr) + delete i->ptr; + } + + delete m_Xforms; + } + + if (m_pApply) + delete m_pApply; +} + +/** + ************************************************************************** + * Name: CIccCmm::AddXform + * + * Purpose: + * Adds a profile at the end of the Xform list + * + * Args: + * szProfilePath = file name of the profile to be added, + * nIntent = rendering intent to be used with the profile, + * nInterp = type of interpolation to be used with the profile, + * nLutType = selection of which transform lut to use + * pHintManager = hints for creating the xform + * + * Return: + * icCmmStatOk, if the profile was added to the list succesfully + ************************************************************************** + */ +icStatusCMM CIccCmm::AddXform(const icChar *szProfilePath, + icRenderingIntent nIntent /*=icUnknownIntent*/, + icXformInterp nInterp /*icXformInterp*/, + icXformLutType nLutType /*=icXformLutColor*/, + bool bUseMpeTags /*=true*/, + CIccCreateXformHintManager *pHintManager /*=NULL*/) +{ + CIccProfile *pProfile = OpenIccProfile(szProfilePath); + + if (!pProfile) + return icCmmStatCantOpenProfile; + + icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (rv != icCmmStatOk) + delete pProfile; + + return rv; +} + + +/** +************************************************************************** +* Name: CIccCmm::AddXform +* +* Purpose: +* Adds a profile at the end of the Xform list +* +* Args: +* pProfileMem = ptr to profile loaded into memory. Note: this memory +* needs to be available until after the Begin() function is called. +* nProfileLen = size in bytes of profile loaded into memory +* nIntent = rendering intent to be used with the profile, +* nInterp = type of interpolation to be used with the profile, +* nLutType = selection of which transform lut to use +* bUseMpeTags = flag to indicate the use MPE flags if available +* pHintManager = hints for creating the xform +* +* Return: +* icCmmStatOk, if the profile was added to the list succesfully +************************************************************************** +*/ +icStatusCMM CIccCmm::AddXform(icUInt8Number *pProfileMem, + icUInt32Number nProfileLen, + icRenderingIntent nIntent /*=icUnknownIntent*/, + icXformInterp nInterp /*icXformInterp*/, + icXformLutType nLutType /*=icXformLutColor*/, + bool bUseMpeTags /*=true*/, + CIccCreateXformHintManager *pHintManager /*=NULL*/) +{ + CIccMemIO *pFile = new CIccMemIO; + + if (!pFile || !pFile->Attach(pProfileMem, nProfileLen)) + return icCmmStatCantOpenProfile; + + CIccProfile *pProfile = new CIccProfile; + + if (!pProfile) + return icCmmStatCantOpenProfile; + + if (!pProfile->Attach(pFile)) { + delete pFile; + delete pProfile; + return icCmmStatCantOpenProfile; + } + + icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (rv != icCmmStatOk) + delete pProfile; + + return rv; +} + + +/** + ************************************************************************** + * Name: CIccCmm::AddXform + * + * Purpose: + * Adds a profile at the end of the Xform list + * + * Args: + * pProfile = pointer to the CIccProfile object to be added, + * nIntent = rendering intent to be used with the profile, + * nInterp = type of interpolation to be used with the profile, + * nLutType = selection of which transform lut to use + * bUseMpeTags = flag to indicate the use MPE flags if available + * pHintManager = hints for creating the xform + * + * Return: + * icCmmStatOk, if the profile was added to the list succesfully + ************************************************************************** + */ +icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile, + icRenderingIntent nIntent /*=icUnknownIntent*/, + icXformInterp nInterp /*=icInterpLinear*/, + icXformLutType nLutType /*=icXformLutColor*/, + bool bUseMpeTags /*=true*/, + CIccCreateXformHintManager *pHintManager /*=NULL*/) +{ + icColorSpaceSignature nSrcSpace, nDstSpace; + bool bInput = !m_bLastInput; + + if (!pProfile) + return icCmmStatInvalidProfile; + + switch (nLutType) { + case icXformLutColor: + { + //Check pProfile if nIntent and input can be found. + if (bInput) { + nSrcSpace = pProfile->m_Header.colorSpace; + nDstSpace = pProfile->m_Header.pcs; + } + else { + if (pProfile->m_Header.deviceClass == icSigLinkClass) { + return icCmmStatBadSpaceLink; + } + nSrcSpace = pProfile->m_Header.pcs; + nDstSpace = pProfile->m_Header.colorSpace; + if (pProfile->m_Header.deviceClass == icSigAbstractClass) { + bInput = true; + nIntent = icPerceptual; // Note: icPerceptualIntent = 0 + } + } + } + break; + + case icXformLutPreview: + nSrcSpace = pProfile->m_Header.pcs; + nDstSpace = pProfile->m_Header.pcs; + bInput = false; + break; + + case icXformLutGamut: + nSrcSpace = pProfile->m_Header.pcs; + nDstSpace = icSigGamutData; + bInput = true; + break; + + default: + return icCmmStatBadLutType; + } + + //Make sure colorspaces match with previous xforms + if (!m_Xforms->size()) { + if (m_nSrcSpace == icSigUnknownData) { + m_nLastSpace = nSrcSpace; + m_nSrcSpace = nSrcSpace; + } + else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)) { + return icCmmStatBadSpaceLink; + } + } + else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)) { + return icCmmStatBadSpaceLink; + } + + if (nSrcSpace==icSigNamedData) + return icCmmStatBadSpaceLink; + + //Automatic creation of intent from header/last profile + if (nIntent==icUnknownIntent) { + if (bInput) { + nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; + } + else { + nIntent = m_nLastIntent; + } + if (nIntent == icUnknownIntent) + nIntent = icPerceptual; + } + + CIccXformPtr Xform; + + Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (!Xform.ptr) { + return icCmmStatBadXform; + } + + m_nLastSpace = nDstSpace; + m_nLastIntent = nIntent; + m_bLastInput = bInput; + + m_Xforms->push_back(Xform); + + return icCmmStatOk; +} + + +/** + ************************************************************************** + * Name: CIccCmm::AddXform + * + * Purpose: + * Adds a profile at the end of the Xform list + * + * Args: + * Profile = reference a CIccProfile object that will be copies and added, + * nIntent = rendering intent to be used with the profile, + * nInterp = type of interpolation to be used with the profile, + * nLutType = selection of which transform lut to use + * bUseMpeTags = flag to indicate the use MPE flags if available + * pHintManager = hints for creating the xform + * + * Return: + * icCmmStatOk, if the profile was added to the list succesfully + ************************************************************************** + */ +icStatusCMM CIccCmm::AddXform(CIccProfile &Profile, + icRenderingIntent nIntent /*=icUnknownIntent*/, + icXformInterp nInterp /*=icInterpLinear*/, + icXformLutType nLutType /*=icXformLutColor*/, + bool bUseMpeTags /*=true*/, + CIccCreateXformHintManager *pHintManager /*=NULL*/) +{ + CIccProfile *pProfile = new CIccProfile(Profile); + + if (!pProfile) + return icCmmStatAllocErr; + + icStatusCMM stat = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (stat != icCmmStatOk) + delete pProfile; + + return stat; +} + +/** +************************************************************************** +* Name: CIccCmm::GetNewApplyCmm +* +* Purpose: +* Does the initialization of the Xforms before Apply() is called. +* Must be called before Apply(). +* +************************************************************************** +*/ +icStatusCMM CIccCmm::Begin(bool bAllocApplyCmm/*=true*/) +{ + if (m_pApply) + return icCmmStatOk; + + if (m_nDestSpace==icSigUnknownData) { + m_nDestSpace = m_nLastSpace; + } + else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)) { + return icCmmStatBadSpaceLink; + } + + if (m_nSrcSpace==icSigNamedData || m_nDestSpace==icSigNamedData) { + return icCmmStatBadSpaceLink; + } + + icStatusCMM rv = icCmmStatOk; + CIccXformList::iterator i; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + rv = i->ptr->Begin(); + + if (rv!= icCmmStatOk) { + return rv; + } + } + + if (bAllocApplyCmm) { + m_pApply = GetNewApplyCmm(rv); + } + else + rv = icCmmStatOk; + + return rv; +} + + +/** + ************************************************************************** + * Name: CIccCmm::GetNewApplyCmm + * + * Purpose: + * Allocates an CIccApplyCmm object that does the initialization of the Xforms + * that provides an Apply() function. + * Multiple CIccApplyCmm objects can be allocated and used in separate threads. + * + ************************************************************************** + */ +CIccApplyCmm *CIccCmm::GetNewApplyCmm(icStatusCMM &status) +{ + CIccApplyCmm *pApply = new CIccApplyCmm(this); + + if (!pApply) { + status = icCmmStatAllocErr; + return NULL; + } + + CIccXformList::iterator i; + CIccApplyXform *pXform; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + pXform = i->ptr->GetNewApply(status); + if (!pXform || status != icCmmStatOk) { + delete pApply; + return NULL; + } + pApply->AppendApplyXform(pXform); + } + + m_bValid = true; + + status = icCmmStatOk; + + return pApply; +} + + +/** +************************************************************************** +* Name: CIccCmm::Apply +* +* Purpose: +* Uses the m_pApply object allocated during Begin to Apply the transformations +* associated with the CMM. +* +************************************************************************** +*/ +icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) +{ + return m_pApply->Apply(DstPixel, SrcPixel); +} + + +/** +************************************************************************** +* Name: CIccCmm::Apply +* +* Purpose: +* Uses the m_pApply object allocated during Begin to Apply the transformations +* associated with the CMM. +* +************************************************************************** +*/ +icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) +{ + return m_pApply->Apply(DstPixel, SrcPixel, nPixels); +} + + +/** +************************************************************************** +* Name: CIccCmm::RemoveAllIO() +* +* Purpose: +* Remove any attachments to CIccIO objects associated with the profiles +* related to the transforms attached to the CMM. +* Must be called after Begin(). +* +* Return: +* icCmmStatOK - All IO objects removed +* icCmmStatBadXform - Begin() has not been performed. +************************************************************************** +*/ +icStatusCMM CIccCmm::RemoveAllIO() +{ + if (!Valid()) + return icCmmStatBadXform; + + CIccXformList::iterator i; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + i->ptr->RemoveIO(); + } + + return icCmmStatOk; +} + +/** + ************************************************************************* + ** Name: CIccCmm::IsInGamut + ** + ** Purpose: + ** Function to check if internal representation of gamut is in gamut. Note + ** since gamut table is 8 bit and a color is considered to be in out of gamut + ** if the value is not zero. Then we need to check where the 8 bit representation + ** of the internal value is not zero. + ** + ** Args: + ** pInternal = internal pixel representation of gamut value + ** + ** Return: + ** true if in gamut, false if out of gamut + **************************************************************************/ +bool CIccCmm::IsInGamut(icFloatNumber *pInternal) +{ + if (!((unsigned int)((*pInternal)*255.0))) + return true; + return false; +} + + +/** + ************************************************************************** + * Name: CIccCmm::ToInternalEncoding + * + * Purpose: + * Functions for converting to Internal representation of pixel colors. + * + * Args: + * nSpace = color space signature of the data, + * nEncode = icFloatColorEncoding type of the data, + * pInternal = converted data is stored here, + * pData = the data to be converted + * bClip = flag to clip to internal range + ************************************************************************** + */ +icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, + icFloatNumber *pInternal, const icFloatNumber *pData, + bool bClip) +{ + int nSamples = icGetSpaceSamples(nSpace); + if (!nSamples) + return icCmmStatBadColorEncoding; + + icUInt16Number i; + icFloatNumber pInput[16]; + memcpy(pInput, pData, nSamples*sizeof(icFloatNumber)); + bool bCLRspace = icIsSpaceCLR(nSpace); + + switch(nSpace) { + + case icSigLabData: + { + switch(nEncode) { + case icEncodeValue: + { + icLabToPcs(pInput); + break; + } + case icEncodeFloat: + { + break; + } + case icEncode8Bit: + { + pInput[0] = icU8toF((icUInt8Number)pInput[0])*100.0f; + pInput[1] = icU8toAB((icUInt8Number)pInput[1]); + pInput[2] = icU8toAB((icUInt8Number)pInput[2]); + + icLabToPcs(pInput); + break; + } + case icEncode16Bit: + { + pInput[0] = icU16toF((icUInt16Number)pInput[0]); + pInput[1] = icU16toF((icUInt16Number)pInput[1]); + pInput[2] = icU16toF((icUInt16Number)pInput[2]); + break; + } + case icEncode16BitV2: + { + pInput[0] = icU16toF((icUInt16Number)pInput[0]); + pInput[1] = icU16toF((icUInt16Number)pInput[1]); + pInput[2] = icU16toF((icUInt16Number)pInput[2]); + + CIccPCS::Lab2ToLab4(pInput, pInput); + break; + } + default: + return icCmmStatBadColorEncoding; + break; + } + break; + } + + case icSigXYZData: + { + switch(nEncode) { + case icEncodeValue: + { + pInput[0] = (icFloatNumber)pInput[0]; + pInput[1] = (icFloatNumber)pInput[1]; + pInput[2] = (icFloatNumber)pInput[2]; + icXyzToPcs(pInput); + break; + } + case icEncodePercent: + { + pInput[0] = (icFloatNumber)(pInput[0] / 100.0); + pInput[1] = (icFloatNumber)(pInput[1] / 100.0); + pInput[2] = (icFloatNumber)(pInput[2] / 100.0); + icXyzToPcs(pInput); + break; + } + case icEncodeFloat: + { + icXyzToPcs(pInput); + break; + } + + case icEncode16Bit: + case icEncode16BitV2: + { + pInput[0] = icUSFtoD((icU1Fixed15Number)pInput[0]); + pInput[1] = icUSFtoD((icU1Fixed15Number)pInput[1]); + pInput[2] = icUSFtoD((icU1Fixed15Number)pInput[2]); + break; + } + + default: + return icCmmStatBadColorEncoding; + break; + } + break; + } + + case icSigNamedData: + return icCmmStatBadColorEncoding; + + default: + { + switch(nEncode) { + case icEncodeValue: + { + if (!bCLRspace || nSamples<3) { + return icCmmStatBadColorEncoding; + } + icLabToPcs(pInput); + break; + } + + case icEncodePercent: + { + if (bClip) { + for(i=0; i 1.0) pInput[i] = 1.0; + } + } + else { + for(i=0; i 1.0) pInput[i] = 1.0; + } + } + break; + } + + case icEncode8Bit: + { + for(i=0; i 1.0) pInput[i] = 1.0; + pInput[i] = (icFloatNumber)(pInput[i]*100.0); + } + } + else { + for(i=0; i 1.0) pInput[i] = 1.0; + } + } + break; + } + + case icEncode8Bit: + { + for(i=0; isize(); +} + + +/** +************************************************************************** +* Name: CIccCmm::GetFirstXformSource +* +* Purpose: +* Get source colorspace of first transform (similar to m_nSrcSpace with differences in dev colorimetric spaces) +* +* Return: +* colorspace +************************************************************************** +*/ +icColorSpaceSignature CIccCmm::GetFirstXformSource() +{ + if (!m_Xforms->size()) + return m_nSrcSpace; + + return m_Xforms->begin()->ptr->GetSrcSpace(); +} + +/** +************************************************************************** +* Name: CIccCmm::GetNumXforms +* +* Purpose: +* Get source colorspace of last transform (similar to m_nSrcSpace with differences in dev colorimetric spaces) +* +* Return: +* colorspace +************************************************************************** +*/ +icColorSpaceSignature CIccCmm::GetLastXformDest() +{ + if (!m_Xforms->size()) + return m_nDestSpace; + + return m_Xforms->rbegin()->ptr->GetDstSpace(); +} + +/** +************************************************************************** +* Name: CIccApplyCmm::CIccApplyCmm +* +* Purpose: +* Constructor +* +* Args: +* pCmm = ptr to CMM to apply against +************************************************************************** +*/ +CIccApplyNamedColorCmm::CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm) : CIccApplyCmm(pCmm) +{ +} + + +/** +************************************************************************** +* Name: CIccApplyCmm::CIccApplyCmm +* +* Purpose: +* Destructor +************************************************************************** +*/ +CIccApplyNamedColorCmm::~CIccApplyNamedColorCmm() +{ +} + + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + int j, n = (int)m_Xforms->size(); + CIccApplyXform *pApply; + const CIccXform *pApplyXform; + CIccXformNamedColor *pXform; + + if (!n) + return icCmmStatBadXform; + + icChar NamedColor[256]; + icStatusCMM rv; + + m_pPCS->Reset(m_pCmm->GetSourceSpace()); + + pSrc = SrcPixel; + pDst = Pixel; + + if (n>1) { + for (j=0, i=m_Xforms->begin(); jend(); i++, j++) { + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyNamed2Pixel: + if (j==0) { + return icCmmStatIncorrectApply; + } + + rv = pXform->Apply(pApply, pDst, NamedColor); + + if (rv) { + return rv; + } + break; + + default: + break; + } + } + else { + pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); + } + pSrc = pDst; + } + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + default: + return icCmmStatIncorrectApply; + break; + + case icApplyNamed2Pixel: + rv = pXform->Apply(pApply, DstPixel, NamedColor); + if (rv) { + return rv; + } + break; + + } + } + else { + pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); + } + + } + else if (n==1) { + i = m_Xforms->begin(); + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + return icCmmStatIncorrectApply; + } + + pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); + } + + m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); + + return icCmmStatOk; +} + + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstPixel = Destination pixel where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + int j, n = (int)m_Xforms->size(); + CIccApplyXform *pApply; + const CIccXform *pApplyXform; + CIccXformNamedColor *pXform; + icUInt32Number k; + + if (!n) + return icCmmStatBadXform; + + icChar NamedColor[256]; + icStatusCMM rv; + + for (k=0; kReset(m_pCmm->GetSourceSpace()); + + pSrc = SrcPixel; + pDst = Pixel; + + if (n>1) { + for (j=0, i=m_Xforms->begin(); jend(); i++, j++) { + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyNamed2Pixel: + if (j==0) { + return icCmmStatIncorrectApply; + } + + rv = pXform->Apply(pApply, pDst, NamedColor); + + if (rv) { + return rv; + } + break; + + default: + break; + } + } + else { + pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); + } + pSrc = pDst; + } + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + default: + return icCmmStatIncorrectApply; + break; + + case icApplyNamed2Pixel: + rv = pXform->Apply(pApply, DstPixel, NamedColor); + if (rv) { + return rv; + } + break; + + } + } + else { + pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); + } + + } + else if (n==1) { + i = m_Xforms->begin(); + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + return icCmmStatIncorrectApply; + } + + pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); + } + + m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); + + SrcPixel += m_pCmm->GetSourceSamples(); + DstPixel += m_pCmm->GetDestSamples(); + } + + return icCmmStatOk; +} + + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstColorName = Destination string where the result is stored, +* SrcPixel = Source pixel which is to be applied. +************************************************************************** +*/ +icStatusCMM CIccApplyNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + int j, n = (int)m_Xforms->size(); + CIccApplyXform *pApply; + const CIccXform *pApplyXform; + CIccXformNamedColor *pXform; + + if (!n) + return icCmmStatBadXform; + + icChar NamedColor[256]; + icStatusCMM rv; + + m_pPCS->Reset(m_pCmm->GetSourceSpace()); + + pSrc = SrcPixel; + pDst = Pixel; + + if (n>1) { + for (j=0, i=m_Xforms->begin(); jend(); i++, j++) { + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyNamed2Pixel: + if (j==0) { + return icCmmStatIncorrectApply; + } + rv = pXform->Apply(pApply, pDst, NamedColor); + if (rv) { + return rv; + } + break; + + default: + break; + } + } + else { + pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); + } + pSrc = pDst; + } + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + switch(pXform->GetInterface()) { + + case icApplyPixel2Named: + pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Pixel: + case icApplyNamed2Pixel: + default: + return icCmmStatIncorrectApply; + break; + } + } + else { + return icCmmStatIncorrectApply; + } + + } + else if (n==1) { + i = m_Xforms->begin(); + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()!=icXformTypeNamedColor) { + return icCmmStatIncorrectApply; + } + + pXform = (CIccXformNamedColor*)pApplyXform; + pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); + } + + return icCmmStatOk; +} + + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstPixel = Destination pixel where the result is stored, +* SrcColorName = Source color name which is to be searched. +************************************************************************** +*/ +icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + int j, n = (int)m_Xforms->size(); + CIccApplyXform *pApply; + const CIccXform *pApplyXform; + CIccXformNamedColor *pXform; + + if (!n) + return icCmmStatBadXform; + + icChar NamedColor[256]; + icStatusCMM rv; + + i=m_Xforms->begin(); + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()!=icXformTypeNamedColor) + return icCmmStatIncorrectApply; + + pXform = (CIccXformNamedColor*)pApplyXform; + m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS()); + + pDst = Pixel; + + if (n>1) { + rv = pXform->Apply(pApply, pDst, SrcColorName); + if (rv) { + return rv; + } + + pSrc = pDst; + + for (j=0, i++; jend(); i++, j++) { + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + CIccXformNamedColor *pXform = (CIccXformNamedColor*)pApplyXform; + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyNamed2Pixel: + rv = pXform->Apply(pApply, pDst, NamedColor); + if (rv) { + return rv; + } + break; + + default: + break; + } + } + else { + pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); + } + pSrc = pDst; + } + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Named: + default: + return icCmmStatIncorrectApply; + break; + + case icApplyNamed2Pixel: + rv = pXform->Apply(pApply, DstPixel, NamedColor); + if (rv) { + return rv; + } + break; + + } + } + else { + pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); + } + + } + else if (n==1) { + rv = pXform->Apply(pApply, DstPixel, SrcColorName); + if (rv) { + return rv; + } + m_pPCS->Check(DstPixel, pXform); + } + + m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); + + return icCmmStatOk; +} + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstColorName = Destination string where the result is stored, +* SrcColorName = Source color name which is to be searched. +************************************************************************** +*/ +icStatusCMM CIccApplyNamedColorCmm::Apply(icChar *DstColorName, const icChar *SrcColorName) +{ + icFloatNumber Pixel[16], *pDst; + const icFloatNumber *pSrc; + CIccApplyXformList::iterator i; + int j, n = (int)m_Xforms->size(); + icChar NamedColor[256]; + icStatusCMM rv; + CIccApplyXform *pApply; + const CIccXform *pApplyXform; + CIccXformNamedColor *pXform; + + if (!n) + return icCmmStatBadXform; + + i=m_Xforms->begin(); + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()!=icXformTypeNamedColor) + return icCmmStatIncorrectApply; + + pXform = (CIccXformNamedColor*)pApplyXform; + + m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS()); + + pDst = Pixel; + + if (n>1) { + rv = pXform->Apply(pApply, pDst, SrcColorName); + + if (rv) { + return rv; + } + + pSrc = pDst; + + for (j=0, i++; jend(); i++, j++) { + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + switch(pXform->GetInterface()) { + case icApplyPixel2Pixel: + pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); + break; + + + case icApplyPixel2Named: + pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyNamed2Pixel: + rv = pXform->Apply(pApply, pDst, NamedColor); + if (rv) { + return rv; + } + break; + + default: + break; + } + } + else { + pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); + } + pSrc = pDst; + } + + pApply = i->ptr; + pApplyXform = pApply->GetXform(); + if (pApplyXform->GetXformType()==icXformTypeNamedColor) { + pXform = (CIccXformNamedColor*)pApplyXform; + switch(pXform->GetInterface()) { + case icApplyPixel2Named: + pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); + break; + + case icApplyPixel2Pixel: + case icApplyNamed2Pixel: + default: + return icCmmStatIncorrectApply; + break; + } + } + else { + return icCmmStatIncorrectApply; + } + + } + else if (n==1) { + return icCmmStatIncorrectApply; + } + + return icCmmStatOk; +} + +/** + ************************************************************************** + * Name: CIccNamedColorCmm::CIccNamedColorCmm + * + * Purpose: + * Constructor + * + * Args: + * nSrcSpace = signature of the source color space, + * nDestSpace = signature of the destination color space, + * bFirstInput = true if the first profile added is an input profile + ************************************************************************** + */ +CIccNamedColorCmm::CIccNamedColorCmm(icColorSpaceSignature nSrcSpace, icColorSpaceSignature nDestSpace, + bool bFirstInput) : CIccCmm(nSrcSpace, nDestSpace, bFirstInput) +{ + m_nApplyInterface = icApplyPixel2Pixel; +} + +/** + ************************************************************************** + * Name: CIccNamedColorCmm::~CIccNamedColorCmm + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccNamedColorCmm::~CIccNamedColorCmm() +{ +} + + +/** + ************************************************************************** + * Name: CIccNamedColorCmm::AddXform + * + * Purpose: + * Adds a profile at the end of the Xform list + * + * Args: + * szProfilePath = file name of the profile to be added, + * nIntent = rendering intent to be used with the profile, + * nInterp = type of interpolation to be used with the profile + * pHintManager = hints for creating the xform + * + * Return: + * icCmmStatOk, if the profile was added to the list succesfully + ************************************************************************** + */ +icStatusCMM CIccNamedColorCmm::AddXform(const icChar *szProfilePath, + icRenderingIntent nIntent /*=icUnknownIntent*/, + icXformInterp nInterp /*icXformInterp*/, + icXformLutType nLutType /*=icXformLutColor*/, + bool bUseMpeTags /*=true*/, + CIccCreateXformHintManager *pHintManager /*=NULL*/) +{ + CIccProfile *pProfile = OpenIccProfile(szProfilePath); + + if (!pProfile) + return icCmmStatCantOpenProfile; + + icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (rv != icCmmStatOk) + delete pProfile; + + return rv; +} + +/** + ************************************************************************** + * Name: CIccNamedColorCmm::AddXform + * + * Purpose: + * Adds a profile at the end of the Xform list + * + * Args: + * pProfile = pointer to the CIccProfile object to be added, + * nIntent = rendering intent to be used with the profile, + * nInterp = type of interpolation to be used with the profile + * nLutType = type of lut to use from the profile + * pHintManager = hints for creating the xform + * + * Return: + * icCmmStatOk, if the profile was added to the list succesfully + ************************************************************************** + */ +icStatusCMM CIccNamedColorCmm::AddXform(CIccProfile *pProfile, + icRenderingIntent nIntent /*=icUnknownIntent*/, + icXformInterp nInterp /*=icInterpLinear*/, + icXformLutType nLutType /*=icXformLutColor*/, + bool bUseMpeTags /*=true*/, + CIccCreateXformHintManager *pHintManager /*=NULL*/) +{ + icColorSpaceSignature nSrcSpace, nDstSpace; + CIccXformPtr Xform; + bool bInput = !m_bLastInput; + icStatusCMM rv; + + Xform.ptr = NULL; + switch (nLutType) { + //Automatically choose which one + case icXformLutColor: + case icXformLutNamedColor: + { + CIccTagNamedColor2 *pTag = (CIccTagNamedColor2*)pProfile->FindTag(icSigNamedColor2Tag); + + if (pTag && (pProfile->m_Header.deviceClass==icSigNamedColorClass || nLutType==icXformLutNamedColor)) { + if (bInput) { + nSrcSpace = icSigNamedData; + } + else { + nSrcSpace = pProfile->m_Header.pcs; + } + + if (!m_Xforms->size()) { + if (m_nSrcSpace==icSigUnknownData) { + m_nSrcSpace = nSrcSpace; + } + else { + nSrcSpace = m_nSrcSpace; + } + } + else { + if (m_nLastSpace==icSigUnknownData) { + m_nLastSpace = nSrcSpace; + } + else { + nSrcSpace = m_nLastSpace; + } + } + + if (nSrcSpace==icSigNamedData) { + nDstSpace = pProfile->m_Header.pcs; + bInput = true; + } + else { + nDstSpace = icSigNamedData; + bInput = false; + } + + Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, icXformLutNamedColor, bUseMpeTags, pHintManager); + if (!Xform.ptr) { + return icCmmStatBadXform; + } + CIccXformNamedColor *pXform = (CIccXformNamedColor *)Xform.ptr; + rv = pXform->SetSrcSpace(nSrcSpace); + if (rv) + return rv; + + rv = pXform->SetDestSpace(nDstSpace); + if (rv) + return rv; + } + else { + //It isn't named color so make we will use color lut. + nLutType = icXformLutColor; + + //Check pProfile if nIntent and input can be found. + if (bInput) { + nSrcSpace = pProfile->m_Header.colorSpace; + nDstSpace = pProfile->m_Header.pcs; + } + else { + if (pProfile->m_Header.deviceClass == icSigLinkClass) { + return icCmmStatBadSpaceLink; + } + if (pProfile->m_Header.deviceClass == icSigAbstractClass) { + bInput = true; + nIntent = icPerceptual; // Note: icPerceptualIntent = 0 + } + nSrcSpace = pProfile->m_Header.pcs; + nDstSpace = pProfile->m_Header.colorSpace; + } + } + } + break; + + case icXformLutPreview: + nSrcSpace = pProfile->m_Header.pcs; + nDstSpace = pProfile->m_Header.pcs; + bInput = false; + break; + + case icXformLutGamut: + nSrcSpace = pProfile->m_Header.pcs; + nDstSpace = icSigGamutData; + bInput = true; + break; + + default: + return icCmmStatBadLutType; + } + + //Make sure color spaces match with previous xforms + if (!m_Xforms->size()) { + if (m_nSrcSpace == icSigUnknownData) { + m_nLastSpace = nSrcSpace; + m_nSrcSpace = nSrcSpace; + } + else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)) { + return icCmmStatBadSpaceLink; + } + } + else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)) { + return icCmmStatBadSpaceLink; + } + + //Automatic creation of intent from header/last profile + if (nIntent==icUnknownIntent) { + if (bInput) { + nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; + } + else { + nIntent = m_nLastIntent; + } + if (nIntent == icUnknownIntent) + nIntent = icPerceptual; + } + + if (!Xform.ptr) + Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, nLutType, bUseMpeTags, pHintManager); + + if (!Xform.ptr) { + return icCmmStatBadXform; + } + + m_nLastSpace = nDstSpace; + m_nLastIntent = nIntent; + m_bLastInput = bInput; + + m_Xforms->push_back(Xform); + + return icCmmStatOk; +} + +/** + ************************************************************************** + * Name: CIccNamedColorCmm::Begin + * + * Purpose: + * Does the initialization of the Xforms in the list before Apply() is called. + * Must be called before Apply(). + * + ************************************************************************** + */ + icStatusCMM CIccNamedColorCmm::Begin(bool bAllocNewApply/* =true */) +{ + if (m_nDestSpace==icSigUnknownData) { + m_nDestSpace = m_nLastSpace; + } + else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)) { + return icCmmStatBadSpaceLink; + } + + if (m_nSrcSpace != icSigNamedData) { + if (m_nDestSpace != icSigNamedData) { + m_nApplyInterface = icApplyPixel2Pixel; + } + else { + m_nApplyInterface = icApplyPixel2Named; + } + } + else { + if (m_nDestSpace != icSigNamedData) { + m_nApplyInterface = icApplyNamed2Pixel; + } + else { + m_nApplyInterface = icApplyNamed2Named; + } + } + + icStatusCMM rv; + CIccXformList::iterator i; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + rv = i->ptr->Begin(); + + if (rv!= icCmmStatOk) { + return rv; + } + } + + if (bAllocNewApply) { + m_pApply = GetNewApplyCmm(rv); + } + else + rv = icCmmStatOk; + + return rv; +} + + /** + ************************************************************************** + * Name: CIccNamedColorCmm::GetNewApply + * + * Purpose: + * Allocates a CIccApplyCmm object that allows one to call apply from + * multiple threads. + * + ************************************************************************** + */ + CIccApplyCmm *CIccNamedColorCmm::GetNewApply(icStatusCMM &status) + { + CIccApplyCmm *pApply = new CIccApplyNamedColorCmm(this); + + CIccXformList::iterator i; + + for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { + CIccApplyXform *pXform = i->ptr->GetNewApply(status); + if (status != icCmmStatOk || !pXform) { + delete pApply; + return NULL; + } + pApply->AppendApplyXform(pXform); + } + + m_bValid = true; + + status = icCmmStatOk; + return pApply; +} + + + /** + ************************************************************************** + * Name: CIccApplyNamedColorCmm::Apply + * + * Purpose: + * Does the actual application of the Xforms in the list. + * + * Args: + * DstColorName = Destination string where the result is stored, + * SrcPoxel = Source pixel + ************************************************************************** + */ +icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel) +{ + return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcPixel); +} + + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DestPixel = Destination pixel where the result is stored, +* SrcColorName = Source color name which is to be searched. +************************************************************************** +*/ +icStatusCMM CIccNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName) +{ + return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstPixel, SrcColorName); +} + + +/** +************************************************************************** +* Name: CIccApplyNamedColorCmm::Apply +* +* Purpose: +* Does the actual application of the Xforms in the list. +* +* Args: +* DstColorName = Destination string where the result is stored, +* SrcColorName = Source color name which is to be searched. +************************************************************************** +*/ +icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icChar *SrcColorName) +{ + return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcColorName); +} + + +/** + ************************************************************************** + * Name: CIccNamedColorCmm::SetLastXformDest + * + * Purpose: + * Sets the destination Color space of the last Xform in the list + * + * Args: + * nDestSpace = signature of the color space to be set + ************************************************************************** + */ +icStatusCMM CIccNamedColorCmm::SetLastXformDest(icColorSpaceSignature nDestSpace) +{ + int n = (int)m_Xforms->size(); + CIccXformPtr *pLastXform; + + if (!n) + return icCmmStatBadXform; + + pLastXform = &m_Xforms->back(); + + if (pLastXform->ptr->GetXformType()==icXformTypeNamedColor) { + CIccXformNamedColor *pXform = (CIccXformNamedColor *)pLastXform->ptr; + if (pXform->GetSrcSpace() == icSigNamedData && + nDestSpace == icSigNamedData) { + return icCmmStatBadSpaceLink; + } + + if (nDestSpace != icSigNamedData && + pXform->GetDstSpace() == icSigNamedData) { + return icCmmStatBadSpaceLink; + } + + return pXform->SetDestSpace(nDestSpace); + } + + return icCmmStatBadXform; +} + + +/** +**************************************************************************** +* Name: CIccMruCmm::CIccMruCmm +* +* Purpose: private constructor - Use Attach to create CIccMruCmm objects +***************************************************************************** +*/ +CIccMruCmm::CIccMruCmm() +{ + m_pCmm = NULL; +} + + +/** +**************************************************************************** +* Name: CIccMruCmm::~CIccMruCmm +* +* Purpose: destructor +***************************************************************************** +*/ +CIccMruCmm::~CIccMruCmm() +{ + if (m_pCmm) + delete m_pCmm; +} + + +/** +**************************************************************************** +* Name: CIccMruCmm::Attach +* +* Purpose: Create a Cmm decorator object that implements a cache of most +* recently used pixel transformations. +* +* Args: +* pCmm - pointer to cmm object that we are attaching to. +* nCacheSize - number of most recently used transformations to cache +* +* Return: +* A CIccMruCmm object that represents a cached form of the pCmm passed in. +* The pCmm will be owned by the returned object. +* +* If this function fails the pCmm object will be deleted. +***************************************************************************** +*/ +CIccMruCmm* CIccMruCmm::Attach(CIccCmm *pCmm, icUInt8Number nCacheSize/* =4 */) +{ + if (!pCmm || !nCacheSize) + return NULL; + + if (!pCmm->Valid()) { + delete pCmm; + return NULL; + } + + CIccMruCmm *rv = new CIccMruCmm(); + + rv->m_pCmm = pCmm; + rv->m_nCacheSize = nCacheSize; + + rv->m_nSrcSpace = pCmm->GetSourceSpace(); + rv->m_nDestSpace = pCmm->GetDestSpace(); + rv->m_nLastSpace = pCmm->GetLastSpace(); + rv->m_nLastIntent = pCmm->GetLastIntent(); + + if (rv->Begin()!=icCmmStatOk) { + delete rv; + return NULL; + } + + return rv; +} + +CIccApplyCmm *CIccMruCmm::GetNewApplyCmm(icStatusCMM &status) +{ + CIccApplyMruCmm *rv = new CIccApplyMruCmm(this); + + if (!rv) { + status = icCmmStatAllocErr; + return NULL; + } + + if (!rv->Init(m_pCmm, m_nCacheSize)) { + delete rv; + status = icCmmStatBad; + return NULL; + } + + return rv; +} + + +CIccApplyMruCmm::CIccApplyMruCmm(CIccMruCmm *pCmm) : CIccApplyCmm(pCmm) +{ + m_cache = NULL; + + m_pixelData = NULL; +} + +/** +**************************************************************************** +* Name: CIccApplyMruCmm::~CIccApplyMruCmm +* +* Purpose: destructor +***************************************************************************** +*/ +CIccApplyMruCmm::~CIccApplyMruCmm() +{ + if (m_cache) + delete [] m_cache; + + if (m_pixelData) + free(m_pixelData); +} + +/** +**************************************************************************** +* Name: CIccApplyMruCmm::Init +* +* Purpose: Initialize the object and set up the cache +* +* Args: +* pCmm - pointer to cmm object that we are attaching to. +* nCacheSize - number of most recently used transformations to cache +* +* Return: +* true if successful +***************************************************************************** +*/ +bool CIccApplyMruCmm::Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize) +{ + m_pCachedCmm = pCachedCmm; + + m_nSrcSamples = m_pCmm->GetSourceSamples(); + m_nSrcSize = m_nSrcSamples * sizeof(icFloatNumber); + m_nDstSize = m_pCmm->GetDestSamples() * sizeof(icFloatNumber); + + m_nTotalSamples = m_nSrcSamples + m_pCmm->GetDestSamples(); + + m_nNumPixel = 0; + m_nCacheSize = nCacheSize; + + m_pFirst = NULL; + m_cache = new CIccMruPixel[nCacheSize]; + + if (!m_cache) + return false; + + m_pixelData = (icFloatNumber*)malloc(nCacheSize * m_nTotalSamples * sizeof(icFloatNumber)); + + if (!m_pixelData) + return false; + + return true; +} + +/** +**************************************************************************** +* Name: CIccMruCmm::Apply +* +* Purpose: Apply a transformation to a pixel. +* +* Args: +* DstPixel - Location to store pixel results +* SrcPixel - Location to get pixel values from +* +* Return: +* icCmmStatOk if successful +***************************************************************************** +*/ +icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) +{ + CIccMruPixel *ptr, *prev=NULL, *last=NULL; + int i; + icFloatNumber *pixel; + + for (ptr = m_pFirst, i=0; ptr; ptr=ptr->pNext, i++) { + if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) { + memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize); + return icCmmStatOk; + } + prev = last; + last = ptr; + } + + //If we get here SrcPixel is not in the cache + if (ipPixelData = pixel; + + if (!last) { + m_pFirst = ptr; + } + else { + + last->pNext = ptr; + } + } + else { //Reuse oldest value and put it at the front of the list + prev->pNext = NULL; + last->pNext = m_pFirst; + + m_pFirst = last; + pixel = last->pPixelData; + } + icFloatNumber *dest = &pixel[m_nSrcSamples]; + + memcpy(pixel, SrcPixel, m_nSrcSize); + + m_pCachedCmm->Apply(dest, pixel); + + memcpy(DstPixel, dest, m_nDstSize); + + return icCmmStatOk; +} + +/** +**************************************************************************** +* Name: CIccMruCmm::Apply +* +* Purpose: Apply a transformation to a pixel. +* +* Args: +* DstPixel - Location to store pixel results +* SrcPixel - Location to get pixel values from +* nPixels - number of pixels to convert +* +* Return: +* icCmmStatOk if successful +***************************************************************************** +*/ +icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) +{ + CIccMruPixel *ptr, *prev=NULL, *last=NULL; + int i; + icFloatNumber *pixel, *dest; + icUInt32Number k; + + for (k=0; kpNext, i++) { + if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) { + memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize); + goto next_k; + } + prev = last; + last = ptr; + } + + //If we get here SrcPixel is not in the cache + if (ipPixelData = pixel; + + if (!last) { + m_pFirst = ptr; + } + else { + + last->pNext = ptr; + } + } + else { //Reuse oldest value and put it at the front of the list + prev->pNext = NULL; + last->pNext = m_pFirst; + + m_pFirst = last; + pixel = last->pPixelData; + } + dest = &pixel[m_nSrcSamples]; + + memcpy(pixel, SrcPixel, m_nSrcSize); + + m_pCachedCmm->Apply(dest, pixel); + + memcpy(DstPixel, dest, m_nDstSize); + +next_k: + k++; + } + + return icCmmStatOk; +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccCmm.h b/library/src/main/cpp/icc/IccCmm.h new file mode 100644 index 00000000..4e450ca0 --- /dev/null +++ b/library/src/main/cpp/icc/IccCmm.h @@ -0,0 +1,1141 @@ +/** @file + File: IccCmm.h + + Contains: Header file for implementation of the CIccCmm class. + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// -Added support for Monochrome ICC profile apply by Rohit Patil 12-03-2008 +// -Integrate changes for PCS adjustment by George Pawle 12-09-2008 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCCMM_H) +#define _ICCCMM_H + +#include "IccProfile.h" +#include "IccTag.h" +#include "IccUtil.h" +#include +#include +#include + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/// CMM return status values +typedef enum { + icCmmStatBad = -1, + icCmmStatOk = 0, + icCmmStatCantOpenProfile = 1, + icCmmStatBadSpaceLink = 2, + icCmmStatInvalidProfile = 3, + icCmmStatBadXform = 4, + icCmmStatInvalidLut = 5, + icCmmStatProfileMissingTag = 6, + icCmmStatColorNotFound = 7, + icCmmStatIncorrectApply = 8, + icCmmStatBadColorEncoding = 9, + icCmmStatAllocErr = 10, + icCmmStatBadLutType = 11, +} icStatusCMM; + +/// CMM Interpolation types +typedef enum { + icInterpLinear = 0, + icInterpTetrahedral = 1, +} icXformInterp; + +/// CMM Xform LUT types +typedef enum { + icXformLutColor = 0, + icXformLutNamedColor = 1, + icXformLutPreview = 2, + icXformLutGamut = 3, +} icXformLutType; + +#define icPerceptualRefBlackX 0.00336 +#define icPerceptualRefBlackY 0.0034731 +#define icPerceptualRefBlackZ 0.00287 + +#define icPerceptualRefWhiteX 0.9642 +#define icPerceptualRefWhiteY 1.0000 +#define icPerceptualRefWhiteZ 0.8249 + +// CMM Xform types +typedef enum { + icXformTypeMatrixTRC = 0, + icXformType3DLut = 1, + icXformType4DLut = 2, + icXformTypeNDLut = 3, + icXformTypeNamedColor = 4, //Creator uses icNamedColorXformHint + icXformTypeMpe = 5, + icXformTypeMonochrome = 6, + + icXformTypeUnknown = 0x7ffffff, +} icXformType; + +/** +************************************************************************** +* Type: Class +* +* Purpose: +* Interface for creation of a named xform hint +************************************************************************** +*/ +class ICCPROFLIB_API IIccCreateXformHint +{ +public: + virtual const char *GetHintType() const=0; +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: +* Manages the named xform hints +************************************************************************** +*/ +class ICCPROFLIB_API CIccCreateXformHintManager +{ +public: + CIccCreateXformHintManager() { m_pList = NULL; } + ~CIccCreateXformHintManager(); + + /// Adds and owns the passed named hint to it's list + bool AddHint(IIccCreateXformHint* pHint); + + /// Deletes the object referenced by the passed named hint pointer and removes it from the list + bool DeleteHint(IIccCreateXformHint* pHint); + + /// Finds and returns a pointer to the named hint + IIccCreateXformHint* GetHint(const char* hintName); + +private: + // private hint ptr class + class IIccCreateXformHintPtr { + public: + IIccCreateXformHint* ptr; + }; + typedef std::list IIccCreateXformHintList; + + // private members + IIccCreateXformHintList* m_pList; +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: +* Hint for creation of a named color xform +************************************************************************** +*/ +class ICCPROFLIB_API CIccCreateNamedColorXformHint : public IIccCreateXformHint +{ +public: + virtual const char *GetHintType() const {return "CIccCreateNamedColorXformHint";} + + icColorSpaceSignature csPcs; + icColorSpaceSignature csDevice; +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: +* Interface for calculating adjust PCS factors +************************************************************************** +*/ +class CIccXform; +class ICCPROFLIB_API IIccAdjustPCSXform +{ +public: + virtual ~IIccAdjustPCSXform() {} + virtual bool CalcFactors(const CIccProfile* pProfile, const CIccXform* pXfm, icFloatNumber* Scale, icFloatNumber* Offset) const=0; +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: +* Hint for calculating adjust PCS factors +************************************************************************** +*/ +class ICCPROFLIB_API CIccCreateAdjustPCSXformHint : public IIccCreateXformHint +{ +public: + virtual const char *GetHintType() const {return "CIccCreateAdjustPCSXformHint";} + virtual const char *GetAdjustPCSType() const=0; + virtual IIccAdjustPCSXform *GetNewAdjustPCSXform() const=0; +}; + +//forward reference to CIccXform used by CIccApplyXform +class CIccApplyXform; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: + * This is the base CMM xform object. A general static creation function, + * base behavior, and data are defined. The Create() function will assign + * a profile to the class. The CIccProfile object will then be owned by the + * xform object and later deleted when the IccXform is deleted. + ************************************************************************** + */ +class ICCPROFLIB_API CIccXform +{ +public: + CIccXform(); + virtual ~CIccXform(); + + virtual icXformType GetXformType() const = 0; + + ///Note: The returned CIccXform will own the profile. + static CIccXform *Create(CIccProfile *pProfile, bool bInput=true, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); + + ///Note: Provide an interface to work profile references. The IccProfile is copied, and the copy's ownership + ///is turned over to the Returned CIccXform object. + static CIccXform *Create(CIccProfile &pProfile, bool bInput=true, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); + + virtual icStatusCMM Begin(); + + virtual CIccApplyXform *GetNewApply(icStatusCMM &status); + + virtual void Apply(CIccApplyXform *pXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const = 0; + + //Detach and remove CIccIO object associated with xform's profile. Must call after Begin() + virtual bool RemoveIO() { return m_pProfile->Detach(); } + + ///Returns the source color space of the transform + virtual icColorSpaceSignature GetSrcSpace() const; + + ///Returns the destination color space of the transform + virtual icColorSpaceSignature GetDstSpace() const; + + ///Checks if version 2 PCS is to be used + virtual bool UseLegacyPCS() const { return false; } + ///Checks if the profile is version 2 + virtual bool IsVersion2() const { return !m_pProfile || m_pProfile->m_Header.version < icVersionNumberV4; } + + ///Checks if the profile is to be used as input profile + bool IsInput() const { return m_bInput; } + + /// The following function is for Overridden create function + void SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent, icXformInterp nInterp, CIccCreateXformHintManager *pHintManager=NULL); + + /// Use these functions to extract the input/output curves from the xform + virtual LPIccCurve* ExtractInputCurves()=0; + virtual LPIccCurve* ExtractOutputCurves()=0; + + virtual bool NoClipPCS() const { return false; } + + /// Returns the profile pointer. Profile is still owned by the Xform. + const CIccProfile* GetProfile() const { return m_pProfile; } + + /// Returns the rendering intent being used by the Xform + icRenderingIntent GetIntent() const { return m_nIntent; } + +protected: + //Called by derived classes to initialize Base + + const icFloatNumber *CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const; + void CheckDstAbs(icFloatNumber *Pixel) const; + void AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual bool HasPerceptualHandling() { return true; } + + CIccProfile *m_pProfile; + bool m_bInput; + icRenderingIntent m_nIntent; + icXYZNumber m_MediaXYZ; + icXformInterp m_nInterp; + + // track PCS adjustments + IIccAdjustPCSXform* m_pAdjustPCS; + bool m_bAdjustPCS; + icFloatNumber m_PCSScale[3]; // scale and offset for PCS adjustment in XYZ + icFloatNumber m_PCSOffset[3]; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: Pointer to the Cmm Xform object + ************************************************************************** + */ +class ICCPROFLIB_API CIccXformPtr { +public: + CIccXform *ptr; +}; + + +/** + ************************************************************************** + * Type: List Class + * + * Purpose: List of CIccXformPtr which is updated on addition of Xforms + ************************************************************************** + */ +typedef std::list CIccXformList; + + +/** +************************************************************************** +* Type: Class +* +* Purpose: The Apply Cmm Xform object (Allows xforms to have apply time data) +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyXform +{ + friend class CIccXform; +public: + virtual ~CIccApplyXform(); + virtual icXformType GetXformType() const { return icXformTypeUnknown; } + + void __inline Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) { m_pXform->Apply(this, DstPixel, SrcPixel); } + + const CIccXform *GetXform() { return m_pXform; } + +protected: + icFloatNumber m_AbsLab[3]; + + CIccApplyXform(CIccXform *pXform); + + const CIccXform *m_pXform; +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: Pointer to the Apply Cmm Xform object +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyXformPtr { +public: + CIccApplyXform *ptr; +}; + + +/** +************************************************************************** +* Type: List Class +* +* Purpose: List of CIccApplyXformPtr which is updated on addition of Apply Xforms +************************************************************************** +*/ +typedef std::list CIccApplyXformList; + +/** +************************************************************************** +* Type: Class +* +* Purpose: This is the general Monochrome Xform (uses a grayTRCTag) +* +************************************************************************** +*/ +class ICCPROFLIB_API CIccXformMonochrome : public CIccXform +{ +public: + CIccXformMonochrome(); + virtual ~CIccXformMonochrome(); + + virtual icXformType GetXformType() const { return icXformTypeMonochrome; } + + virtual icStatusCMM Begin(); + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual LPIccCurve* ExtractInputCurves(); + virtual LPIccCurve* ExtractOutputCurves(); + +protected: + + virtual bool HasPerceptualHandling() { return false; } + + CIccCurve *m_Curve; + CIccCurve *GetCurve(icSignature sig) const; + CIccCurve *GetInvCurve(icSignature sig) const; + + bool m_bFreeCurve; + /// used only when applying the xform + LPIccCurve m_ApplyCurvePtr; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: This is the general Matrix-TRC Xform + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccXformMatrixTRC : public CIccXform +{ +public: + CIccXformMatrixTRC(); + virtual ~CIccXformMatrixTRC(); + + virtual icXformType GetXformType() const { return icXformTypeMatrixTRC; } + + virtual icStatusCMM Begin(); + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual LPIccCurve* ExtractInputCurves(); + virtual LPIccCurve* ExtractOutputCurves(); + +protected: + + virtual bool HasPerceptualHandling() { return false; } + + icFloatNumber m_e[9]; + CIccCurve *m_Curve[3]; + CIccCurve *GetCurve(icSignature sig) const; + CIccCurve *GetInvCurve(icSignature sig) const; + + CIccTagXYZ *GetColumn(icSignature sig) const; + bool m_bFreeCurve; + /// used only when applying the xform + const LPIccCurve* m_ApplyCurvePtr; +}; + + +/** + ************************************************************************** + * Type: Class + * + * Purpose: This is the general 3D-LUT Xform + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccXform3DLut : public CIccXform +{ +public: + CIccXform3DLut(CIccTag *pTag); + virtual ~CIccXform3DLut(); + + virtual icXformType GetXformType() const { return icXformType3DLut; } + + virtual icStatusCMM Begin(); + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); } + + virtual LPIccCurve* ExtractInputCurves(); + virtual LPIccCurve* ExtractOutputCurves(); +protected: + + const CIccMBB *m_pTag; + + /// Pointers to data in m_pTag, used only for applying the xform + const LPIccCurve* m_ApplyCurvePtrA; + const LPIccCurve* m_ApplyCurvePtrB; + const LPIccCurve* m_ApplyCurvePtrM; + const CIccMatrix* m_ApplyMatrixPtr; +}; + + +/** + ************************************************************************** + * Type: Class + * + * Purpose: This is the general 4D-LUT Xform + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccXform4DLut : public CIccXform +{ +public: + CIccXform4DLut(CIccTag *pTag); + virtual ~CIccXform4DLut(); + + virtual icXformType GetXformType() const { return icXformType4DLut; } + + virtual icStatusCMM Begin(); + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); } + + virtual LPIccCurve* ExtractInputCurves(); + virtual LPIccCurve* ExtractOutputCurves(); +protected: + const CIccMBB *m_pTag; + + /// Pointers to data in m_pTag, used only for applying the xform + const LPIccCurve* m_ApplyCurvePtrA; + const LPIccCurve* m_ApplyCurvePtrB; + const LPIccCurve* m_ApplyCurvePtrM; + const CIccMatrix* m_ApplyMatrixPtr; +}; + + +/** + ************************************************************************** + * Type: Class + * + * Purpose: This is the general ND-LUT Xform + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccXformNDLut : public CIccXform +{ +public: + CIccXformNDLut(CIccTag *pTag); + virtual ~CIccXformNDLut(); + + virtual icXformType GetXformType() const { return icXformTypeNDLut; } + + virtual icStatusCMM Begin(); + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); } + + virtual LPIccCurve* ExtractInputCurves(); + virtual LPIccCurve* ExtractOutputCurves(); +protected: + const CIccMBB *m_pTag; + int m_nNumInput; + + /// Pointers to data in m_pTag, used only for applying the xform + const LPIccCurve* m_ApplyCurvePtrA; + const LPIccCurve* m_ApplyCurvePtrB; + const LPIccCurve* m_ApplyCurvePtrM; + const CIccMatrix* m_ApplyMatrixPtr; +}; + + + +/** + ************************************************************************** + * Type: Enum + * + * Purpose: Defines the interface to be used when applying Named Color + * Profiles. + * + ************************************************************************** + */ +typedef enum { + icApplyPixel2Pixel = 0, + icApplyNamed2Pixel = 1, + icApplyPixel2Named = 2, + icApplyNamed2Named = 3, +} icApplyInterface; + + + +/** + ************************************************************************** + * Type: Class + * + * Purpose: This is the general Xform for Named Color Profiles. + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccXformNamedColor : public CIccXform +{ +public: + CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPCS, icColorSpaceSignature csDevice); + virtual ~CIccXformNamedColor(); + + virtual icXformType GetXformType() const { return icXformTypeNamedColor; } + + virtual icStatusCMM Begin(); + + ///Returns the type of interface that will be applied + icApplyInterface GetInterface() const {return m_nApplyInterface;} + + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const {} + + icStatusCMM Apply(CIccApplyXform *pApplyXform, icChar *DstColorName, const icFloatNumber *SrcPixel) const; + icStatusCMM Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icChar *SrcColorName) const; + + virtual bool UseLegacyPCS() const { return m_pTag->UseLegacyPCS(); } + + icStatusCMM SetSrcSpace(icColorSpaceSignature nSrcSpace); + icStatusCMM SetDestSpace(icColorSpaceSignature nDestSpace); + + ///Returns the source color space of the transform + icColorSpaceSignature GetSrcSpace() const { return m_nSrcSpace; } + ///Returns the destination color space of the transform + icColorSpaceSignature GetDstSpace() const { return m_nDestSpace; } + + ///Checks if the source space of the transform is PCS + bool IsSrcPCS() const {return m_nSrcSpace == m_pTag->GetPCS();} + ///Checks if the destination space of the transform is PCS + bool IsDestPCS() const {return m_nDestSpace == m_pTag->GetPCS();} + + + virtual LPIccCurve* ExtractInputCurves() {return NULL;} + virtual LPIccCurve* ExtractOutputCurves() {return NULL;} + +protected: + + virtual bool HasPerceptualHandling() { return false; } + + CIccTagNamedColor2 *m_pTag; + icApplyInterface m_nApplyInterface; + icColorSpaceSignature m_nSrcSpace; + icColorSpaceSignature m_nDestSpace; +}; + + +/** +************************************************************************** +* Type: Class +* +* Purpose: This is the general Xform for Multi Processing Elements. +* +************************************************************************** +*/ +class ICCPROFLIB_API CIccXformMpe : public CIccXform +{ +public: + CIccXformMpe(CIccTag *pTag); + virtual ~CIccXformMpe(); + + virtual icXformType GetXformType() const { return icXformTypeMpe; } + + ///Note: The returned CIccXform will own the profile. + static CIccXform *Create(CIccProfile *pProfile, bool bInput=true, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, CIccCreateXformHintManager *pHintManager=NULL); + + virtual icStatusCMM Begin(); + + virtual CIccApplyXform *GetNewApply(icStatusCMM &status); + virtual void Apply(CIccApplyXform *pApplyXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const; + + virtual bool UseLegacyPCS() const { return false; } + virtual LPIccCurve* ExtractInputCurves() {return NULL;} + virtual LPIccCurve* ExtractOutputCurves() {return NULL;} + + virtual bool NoClipPCS() const { return true; } + +protected: + CIccTagMultiProcessElement *m_pTag; + bool m_bUsingAcs; +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: The Apply general MPE Xform object (Allows xforms to have apply time data) +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyXformMpe : public CIccApplyXform +{ + friend class CIccXformMpe; +public: + virtual ~CIccApplyXformMpe(); + virtual icXformType GetXformType() const { return icXformTypeMpe; } + +protected: + CIccApplyXformMpe(CIccXformMpe *pXform); + + CIccApplyTagMpe *m_pApply; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: Independant PCS class to do PCS based calculations. + * This is a class for managing PCS colorspace transformations. There + * are two important categories V2 <-> V4, and Lab <-> XYZ. + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccPCS +{ +public: + CIccPCS(); + virtual ~CIccPCS() {} + + void Reset(icColorSpaceSignature StartSpace, bool bUseLegacyPCS = false); + + virtual const icFloatNumber *Check(const icFloatNumber *SrcPixel, const CIccXform *pXform); + void CheckLast(icFloatNumber *SrcPixel, icColorSpaceSignature Space, bool bNoClip=false); + + static void LabToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false); + static void XyzToLab(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false); + static void Lab2ToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false); + static void XyzToLab2(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip=false); + static icFloatNumber NegClip(icFloatNumber v); + static icFloatNumber UnitClip(icFloatNumber v); + + static void Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoclip=false); + static void Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src); +protected: + + bool m_bIsV2Lab; + icColorSpaceSignature m_Space; + + icFloatNumber m_Convert[3]; +}; + +/** + ************************************************************************** + Color data passed to/from the CMM is encoded as floating point numbers ranging from 0.0 to 1.0 + Often data is encoded using other ranges. The icFloatColorEncoding enum is used by the + ToInternalEncoding() and FromInternalEncoding() functions to convert to/from the internal + encoding. The valid encoding transforms for the following color space signatures are given + below. + + 'CMYK', 'RGB ', 'GRAY', 'CMY ', 'Luv ', 'YCbr', 'Yxy ', 'HSV ', 'HLS ', 'gamt' + icEncodePercent: 0.0 <= value <= 100.0 + icEncodeFloat: 0.0 <= value <= 1.0 + icEncode8Bit: 0.0 <= value <= 255 + icEncode16Bit: 0.0 <= value <= 65535 + icEncode16BitV2: 0.0 <= value <= 65535 + + 'XCLR' + icEncodeValue: (if X>=3) 0.0 <= L <= 100.0; -128.0 <= a,b <= 127.0 others 0.0 <= value <= 1.0 + icEncodePercent: 0.0 <= value <= 100.0 + icEncodeFloat: 0.0 <= value <= 1.0 + icEncode8Bit: 0.0 <= value <= 255 + icEncode16Bit: 0.0 <= value <= 65535 + icEncode16BitV2: 0.0 <= value <= 65535 + + 'Lab ' + icEncodeValue: 0.0 <= L <= 100.0; -128.0 <= a,b <= 127.0 + icEncodeFloat: 0.0 <= L,a,b <= 1.0 - ICC PCS encoding (See ICC Specification) + icEncode8BIt: ICC 8 bit Lab Encoding - See ICC Specification + icEncode16Bit: ICC 16 bit V4 Lab Encoding - See ICC Specification + icEncode16BitV2: ICC 16 bit V2 Lab Encoding - See ICC Specification + + 'XYZ ' + icEncodeValue: 0.0 <= X,Y,Z < 1.999969482421875 + icEncodePercent: 0.0 <= X,Y,Z < 199.9969482421875 + icEncodeFloat: 0.0 <= L,a,b <= 1.0 - ICC PCS encoding (See ICC Specification + icEncode16Bit: ICC 16 bit XYZ Encoding - (icU1Fixed15) See ICC Specification + icEncode16BitV2: ICC 16 bit XYZ Encoding - (icU1Fixed15) See ICC Specification + ************************************************************************** +*/ + +typedef enum +{ + icEncodeValue=0, + icEncodePercent, + icEncodeFloat, + icEncode8Bit, + icEncode16Bit, + icEncode16BitV2, + icEncodeUnknown, +} icFloatColorEncoding; + +//Forward Reference of CIccCmm for CIccCmmApply +class CIccCmm; + +/** +************************************************************************** +* Type: Class +* +* Purpose: Defines a class that provides and interface for applying pixel +* transformations through a CMM. Multiply CIccCmmApply objects can use +* a single CIccCmm Object. +* +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyCmm +{ + friend class CIccCmm; +public: + virtual ~CIccApplyCmm(); + + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel); + + //Make sure that when DstPixel==SrcPixel the sizeof DstPixel is less than size of SrcPixel + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels); + + void AppendApplyXform(CIccApplyXform *pApplyXform); + + CIccCmm *GetCmm() { return m_pCmm; } + +protected: + CIccApplyCmm(CIccCmm *pCmm); + + CIccApplyXformList *m_Xforms; + CIccCmm *m_pCmm; + + CIccPCS *m_pPCS; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: Defines a class that allows one or more profiles to be applied + * in order that they are Added. + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccCmm +{ + friend class CIccApplyCmm; +public: + CIccCmm(icColorSpaceSignature nSrcSpace=icSigUnknownData, + icColorSpaceSignature nDestSpace=icSigUnknownData, + bool bFirstInput=true); + virtual ~CIccCmm(); + + virtual CIccPCS *GetPCS() { return new CIccPCS(); } + + ///Must make at least one call to some form of AddXform() before calling Begin() + virtual icStatusCMM AddXform(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); + virtual icStatusCMM AddXform(icUInt8Number *pProfileMem, icUInt32Number nProfileLen, + icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear, + icXformLutType nLutType=icXformLutColor, bool bUseMpeTags=true, + CIccCreateXformHintManager *pHintManager=NULL); + virtual icStatusCMM AddXform(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); //Note: profile will be owned by the CMM + virtual icStatusCMM AddXform(CIccProfile &Profile, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); //Note the profile will be copied + + //The Begin function should be called before Apply or GetNewApplyCmm() + virtual icStatusCMM Begin(bool bAllocNewApply=true); + + //Get an additional Apply cmm object to apply pixels with. The Apply object should be deleted by the caller. + virtual CIccApplyCmm *GetNewApplyCmm(icStatusCMM &status); + + virtual CIccApplyCmm *GetApply() { return m_pApply; } + + //The following apply functions should only be called if using Begin(true); + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel); + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels); + + //Call to Detach and remove all pending IO objects attached to the profiles used by the CMM. Should be called only after Begin() + virtual icStatusCMM RemoveAllIO(); + + ///Returns the number of profiles/transforms added + virtual icUInt32Number GetNumXforms() const; + + ///Returns the source color space + icColorSpaceSignature GetSourceSpace() const { return m_nSrcSpace; } + ///Returns the destination color space + icColorSpaceSignature GetDestSpace() const { return m_nDestSpace; } + ///Returns the color space of the last profile added + icColorSpaceSignature GetLastSpace() const { return m_nLastSpace; } + ///Returns the rendering intent of the last profile added + icRenderingIntent GetLastIntent() const { return m_nLastIntent; } + + ///Returns the number of samples in the source color space + icUInt16Number GetSourceSamples() const {return (icUInt16Number)icGetSpaceSamples(m_nSrcSpace);} + ///Returns the number of samples in the destination color space + icUInt16Number GetDestSamples() const {return (icUInt16Number)icGetSpaceSamples(m_nDestSpace);} + + ///Checks if this is a valid CMM object + bool Valid() const { return m_bValid; } + + //Function to convert check if Internal representation of 'gamt' color is in gamut. + static bool IsInGamut(icFloatNumber *pData); + + ///Functions for converting to Internal representation of pixel colors + static icStatusCMM ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, + icFloatNumber *pInternal, const icFloatNumber *pData, bool bClip=true); + static icStatusCMM ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal, + const icUInt8Number *pData); + static icStatusCMM ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal, + const icUInt16Number *pData); + icStatusCMM ToInternalEncoding(icFloatNumber *pInternal, const icUInt8Number *pData) {return ToInternalEncoding(m_nSrcSpace, pInternal, pData);} + icStatusCMM ToInternalEncoding(icFloatNumber *pInternal, const icUInt16Number *pData) {return ToInternalEncoding(m_nSrcSpace, pInternal, pData);} + + + ///Functions for converting from Internal representation of pixel colors + static icStatusCMM FromInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, + icFloatNumber *pData, const icFloatNumber *pInternal, bool bClip=true); + static icStatusCMM FromInternalEncoding(icColorSpaceSignature nSpace, icUInt8Number *pData, + const icFloatNumber *pInternal); + static icStatusCMM FromInternalEncoding(icColorSpaceSignature nSpace, icUInt16Number *pData, + const icFloatNumber *pInternal); + icStatusCMM FromInternalEncoding(icUInt8Number *pData, icFloatNumber *pInternal) {return FromInternalEncoding(m_nDestSpace, pData, pInternal);} + icStatusCMM FromInternalEncoding(icUInt16Number *pData, icFloatNumber *pInternal) {return FromInternalEncoding(m_nDestSpace, pData, pInternal);} + + static const icChar *GetFloatColorEncoding(icFloatColorEncoding val); + static icFloatColorEncoding GetFloatColorEncoding(const icChar* val); + + virtual icColorSpaceSignature GetFirstXformSource(); + virtual icColorSpaceSignature GetLastXformDest(); + +protected: + + CIccApplyCmm *m_pApply; + + bool m_bValid; + + bool m_bLastInput; + icColorSpaceSignature m_nSrcSpace; + icColorSpaceSignature m_nDestSpace; + + icColorSpaceSignature m_nLastSpace; + icRenderingIntent m_nLastIntent; + + CIccXformList *m_Xforms; +}; + +//Forward Class for CIccApplyNamedColorCmm +class CIccNamedColorCmm; +/** +************************************************************************** +* Type: Class +* +* Purpose: Defines a class that provides and interface for applying pixel +* transformations through a Named Color CMM. Multiply CIccApplyNamedColorCmm +* objects can refer to a single CIccNamedColorCmm Object. +* +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyNamedColorCmm : public CIccApplyCmm +{ + friend class CIccNamedColorCmm; +public: + virtual ~CIccApplyNamedColorCmm(); + + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel); + + //Make sure that when DstPixel==SrcPixel the sizeof DstPixel is less than size of SrcPixel + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels); + + ///Define 4 apply interfaces that are used depending upon the source and destination xforms + virtual icStatusCMM Apply(icChar* DstColorName, const icFloatNumber *SrcPixel); + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icChar *SrcColorName); + virtual icStatusCMM Apply(icChar* DstColorName, const icChar *SrcColorName); + +protected: + CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm); +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: A Slower Named Color Profile compatible CMM + * + ************************************************************************** + */ +class ICCPROFLIB_API CIccNamedColorCmm : public CIccCmm +{ + friend class CIccApplyNamedColorCmm; +public: + ///nSrcSpace cannot be icSigUnknownData if first profile is named color + CIccNamedColorCmm(icColorSpaceSignature nSrcSpace=icSigUnknownData, + icColorSpaceSignature nDestSpace=icSigUnknownData, + bool bFirstInput=true); + virtual ~CIccNamedColorCmm(); + + ///Must make at least one call to some form of AddXform() before calling Begin() + virtual icStatusCMM AddXform(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); + virtual icStatusCMM AddXform(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool buseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL); //Note: profile will be owned by the CMM + + ///Must be called before calling Apply() or GetNewApply() + //The Begin function should be called before Apply or GetNewApplyCmm() + virtual icStatusCMM Begin(bool bAllocNewApply=true); + + virtual CIccApplyCmm *GetNewApply(icStatusCMM &status); + + + //The following apply functions should only be called if using Begin(true); + icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) { return CIccCmm::Apply(DstPixel, SrcPixel); } + icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) { return CIccCmm::Apply(DstPixel, SrcPixel, nPixels); } + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icChar *SrcColorName); + virtual icStatusCMM Apply(icChar* DstColorName, const icFloatNumber *SrcPixel); + virtual icStatusCMM Apply(icChar* DstColorName, const icChar *SrcColorName); + + ///Returns the type of interface that will be applied + icApplyInterface GetInterface() const {return m_nApplyInterface;} + + icStatusCMM SetLastXformDest(icColorSpaceSignature nDestSpace); + +protected: + icApplyInterface m_nApplyInterface; +}; + + +class ICCPROFLIB_API CIccMruPixel +{ +public: + CIccMruPixel() { pPixelData = NULL; pNext = NULL; } + + icFloatNumber *pPixelData; + CIccMruPixel *pNext; +}; + +//Forward Class for CIccApplyNamedColorCmm +class CIccMruCmm; +/** +************************************************************************** +* Type: Class +* +* Purpose: Defines a class that provides and interface for applying pixel +* transformations through a CMM. Multiply CIccCmmApply objects can use +* a single CIccCmm Object. +* +************************************************************************** +*/ +class ICCPROFLIB_API CIccApplyMruCmm : public CIccApplyCmm +{ + friend class CIccMruCmm; +public: + virtual ~CIccApplyMruCmm(); + + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel); + + //Make sure that when DstPixel==SrcPixel the sizeof DstPixel is greater than size of SrcPixel + virtual icStatusCMM Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels); + +protected: + CIccApplyMruCmm(CIccMruCmm *pCmm); + + bool Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize); + + CIccCmm *m_pCachedCmm; + + icUInt16Number m_nCacheSize; + + icFloatNumber *m_pixelData; + + CIccMruPixel *m_pFirst; + CIccMruPixel *m_cache; + + icUInt16Number m_nNumPixel; + + icUInt32Number m_nTotalSamples; + icUInt32Number m_nSrcSamples; + + icUInt32Number m_nSrcSize; + icUInt32Number m_nDstSize; + +}; + +/** +************************************************************************** +* Type: Class +* +* Purpose: A CMM decorator class that provides limited caching of results +* +************************************************************************** +*/ +class ICCPROFLIB_API CIccMruCmm : public CIccCmm +{ + friend class CIccApplyMruCmm; +private: + CIccMruCmm(); +public: + virtual ~CIccMruCmm(); + + //This is the function used to create a new CIccMruCmm. The pCmm must be valid and its Begin() already called. + static CIccMruCmm* Attach(CIccCmm *pCmm, icUInt8Number nCacheSize=6); //The returned object will own pCmm, and pCmm is deleted on failure. + + //override AddXform/Begin functions to return bad status. + virtual icStatusCMM AddXform(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; } + virtual icStatusCMM AddXform(icUInt8Number *pProfileMem, icUInt32Number nProfileLen, + icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear, + icXformLutType nLutType=icXformLutColor, bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; } + virtual icStatusCMM AddXform(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; } + virtual icStatusCMM AddXform(CIccProfile &Profile, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, icXformLutType nLutType=icXformLutColor, + bool bUseMpeTags=true, CIccCreateXformHintManager *pHintManager=NULL) { return icCmmStatBad; } + + virtual CIccApplyCmm *GetNewApplyCmm(icStatusCMM &status); + + //Forward calls to attached CMM + virtual icStatusCMM RemoveAllIO() { return m_pCmm->RemoveAllIO(); } + virtual CIccPCS *GetPCS() { return m_pCmm->GetPCS(); } + virtual icUInt32Number GetNumXforms() const { return m_pCmm->GetNumXforms(); } + + virtual icColorSpaceSignature GetFirstXformSource() { return m_pCmm->GetFirstXformSource(); } + virtual icColorSpaceSignature GetLastXformDest() { return m_pCmm->GetLastXformDest(); } + +protected: + CIccCmm *m_pCmm; + icUInt16Number m_nCacheSize; + +}; + +#ifdef USESAMPLEICCNAMESPACE +}; //namespace sampleICC +#endif + +#endif // !defined(_ICCCMM_H) diff --git a/library/src/main/cpp/icc/IccConvertUTF.cpp b/library/src/main/cpp/icc/IccConvertUTF.cpp new file mode 100644 index 00000000..f796dafa --- /dev/null +++ b/library/src/main/cpp/icc/IccConvertUTF.cpp @@ -0,0 +1,541 @@ +/* +* Copyright 2001-2004 Unicode, Inc. +* +* Disclaimer +* +* This source code is provided as is by Unicode, Inc. No claims are +* made as to fitness for any particular purpose. No warranties of any +* kind are expressed or implied. The recipient agrees to determine +* applicability of information provided. If this file has been +* purchased on magnetic or optical media from Unicode, Inc., the +* sole remedy for any claim will be exchange of defective media +* within 90 days of receipt. +* +* Limitations on Rights to Redistribute This Code +* +* Unicode, Inc. hereby grants the right to freely use the information +* supplied in this file in the creation of products supporting the +* Unicode Standard, and to make copies of this file in any form +* for internal or external distribution as long as this notice +* remains attached. +*/ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Source code file. +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Sept 2001: fixed const & error conditions per +mods suggested by S. Parent & A. Lillich. +June 2002: Tim Dodd added detection and handling of incomplete +source sequences, enhanced error detection, added casts +to eliminate compiler warnings. +July 2003: slight mods to back out aggressive FFFE detection. +Jan 2004: updated switches in from-UTF8 conversions. +Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + +See the header file "icConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "IccConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +icUtfConversionResult icConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags) +{ + icUtfConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +icUtfConversionResult icConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags) +{ + icUtfConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG + if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); + } +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* +* Index into the table below with the first byte of a UTF-8 sequence to +* get the number of trailing bytes that are supposed to follow it. +* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is +* left as-is for anyone who may want to do such conversion, which was +* allowed in earlier algorithms. +*/ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* +* Magic values subtracted from a buffer value during UTF8 conversion. +* This table contains as many values as there might be trailing bytes +* in a UTF-8 sequence. +*/ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, +0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* +* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed +* into the first byte, depending on how many bytes follow. There are +* as many entries in this table as there are UTF-8 sequence types. +* (I.e., one byte sequence, two byte... etc.). Remember that sequencs +* for *legal* UTF-8 will be 4 or fewer bytes total. +*/ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. +* Constants have been gathered. Loops & conditionals have been removed as +* much as possible for efficiency, in favor of drop-through switches. +* (See "Note A" at the bottom of the file for equivalent code.) +* If your compiler supports it, the "isLegalUTF8" call can be turned +* into an inline function. +*/ + +/* --------------------------------------------------------------------- */ + +icUtfConversionResult icConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags) +{ + icUtfConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* +* Utility routine to tell whether a sequence of bytes is legal UTF-8. +* This must be called with the length pre-determined by the first byte. +* If not calling this from ConvertUTF8to*, then the length can be set by: +* length = trailingBytesForUTF8[*source]+1; +* and the sequence is illegal right away if there aren't that many bytes +* available. +* If presented with a length > 4, this returns false. The Unicode +* definition of UTF-8 goes up to 4-byte sequences. +*/ + +static Boolean isLegalUTF8(const UTF8 *source, int length) +{ + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* +* Exported function to return whether a UTF-8 sequence is legal or not. +* This is not used here; it's just exported. +*/ +Boolean icIsLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) +{ + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +icUtfConversionResult icConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags) +{ + icUtfConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +icUtfConversionResult icConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags) +{ + icUtfConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +icUtfConversionResult icConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags) +{ + icUtfConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + +Note A. +The fall-through switches in UTF-8 reading code save a +temp variable, some decrements & conditionals. The switches +are equivalent to the following loop: +{ +int tmpBytesToRead = extraBytesToRead+1; +do { +ch += *source++; +--tmpBytesToRead; +if (tmpBytesToRead) ch <<= 6; +} while (tmpBytesToRead > 0); +} +In UTF-8 writing code, the switches on "bytesToWrite" are +similarly unrolled loops. + +--------------------------------------------------------------------- */ diff --git a/library/src/main/cpp/icc/IccConvertUTF.h b/library/src/main/cpp/icc/IccConvertUTF.h new file mode 100644 index 00000000..fcb224b2 --- /dev/null +++ b/library/src/main/cpp/icc/IccConvertUTF.h @@ -0,0 +1,158 @@ +/* +* Copyright 2001-2004 Unicode, Inc. +* +* Disclaimer +* +* This source code is provided as is by Unicode, Inc. No claims are +* made as to fitness for any particular purpose. No warranties of any +* kind are expressed or implied. The recipient agrees to determine +* applicability of information provided. If this file has been +* purchased on magnetic or optical media from Unicode, Inc., the +* sole remedy for any claim will be exchange of defective media +* within 90 days of receipt. +* +* Limitations on Rights to Redistribute This Code +* +* Unicode, Inc. hereby grants the right to freely use the information +* supplied in this file in the creation of products supporting the +* Unicode Standard, and to make copies of this file in any form +* for internal or external distribution as long as this notice +* remains attached. +*/ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Header file. + +Several funtions are included here, forming a complete set of +conversions between the three formats. UTF-7 is not included +here, but is handled in a separate source file. + +Each of these routines takes pointers to input buffers and output +buffers. The input buffers are const. + +Each routine converts the text between *sourceStart and sourceEnd, +putting the result into the buffer between *targetStart and +targetEnd. Note: the end pointers are *after* the last item: e.g. +*(sourceEnd - 1) is the last item. + +The return result indicates whether the conversion was successful, +and if not, whether the problem was in the source or target buffers. +(Only the first encountered problem is indicated.) + +After the conversion, *sourceStart and *targetStart are both +updated to point to the end of last text successfully converted in +the respective buffers. + +Input parameters: +sourceStart - pointer to a pointer to the source buffer. +The contents of this are modified on return so that +it points at the next thing to be converted. +targetStart - similarly, pointer to pointer to the target buffer. +sourceEnd, targetEnd - respectively pointers to the ends of the +two buffers, for overflow checking only. + +These conversion functions take an icUtfConversionFlags argument. When this +flag is set to strict, both irregular sequences and isolated surrogates +will cause an error. When the flag is set to lenient, both irregular +sequences and isolated surrogates are converted. + +Whether the flag is strict or lenient, all illegal sequences will cause +an error return. This includes sequences such as: , , +or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code +must check for illegal sequences. + +When the flag is set to lenient, characters over 0x10FFFF are converted +to the replacement character; otherwise (when the flag is set to strict) +they constitute an error. + +Output parameters: +The value "sourceIllegal" is returned from some routines if the input +sequence is malformed. When "sourceIllegal" is returned, the source +value will point to the illegal value that caused the problem. E.g., +in UTF-8 when a sequence is malformed, it points to the start of the +malformed sequence. + +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- +July 2009 +- Modified names to avoid possible conflicts - Max Derhak +- Added IccProfLibConf.h include to use ICCPROFLIB_API with functions +- Changed typedef of UTF32 to use ICCUINT32 +------------------------------------------------------------------------ */ + +#include "IccProfLibConf.h" + +/* --------------------------------------------------------------------- +The following 4 definitions are compiler-specific. +The C standard does not guarantee that wchar_t has at least +16 bits, so wchar_t is no less portable than unsigned short! +All should be unsigned values to avoid sign extension during +bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef ICCUINT32 UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} icUtfConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} icUtfConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +icUtfConversionResult ICCPROFLIB_API icConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags); + +icUtfConversionResult ICCPROFLIB_API icConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags); + +icUtfConversionResult ICCPROFLIB_API icConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags); + +icUtfConversionResult ICCPROFLIB_API icConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, icUtfConversionFlags flags); + +icUtfConversionResult ICCPROFLIB_API icConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, icUtfConversionFlags flags); + +icUtfConversionResult ICCPROFLIB_API icConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, icUtfConversionFlags flags); + +Boolean ICCPROFLIB_API icIsLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ diff --git a/library/src/main/cpp/icc/IccDefs.h b/library/src/main/cpp/icc/IccDefs.h new file mode 100644 index 00000000..8212906f --- /dev/null +++ b/library/src/main/cpp/icc/IccDefs.h @@ -0,0 +1,136 @@ +/** @file + File: IccDefs.h + + Contains: Access ICC profile definitions and structures including + Version 4 extensions + + Copyright: see ICC Software License + */ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +#include + +/* Header file guard bands */ +#ifndef _ICCDEFS_H +#define _ICCDEFS_H + +#pragma pack(4) + +//Get any platform specific prototypes +#include "IccProfLibConf.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +//Include the standard icProfileHeader definition file +#include "icProfileHeader.h" + +// Define signature for SampleICC's use +#define icSigSampleICC ((icSignature)0x53494343) /* 'SICC' */ + +//Definitions used for conversion of fixed floating point numbers +typedef icUInt16Number icU1Fixed15Number; +typedef icUInt16Number icU8Fixed8Number; + + +/** +* Additional convenience color space signatures to distinguish between device +* encoding and PCS encoding. +* +* Device encoding of these color spaces is left to the device to define. +*/ +#define icSigDevLabData ((icColorSpaceSignature) 0x644C6162) /* 'dLab' */ +#define icSigDevXYZData ((icColorSpaceSignature) 0x6458595A) /* 'dXYZ' */ + + +/** +* All floating point operations/variables in IccProfLib use the icFloatNumber data type. +* It was found that using float instead of double increased performance. Changing +* the definition to double will add greater precision at the cost of performance. +*/ +typedef float icFloatNumber; + +/** String formating macros need to match precision of icFloatNumber +*If precision is double change the "f" below to "lf" +*/ +#define ICFLOATSFX "f" +#define ICFLOATFMT "%f" + +/* For string operations */ +typedef char icChar; +#if defined(WIN32) || defined(WIN64) +typedef wchar_t icWChar; +#endif + +/* Validation Status values */ +typedef enum { + icValidateOK, /*Profile is valid and conforms to specification*/ + icValidateWarning, /*Profile conforms to specification with concerns*/ + icValidateNonCompliant, /*Profile does not conform to specification, but may still be useable*/ + icValidateCriticalError, /*Profile does not conform to specification and is not useable*/ +} icValidateStatus; + + +#pragma pack() + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif /* _ICCDEFS_H */ + + + diff --git a/library/src/main/cpp/icc/IccDemo.cpp b/library/src/main/cpp/icc/IccDemo.cpp new file mode 100644 index 00000000..0c2d76fb --- /dev/null +++ b/library/src/main/cpp/icc/IccDemo.cpp @@ -0,0 +1,229 @@ +// +// Created by 钟元杰 on 2022/9/19. +// + +#include "IccCmm.h" +#include "IccProfile.h" +#include +#include + +#define TAG "IccCmm_ceshi" +#define pri_debug(format, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s:%d]" format, "IccDemo.cpp", __LINE__, ##args) + +CIccCmm *cmm = nullptr; +icFloatNumber Pixels[16]; + +//from skia pdfDocument +const icUInt8Number kProfile[] = + "\0\0\14\214argl\2 \0\0mntrRGB XYZ \7\336\0\1\0\6\0\26\0\17\0:acspM" + "SFT\0\0\0\0IEC sRGB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\366\326\0\1\0\0\0\0" + "\323-argl\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\21desc\0\0\1P\0\0\0\231cprt\0" + "\0\1\354\0\0\0gdmnd\0\0\2T\0\0\0pdmdd\0\0\2\304\0\0\0\210tech\0\0\3" + "L\0\0\0\14vued\0\0\3X\0\0\0gview\0\0\3\300\0\0\0$lumi\0\0\3\344\0\0" + "\0\24meas\0\0\3\370\0\0\0$wtpt\0\0\4\34\0\0\0\24bkpt\0\0\0040\0\0\0" + "\24rXYZ\0\0\4D\0\0\0\24gXYZ\0\0\4X\0\0\0\24bXYZ\0\0\4l\0\0\0\24rTR" + "C\0\0\4\200\0\0\10\14gTRC\0\0\4\200\0\0\10\14bTRC\0\0\4\200\0\0\10" + "\14desc\0\0\0\0\0\0\0?sRGB IEC61966-2.1 (Equivalent to www.srgb.co" + "m 1998 HP profile)\0\0\0\0\0\0\0\0\0\0\0?sRGB IEC61966-2.1 (Equiva" + "lent to www.srgb.com 1998 HP profile)\0\0\0\0\0\0\0\0text\0\0\0\0C" + "reated by Graeme W. Gill. Released into the public domain. No Warr" + "anty, Use at your own risk.\0\0desc\0\0\0\0\0\0\0\26IEC http://www" + ".iec.ch\0\0\0\0\0\0\0\0\0\0\0\26IEC http://www.iec.ch\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0desc\0\0\0\0\0\0\0.IEC 61966-2.1 Default RGB colour sp" + "ace - sRGB\0\0\0\0\0\0\0\0\0\0\0.IEC 61966-2.1 Default RGB colour " + "space - sRGB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0sig \0\0\0" + "\0CRT desc\0\0\0\0\0\0\0\rIEC61966-2.1\0\0\0\0\0\0\0\0\0\0\0\rIEC6" + "1966-2.1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0view\0\0\0\0" + "\0\23\244|\0\24_0\0\20\316\2\0\3\355\262\0\4\23\n\0\3\\g\0\0\0\1XY" + "Z \0\0\0\0\0L\n=\0P\0\0\0W\36\270meas\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\2\217\0\0\0\2XYZ \0\0\0\0\0\0\363Q\0\1\0\0\0" + "\1\26\314XYZ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0XYZ \0\0\0\0\0\0o\240" + "\0\0008\365\0\0\3\220XYZ \0\0\0\0\0\0b\227\0\0\267\207\0\0\30\331X" + "YZ \0\0\0\0\0\0$\237\0\0\17\204\0\0\266\304curv\0\0\0\0\0\0\4\0\0\0" + "\0\5\0\n\0\17\0\24\0\31\0\36\0#\0(\0-\0002\0007\0;\0@\0E\0J\0O\0T\0" + "Y\0^\0c\0h\0m\0r\0w\0|\0\201\0\206\0\213\0\220\0\225\0\232\0\237\0" + "\244\0\251\0\256\0\262\0\267\0\274\0\301\0\306\0\313\0\320\0\325\0" + "\333\0\340\0\345\0\353\0\360\0\366\0\373\1\1\1\7\1\r\1\23\1\31\1\37" + "\1%\1+\0012\0018\1>\1E\1L\1R\1Y\1`\1g\1n\1u\1|\1\203\1\213\1\222\1" + "\232\1\241\1\251\1\261\1\271\1\301\1\311\1\321\1\331\1\341\1\351\1" + "\362\1\372\2\3\2\14\2\24\2\35\2&\2/\0028\2A\2K\2T\2]\2g\2q\2z\2\204" + "\2\216\2\230\2\242\2\254\2\266\2\301\2\313\2\325\2\340\2\353\2\365" + "\3\0\3\13\3\26\3!\3-\0038\3C\3O\3Z\3f\3r\3~\3\212\3\226\3\242\3\256" + "\3\272\3\307\3\323\3\340\3\354\3\371\4\6\4\23\4 \4-\4;\4H\4U\4c\4q" + "\4~\4\214\4\232\4\250\4\266\4\304\4\323\4\341\4\360\4\376\5\r\5\34" + "\5+\5:\5I\5X\5g\5w\5\206\5\226\5\246\5\265\5\305\5\325\5\345\5\366" + "\6\6\6\26\6'\0067\6H\6Y\6j\6{\6\214\6\235\6\257\6\300\6\321\6\343\6" + "\365\7\7\7\31\7+\7=\7O\7a\7t\7\206\7\231\7\254\7\277\7\322\7\345\7" + "\370\10\13\10\37\0102\10F\10Z\10n\10\202\10\226\10\252\10\276\10\322" + "\10\347\10\373\t\20\t%\t:\tO\td\ty\t\217\t\244\t\272\t\317\t\345\t" + "\373\n\21\n'\n=\nT\nj\n\201\n\230\n\256\n\305\n\334\n\363\13\13\13" + "\"\0139\13Q\13i\13\200\13\230\13\260\13\310\13\341\13\371\14\22\14" + "*\14C\14\\\14u\14\216\14\247\14\300\14\331\14\363\r\r\r&\r@\rZ\rt\r" + "\216\r\251\r\303\r\336\r\370\16\23\16.\16I\16d\16\177\16\233\16\266" + "\16\322\16\356\17\t\17%\17A\17^\17z\17\226\17\263\17\317\17\354\20" + "\t\20&\20C\20a\20~\20\233\20\271\20\327\20\365\21\23\0211\21O\21m\21" + "\214\21\252\21\311\21\350\22\7\22&\22E\22d\22\204\22\243\22\303\22" + "\343\23\3\23#\23C\23c\23\203\23\244\23\305\23\345\24\6\24'\24I\24j" + "\24\213\24\255\24\316\24\360\25\22\0254\25V\25x\25\233\25\275\25\340" + "\26\3\26&\26I\26l\26\217\26\262\26\326\26\372\27\35\27A\27e\27\211" + "\27\256\27\322\27\367\30\33\30@\30e\30\212\30\257\30\325\30\372\31" + " \31E\31k\31\221\31\267\31\335\32\4\32*\32Q\32w\32\236\32\305\32\354" + "\33\24\33;\33c\33\212\33\262\33\332\34\2\34*\34R\34{\34\243\34\314" + "\34\365\35\36\35G\35p\35\231\35\303\35\354\36\26\36@\36j\36\224\36" + "\276\36\351\37\23\37>\37i\37\224\37\277\37\352 \25 A l \230 \304 \360" + "!\34!H!u!\241!\316!\373\"'\"U\"\202\"\257\"\335#\n#8#f#\224#\302#\360" + "$\37$M$|$\253$\332%\t%8%h%\227%\307%\367&'&W&\207&\267&\350'\30'I'" + "z'\253'\334(\r(?(q(\242(\324)\6)8)k)\235)\320*\2*5*h*\233*\317+\2+" + "6+i+\235+\321,\5,9,n,\242,\327-\14-A-v-\253-\341.\26.L.\202.\267.\356" + "/$/Z/\221/\307/\376050l0\2440\3331\0221J1\2021\2721\3622*2c2\2332\324" + "3\r3F3\1773\2703\3614+4e4\2364\3305\0235M5\2075\3025\375676r6\2566" + "\3517$7`7\2347\3278\0248P8\2148\3109\0059B9\1779\2749\371:6:t:\262" + ":\357;-;k;\252;\350<' >`>\240>\340?!?a" + "?\242?\342@#@d@\246@\347A)AjA\254A\356B0BrB\265B\367C:C}C\300D\3DG" + "D\212D\316E\22EUE\232E\336F\"FgF\253F\360G5G{G\300H\5HKH\221H\327I" + "\35IcI\251I\360J7J}J\304K\14KSK\232K\342L*LrL\272M\2MJM\223M\334N%" + "NnN\267O\0OIO\223O\335P'PqP\273Q\6QPQ\233Q\346R1R|R\307S\23S_S\252" + "S\366TBT\217T\333U(UuU\302V\17V\\V\251V\367WDW\222W\340X/X}X\313Y\32" + "YiY\270Z\7ZVZ\246Z\365[E[\225[\345\\5\\\206\\\326]']x]\311^\32^l^\275" + "_\17_a_\263`\5`W`\252`\374aOa\242a\365bIb\234b\360cCc\227c\353d@d\224" + "d\351e=e\222e\347f=f\222f\350g=g\223g\351h?h\226h\354iCi\232i\361j" + "Hj\237j\367kOk\247k\377lWl\257m\10m`m\271n\22nkn\304o\36oxo\321p+p" + "\206p\340q:q\225q\360rKr\246s\1s]s\270t\24tpt\314u(u\205u\341v>v\233" + "v\370wVw\263x\21xnx\314y*y\211y\347zFz\245{\4{c{\302|!|\201|\341}A" + "}\241~\1~b~\302\177#\177\204\177\345\200G\200\250\201\n\201k\201\315" + "\2020\202\222\202\364\203W\203\272\204\35\204\200\204\343\205G\205" + "\253\206\16\206r\206\327\207;\207\237\210\4\210i\210\316\2113\211\231" + "\211\376\212d\212\312\2130\213\226\213\374\214c\214\312\2151\215\230" + "\215\377\216f\216\316\2176\217\236\220\6\220n\220\326\221?\221\250" + "\222\21\222z\222\343\223M\223\266\224 \224\212\224\364\225_\225\311" + "\2264\226\237\227\n\227u\227\340\230L\230\270\231$\231\220\231\374" + "\232h\232\325\233B\233\257\234\34\234\211\234\367\235d\235\322\236" + "@\236\256\237\35\237\213\237\372\240i\240\330\241G\241\266\242&\242" + "\226\243\6\243v\243\346\244V\244\307\2458\245\251\246\32\246\213\246" + "\375\247n\247\340\250R\250\304\2517\251\251\252\34\252\217\253\2\253" + "u\253\351\254\\\254\320\255D\255\270\256-\256\241\257\26\257\213\260" + "\0\260u\260\352\261`\261\326\262K\262\302\2638\263\256\264%\264\234" + "\265\23\265\212\266\1\266y\266\360\267h\267\340\270Y\270\321\271J\271" + "\302\272;\272\265\273.\273\247\274!\274\233\275\25\275\217\276\n\276" + "\204\276\377\277z\277\365\300p\300\354\301g\301\343\302_\302\333\303" + "X\303\324\304Q\304\316\305K\305\310\306F\306\303\307A\307\277\310=" + "\310\274\311:\311\271\3128\312\267\3136\313\266\3145\314\265\3155\315" + "\265\3166\316\266\3177\317\270\3209\320\272\321<\321\276\322?\322\301" + "\323D\323\306\324I\324\313\325N\325\321\326U\326\330\327\\\327\340" + "\330d\330\350\331l\331\361\332v\332\373\333\200\334\5\334\212\335\20" + "\335\226\336\34\336\242\337)\337\257\3406\340\275\341D\341\314\342" + "S\342\333\343c\343\353\344s\344\374\345\204\346\r\346\226\347\37\347" + "\251\3502\350\274\351F\351\320\352[\352\345\353p\353\373\354\206\355" + "\21\355\234\356(\356\264\357@\357\314\360X\360\345\361r\361\377\362" + "\214\363\31\363\247\3644\364\302\365P\365\336\366m\366\373\367\212" + "\370\31\370\250\3718\371\307\372W\372\347\373w\374\7\374\230\375)\375" + "\272\376K\376\334\377m\377\377"; +const size_t kProfileLength = 3212; + +extern "C"{ + +JNIEXPORT jint JNICALL Java_com_xsooy_icc_IccUtils_loadProfile(JNIEnv *env, jobject thiz, jstring path) { + delete cmm; + cmm = new CIccCmm; + if (cmm->GetNumXforms()!=0) { + pri_debug("profile已加载"); + return 1; + } + const char *nativeString = env->GetStringUTFChars(path, 0); + if (cmm->AddXform(nativeString, (icRenderingIntent)0)) { + pri_debug("合入失败%s",nativeString); +// printf("Invalid Profile: %s\n", szSrcProfile); + return -1; + } + pri_debug("合入成功%s",nativeString); + if (cmm->Begin() != icCmmStatOk) { + pri_debug("合入失败222%s",nativeString); +// printf("Invalid Profile:\n %s\n %s'\n", szSrcProfile, szDstProfile); + return false; + } + return 0; +} + +icUInt8Number* ConvertJByteaArrayToChars(JNIEnv *env, jbyteArray bytearray) +{ + icUInt8Number *chars = NULL; + jbyte *bytes; + bytes = env->GetByteArrayElements(bytearray, 0); + int chars_len = env->GetArrayLength(bytearray); + chars = new icUInt8Number[chars_len + 1]; + memset(chars,0,chars_len + 1); + memcpy(chars, bytes, chars_len); + chars[chars_len] = 0; + + env->ReleaseByteArrayElements(bytearray, bytes, 0); + return chars; +} + +JNIEXPORT jint JNICALL Java_com_xsooy_icc_IccUtils_loadProfileByData(JNIEnv *env, jobject thiz, jbyteArray data) { + delete cmm; + cmm = new CIccCmm; + icUInt8Number *pmsg = ConvertJByteaArrayToChars(env,data); + int chars_len = env->GetArrayLength(data); + CIccProfile* cIccProfile = OpenIccProfile(pmsg, chars_len); + if (cIccProfile==nullptr) { + pri_debug("创建IccData失败"); + return -1; + } + if (cmm->AddXform(cIccProfile, (icRenderingIntent)0)) { + pri_debug("读取IccData失败"); + return -1; + } + + pri_debug("读取输入IccData成功"); + + CIccProfile* sRgbProfile = OpenIccProfile(kProfile, kProfileLength); + if (cmm->AddXform(sRgbProfile, (icRenderingIntent)0)) { + pri_debug("读取sRgb-IccData失败"); + return -1; + } + + pri_debug("读取输入sRgb-IccData成功"); + + pri_debug("SourceSpace:%d",cmm->GetSourceSpace()); + if (cmm->Begin() != icCmmStatOk) { + pri_debug("启动Icc失败"); + return false; + } + pri_debug("DestSpace:%d",cmm->GetDestSpace()); + return cmm->GetSourceSpace(); +} + +JNIEXPORT jfloat JNICALL Java_com_xsooy_icc_IccUtils_apply(JNIEnv *env, jobject thiz, jfloat pixel) { + Pixels[0] = (float) pixel; + cmm->Apply(Pixels, Pixels); + return Pixels[0]; +} + +JNIEXPORT void JNICALL Java_com_xsooy_icc_IccUtils_applyGray(JNIEnv *env, jobject thiz, jfloatArray array,jfloatArray outArray) { + jboolean isCopy = JNI_FALSE; + jfloat *parray = env->GetFloatArrayElements(array, &isCopy); + Pixels[0] = float (parray[0]); + + cmm->Apply(Pixels, Pixels); + + env->SetFloatArrayRegion(outArray,0,3,Pixels); +} + +JNIEXPORT void JNICALL Java_com_xsooy_icc_IccUtils_applyCmyk(JNIEnv *env, jobject thiz, jfloatArray array,jfloatArray outArray) { + jboolean isCopy = JNI_FALSE; + jfloat *parray = env->GetFloatArrayElements(array, &isCopy); + Pixels[0] = float (parray[0]); + Pixels[1] = float (parray[1]); + Pixels[2] = float (parray[2]); + Pixels[3] = float (parray[3]); + + //change data to 'rgb' + cmm->Apply(Pixels, Pixels); + + env->SetFloatArrayRegion(outArray,0,3,Pixels); +} + +} \ No newline at end of file diff --git a/library/src/main/cpp/icc/IccEval.cpp b/library/src/main/cpp/icc/IccEval.cpp new file mode 100644 index 00000000..cf8b7afc --- /dev/null +++ b/library/src/main/cpp/icc/IccEval.cpp @@ -0,0 +1,208 @@ +/** @file +File: IccEval.cpp + +Contains: Implementation of the CIccProfile Evaluation utilites. + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2003-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#include +#include "IccEval.h" +#include "IccTag.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +static const icFloatNumber SMALLNUM = (icFloatNumber)0.0001; +static const icFloatNumber LESSTHANONE = (icFloatNumber)(1.0 - SMALLNUM); + +icStatusCMM CIccEvalCompare::EvaluateProfile(CIccProfile *pProfile, icUInt8Number nGran/* =0 */, + icRenderingIntent nIntent/* =icUnknownIntent */, icXformInterp nInterp/* =icInterpLinear */, + bool buseMpeTags/* =true */) +{ + if (!pProfile) + { + return icCmmStatCantOpenProfile; + } + + if (pProfile->m_Header.deviceClass!=icSigInputClass && + pProfile->m_Header.deviceClass!=icSigDisplayClass && + pProfile->m_Header.deviceClass!=icSigOutputClass && + pProfile->m_Header.deviceClass!=icSigColorSpaceClass) + { + return icCmmStatInvalidProfile; + } + + CIccCmm dev2Lab(icSigUnknownData, icSigLabData); + CIccCmm Lab2Dev2Lab(icSigLabData, icSigLabData, false); + + icStatusCMM result; + + result = dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); + + if (result!=icCmmStatOk) { + return result; + } + + result = dev2Lab.Begin(); + if (result != icCmmStatOk) { + return result; + } + + result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); + if (result != icCmmStatOk) { + return result; + } + + result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); + if (result != icCmmStatOk) { + return result; + } + + result = Lab2Dev2Lab.Begin(); + if (result != icCmmStatOk) { + return result; + } + + icFloatNumber sPixel[15]; + icFloatNumber devPcs[15], roundPcs1[15], roundPcs2[15]; + + int ndim = icGetSpaceSamples(pProfile->m_Header.colorSpace); + int ndim1 = ndim+1; + + // determine granularity + if (!nGran) + { + CIccTagLutAtoB* pTag = (CIccTagLutAtoB*)pProfile->FindTag(icSigAToB0Tag+(nIntent==icAbsoluteColorimetric ? icRelativeColorimetric : nIntent)); + if (!pTag || ndim==3) + { + nGran = 33; + } + else { + CIccCLUT* pClut = pTag->GetCLUT(); + if (pClut) + nGran = pClut->GridPoints()+2; + else + nGran = 33; + } + } + + int i, j; + icFloatNumber stepsize = (icFloatNumber)(1.0/(icFloatNumber)(nGran-1)); + icFloatNumber* steps = new icFloatNumber[ndim1]; + icFloatNumber nstart = 0.0; + icFloatNumber nEnd = (icFloatNumber)(1.0+stepsize/2.0); + for(j=0; j=0; i--) { + if(steps[i]>nEnd) { + steps[i] = nstart; + steps[i-1] = (steps[i-1]+stepsize); + } + else break; + } + + dev2Lab.Apply(devPcs, sPixel); //Convert device value to pcs from input table + Lab2Dev2Lab.Apply(roundPcs1, devPcs); //First round trip gets color into output gamut + Lab2Dev2Lab.Apply(roundPcs2, roundPcs1); //Second round trip find reproducibility error + + icLabFromPcs(devPcs); + icLabFromPcs(roundPcs1); + icLabFromPcs(roundPcs2); + + Compare(sPixel, devPcs, roundPcs1, roundPcs2); + } + + delete [] steps; + + return icCmmStatOk; +} + +icStatusCMM CIccEvalCompare::EvaluateProfile(const icChar *szProfilePath, icUInt8Number nGrid/* =0 */, icRenderingIntent nIntent/* =icUnknownIntent */, + icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */) +{ + CIccProfile *pProfile = ReadIccProfile(szProfilePath); + + if (!pProfile) + return icCmmStatCantOpenProfile; + + icStatusCMM result = EvaluateProfile(pProfile, nGrid, nIntent, nInterp, buseMpeTags); + + delete pProfile; + + return result; +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccEval.h b/library/src/main/cpp/icc/IccEval.h new file mode 100644 index 00000000..722508ce --- /dev/null +++ b/library/src/main/cpp/icc/IccEval.h @@ -0,0 +1,99 @@ +/** @file +File: IccEval.h + +Contains: Header file for implementation of the CIccProfile Evaluation utilites. + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2003-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 9-25-2007 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCEVAL_H) +#define _ICCEVAL_H + +#include "IccCmm.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + + +class CIccEvalCompare { +public: + //Create prototype for Compare function that must be implemented by a derived class + virtual void Compare(icFloatNumber *pPixel, icFloatNumber *deviceLab, icFloatNumber *destLab1, icFloatNumber *destLab2)=0; + + icStatusCMM ICCPROFLIB_API EvaluateProfile(CIccProfile *pProfile, icUInt8Number nGran=0, + icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear, + bool buseMpeTags=true); + + icStatusCMM ICCPROFLIB_API EvaluateProfile(const icChar *szProfilePath, icUInt8Number nGran=0, + icRenderingIntent nIntent=icUnknownIntent, icXformInterp nInterp=icInterpLinear, + bool buseMpeTags=true); +}; + +#ifdef USESAMPLEICCNAMESPACE +}; //namespace sampleICC +#endif + +#endif // !defined(_ICCCMM_H) diff --git a/library/src/main/cpp/icc/IccIO.cpp b/library/src/main/cpp/icc/IccIO.cpp new file mode 100644 index 00000000..1efa9111 --- /dev/null +++ b/library/src/main/cpp/icc/IccIO.cpp @@ -0,0 +1,712 @@ +/** @file + File: IccIO.cpp + + Contains: Implementation of the CIccIO class. + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#include "IccIO.h" +#include "IccUtil.h" +#include +#include +#include + +#ifndef __max +#define __max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef __min +#define __min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +////////////////////////////////////////////////////////////////////// +// Class CIccIO +////////////////////////////////////////////////////////////////////// + + +icInt32Number CIccIO::ReadLine(void *pBuf8, icInt32Number nNum/*=256*/) +{ + icInt32Number n=0; + icInt8Number c, *ptr=(icInt8Number*)pBuf8; + + while(n>1; + icSwab16Array(pBuf16, nNum); + + return nNum; +} + +icInt32Number CIccIO::Write16(void *pBuf16, icInt32Number nNum) +{ +#ifndef ICC_BYTE_ORDER_LITTLE_ENDIAN + return Write8(pBuf16, nNum<<1)>>1; +#else + icUInt16Number *ptr = (icUInt16Number*)pBuf16; + icUInt16Number tmp; + icInt32Number i; + + for (i=0; i>2; + icSwab32Array(pBuf32, nNum); + + return nNum; +} + + +icInt32Number CIccIO::Write32(void *pBuf32, icInt32Number nNum) +{ +#ifndef ICC_BYTE_ORDER_LITTLE_ENDIAN + return Write8(pBuf32, nNum<<2)>>2; +#else + icUInt32Number *ptr = (icUInt32Number*)pBuf32; + icUInt32Number tmp; + icInt32Number i; + + for (i=0; i>3; + icSwab64Array(pBuf64, nNum); + + return nNum; +} + + +icInt32Number CIccIO::Write64(void *pBuf64, icInt32Number nNum) +{ +#ifndef ICC_BYTE_ORDER_LITTLE_ENDIAN + return Write8(pBuf64, nNum<<3)>>3; +#else + icUInt64Number *ptr = (icUInt64Number*)pBuf64; + icUInt64Number tmp; + icInt32Number i; + + for (i=0; i>2)<<2; + if (Seek(nPos + nOffset, icSeekSet)<0) + return false; + return true; +} + + +////////////////////////////////////////////////////////////////////// +// Class CIccFileIO +////////////////////////////////////////////////////////////////////// + +CIccFileIO::CIccFileIO() : CIccIO() +{ + m_fFile = NULL; +} + +CIccFileIO::~CIccFileIO() +{ + Close(); +} + +bool CIccFileIO::Open(const icChar *szFilename, const icChar *szAttr) +{ +#if defined(WIN32) || defined(WIN64) + char myAttr[20]; + + if (!strchr(szAttr, 'b')) { + myAttr[0] = szAttr[0]; + myAttr[1] = 'b'; + strcpy(myAttr+2, szAttr+1); + szAttr = myAttr; + } +#endif + + if (m_fFile) + fclose(m_fFile); + + m_fFile = fopen(szFilename, szAttr); + + return m_fFile != NULL; +} + + +#if defined(WIN32) || defined(WIN64) +bool CIccFileIO::Open(const icWChar *szFilename, const icWChar *szAttr) +{ + icWChar myAttr[20]; + + if (!wcschr(szAttr, 'b')) { + myAttr[0] = szAttr[0]; + myAttr[1] = 'b'; + wcscpy(myAttr+2, szAttr+1); + szAttr = myAttr; + } + + if (m_fFile) + fclose(m_fFile); + + m_fFile = _wfopen(szFilename, szAttr); + + return m_fFile != NULL; +} +#endif + + +void CIccFileIO::Close() +{ + if (m_fFile) { + fclose(m_fFile); + m_fFile = NULL; + } +} + + +icInt32Number CIccFileIO::Read8(void *pBuf, icInt32Number nNum) +{ + if (!m_fFile) + return 0; + + return (icInt32Number)fread(pBuf, 1, nNum, m_fFile); +} + + +icInt32Number CIccFileIO::Write8(void *pBuf, icInt32Number nNum) +{ + if (!m_fFile) + return 0; + + return (icInt32Number)fwrite(pBuf, 1, nNum, m_fFile); +} + + +icInt32Number CIccFileIO::GetLength() +{ + if (!m_fFile) + return 0; + + fflush(m_fFile); + icInt32Number current = ftell(m_fFile), end; + fseek (m_fFile, 0, SEEK_END); + end = ftell(m_fFile); + fseek (m_fFile, current, SEEK_SET); + return end; +} + + +icInt32Number CIccFileIO::Seek(icInt32Number nOffset, icSeekVal pos) +{ + if (!m_fFile) + return -1; + + return !fseek(m_fFile, nOffset, pos) ? ftell(m_fFile) : -1; +} + + +icInt32Number CIccFileIO::Tell() +{ + if (!m_fFile) + return -1; + + return ftell(m_fFile); +} + + +////////////////////////////////////////////////////////////////////// +// Class CIccMemIO +////////////////////////////////////////////////////////////////////// + +CIccMemIO::CIccMemIO() : CIccIO() +{ + m_pData = NULL; + m_nSize = 0; + m_nAvail = 0; + m_nPos = 0; + + m_bFreeData = false; +} + +CIccMemIO::~CIccMemIO() +{ + Close(); +} + + +bool CIccMemIO::Alloc(icUInt32Number nSize, bool bWrite) +{ + if (m_pData) + Close(); + + icUInt8Number *pData = (icUInt8Number*)malloc(nSize); + + if (!pData) + return false; + + if (!Attach(pData, nSize, bWrite)) { + free(pData); + return false; + } + + m_bFreeData = true; + + return true; +} + + +bool CIccMemIO::Attach(icUInt8Number *pData, icUInt32Number nSize, bool bWrite) +{ + if (!pData) + return false; + + if (m_pData) + Close(); + + m_pData = pData; + m_nPos = 0; + + if (bWrite) { + m_nAvail = nSize; + m_nSize = 0; + } + else { + m_nAvail = m_nSize = nSize; + } + + return true; +} + + +void CIccMemIO::Close() +{ + if (m_pData) { + if (m_bFreeData) { + free(m_pData); + + m_bFreeData = false; + } + m_pData = NULL; + } +} + + +icInt32Number CIccMemIO::Read8(void *pBuf, icInt32Number nNum) +{ + if (!m_pData) + return 0; + + nNum = __min((icInt32Number)(m_nSize-m_nPos), nNum); + + memcpy(pBuf, m_pData+m_nPos, nNum); + m_nPos += nNum; + + return nNum; +} + + +icInt32Number CIccMemIO::Write8(void *pBuf, icInt32Number nNum) +{ + if (!m_pData) + return 0; + + nNum = __min((icInt32Number)(m_nAvail-m_nPos), nNum); + + memcpy(m_pData + m_nPos, pBuf, nNum); + + m_nPos += nNum; + if (m_nPos > m_nSize) + m_nSize = m_nPos; + + return nNum; +} + + +icInt32Number CIccMemIO::GetLength() +{ + if (!m_pData) + return 0; + + return m_nSize; +} + + +icInt32Number CIccMemIO::Seek(icInt32Number nOffset, icSeekVal pos) +{ + if (!m_pData) + return -1; + + icInt32Number nPos; + switch(pos) { + case icSeekSet: + nPos = nOffset; + break; + case icSeekCur: + nPos = (icInt32Number)m_nPos + nOffset; + break; + case icSeekEnd: + nPos = (icInt32Number)m_nSize + nOffset; + break; + default: + nPos = 0; + break; + } + + if (nPos < 0) + return -1; + + icUInt32Number uPos = (icUInt32Number)nPos; + + if (uPos > m_nSize && m_nSize != m_nAvail && uPos <=m_nAvail) { + memset(m_pData+m_nSize, 0, (icInt32Number)(uPos - m_nSize)); + m_nSize = uPos; + } + if (uPos > m_nSize) + return -1; + + m_nPos = uPos; + + return nPos; +} + + +icInt32Number CIccMemIO::Tell() +{ + if (!m_pData) + return -1; + + return (icInt32Number)m_nPos; +} + +/////////////////////////////// + +////////////////////////////////////////////////////////////////////// +// Class CIccNullIO +////////////////////////////////////////////////////////////////////// + +CIccNullIO::CIccNullIO() : CIccIO() +{ + m_nSize = 0; + m_nPos = 0; +} + +CIccNullIO::~CIccNullIO() +{ + Close(); +} + + +void CIccNullIO::Open() +{ + m_nPos = 0; + m_nSize = 0; +} + + +void CIccNullIO::Close() +{ +} + + +icInt32Number CIccNullIO::Read8(void *pBuf, icInt32Number nNum) +{ + icInt32Number nLeft = m_nSize - m_nPos; + icInt32Number nRead = (nNum <= (icInt32Number)nLeft) ? nNum : nLeft; + + memset(pBuf, 0, nRead); + m_nPos += nRead; + + return nRead; +} + + +icInt32Number CIccNullIO::Write8(void *pBuf, icInt32Number nNum) +{ + m_nPos += nNum; + if (m_nPos > m_nSize) + m_nSize = m_nPos; + + return nNum; +} + + +icInt32Number CIccNullIO::GetLength() +{ + return m_nSize; +} + + +icInt32Number CIccNullIO::Seek(icInt32Number nOffset, icSeekVal pos) +{ + icInt32Number nPos; + switch(pos) { + case icSeekSet: + nPos = nOffset; + break; + case icSeekCur: + nPos = (icInt32Number)m_nPos + nOffset; + break; + case icSeekEnd: + nPos = (icInt32Number)m_nSize + nOffset; + break; + default: + nPos = 0; + break; + } + + if (nPos < 0) + return -1; + + m_nPos = (icUInt32Number)nPos; + + if (m_nPos>m_nSize) + m_nSize = m_nPos; + + return nPos; +} + + +icInt32Number CIccNullIO::Tell() +{ + return (icInt32Number)m_nPos; +} + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccIO.h b/library/src/main/cpp/icc/IccIO.h new file mode 100644 index 00000000..7ae8b616 --- /dev/null +++ b/library/src/main/cpp/icc/IccIO.h @@ -0,0 +1,243 @@ +/** @file + File: IccIO.h + + Contains: Implementation of the CIccIO class. + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCIO_H) +#define _ICCIO_H + +#include "IccDefs.h" +#include "stdio.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +///Seek types +typedef enum { + icSeekSet=0, //Seek to an absolute position + icSeekCur, //Seek to relative position + icSeekEnd, //Seek relative to the ending +} icSeekVal; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: + * This is the base object that handles the IO with an ICC profile. + ************************************************************************** + */ +class ICCPROFLIB_API CIccIO +{ +public: + + virtual ~CIccIO() {} + + virtual void Close() {} + + virtual icInt32Number Read8(void *pBuf8, icInt32Number nNum=1) { return 0; } + virtual icInt32Number Write8(void *pBuf8, icInt32Number nNum=1) { return 0; } + + icInt32Number ReadLine(void *pBuf8, icInt32Number nNum=256); + + icInt32Number Read16(void *pBuf16, icInt32Number nNum=1); + icInt32Number Write16(void *pBuf16, icInt32Number nNum=1); + + icInt32Number Read32(void *pBuf32, icInt32Number nNum=1); + icInt32Number Write32(void *pBuf32, icInt32Number nNum=1); + + icInt32Number Read64(void *pBuf64, icInt32Number nNum=1); + icInt32Number Write64(void *pBuf64, icInt32Number nNum=1); + + icInt32Number Read8Float(void *pBufFloat, icInt32Number nNum=1); + icInt32Number Write8Float(void *pBuf16, icInt32Number nNum=1); + + icInt32Number Read16Float(void *pBufFloat, icInt32Number nNum=1); + icInt32Number Write16Float(void *pBuf16, icInt32Number nNum=1); + + icInt32Number ReadFloat32Float(void *pBufFloat, icInt32Number nNum=1); + icInt32Number WriteFloat32Float(void *pBufFloat, icInt32Number nNum=1); + + virtual icInt32Number GetLength() {return 0;} + + virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos) {return -1;} + virtual icInt32Number Tell() {return 0;} + + ///Write operation to make sure that filelength is evenly divisible by 4 + bool Align32(); + + ///Operation to make sure read position is evenly divisible by 4 + bool Sync32(icUInt32Number nOffset=0); +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: Handles generic File IO + ************************************************************************** + */ +class ICCPROFLIB_API CIccFileIO : public CIccIO +{ +public: + CIccFileIO(); + virtual ~CIccFileIO(); + + bool Open(const icChar *szFilename, const icChar *szAttr); +#if defined(WIN32) || defined(WIN64) + bool Open(const icWChar *szFilename, const icWChar *szAttr); +#endif + virtual void Close(); + + virtual icInt32Number Read8(void *pBuf, icInt32Number nNum=1); + virtual icInt32Number Write8(void *pBuf, icInt32Number nNum=1); + + virtual icInt32Number GetLength(); + + virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos); + virtual icInt32Number Tell(); + +protected: + FILE *m_fFile; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: Handles generic memory IO + ************************************************************************** + */ +class ICCPROFLIB_API CIccMemIO : public CIccIO +{ +public: + CIccMemIO(); + virtual ~CIccMemIO(); + + bool Alloc(icUInt32Number nSize, bool bWrite = false); + + bool Attach(icUInt8Number *pData, icUInt32Number nSize, bool bWrite=false); + virtual void Close(); + + virtual icInt32Number Read8(void *pBuf, icInt32Number nNum=1); + virtual icInt32Number Write8(void *pBuf, icInt32Number nNum=1); + + virtual icInt32Number GetLength(); + + virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos); + virtual icInt32Number Tell(); + + icUInt8Number *GetData() { return m_pData; } + +protected: + icUInt8Number *m_pData; + icUInt32Number m_nSize; + icUInt32Number m_nAvail; + icUInt32Number m_nPos; + + bool m_bFreeData; +}; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: Handles simulated File IO + ************************************************************************** + */ +class ICCPROFLIB_API CIccNullIO : public CIccIO +{ +public: + CIccNullIO(); + virtual ~CIccNullIO(); + + //Open resets the file to being zero size + void Open(); + virtual void Close(); + + + virtual icInt32Number Read8(void *pBuf, icInt32Number nNum=1); //Read zero's into buf + virtual icInt32Number Write8(void *pBuf, icInt32Number nNum=1); + + virtual icInt32Number GetLength(); + + virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos); + virtual icInt32Number Tell(); + +protected: + icUInt32Number m_nSize; + icUInt32Number m_nPos; +}; + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif // !defined(_ICCIO_H) diff --git a/library/src/main/cpp/icc/IccMpeACS.cpp b/library/src/main/cpp/icc/IccMpeACS.cpp new file mode 100644 index 00000000..8e4354c3 --- /dev/null +++ b/library/src/main/cpp/icc/IccMpeACS.cpp @@ -0,0 +1,491 @@ +/** @file + File: IccMpeACS.cpp + + Contains: Implementation of ACS Elements + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 1-30-2006 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) +#pragma warning( disable: 4786) //disable warning in +#endif + +#include +#include +#include +#include +#include "IccMpeACS.h" +#include "IccIO.h" +#include +#include "IccUtil.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + + +/** +****************************************************************************** +* Name: CIccMpeAcs::CIccMpeACS +* +* Purpose: +* Base constructor (protected) +******************************************************************************/ +CIccMpeAcs::CIccMpeAcs() +{ + m_pData = NULL; + m_nDataSize = 0; + + m_nReserved = 0; +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::~CIccMpeAcs +* +* Purpose: +* Base destructor +******************************************************************************/ +CIccMpeAcs::~CIccMpeAcs() +{ + if (m_pData) + free(m_pData); +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::Describe +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +void CIccMpeAcs::Describe(std::string &sDescription) +{ + icChar sigBuf[30]; + + if (GetBAcsSig()) + sDescription += "ELEM_bACS\r\n"; + else + sDescription += "ELEM_eACS\r\n"; + + icGetSig(sigBuf, m_signature); + sDescription += " Signature = "; + sDescription += sigBuf; + sDescription += "\r\n"; + + if (m_pData) { + sDescription += "\r\nData Follows:\r\n"; + + icMemDump(sDescription, m_pData, m_nDataSize); + } +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::Read +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccMpeAcs::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt16Number) + + sizeof(icUInt16Number) + + sizeof(icUInt32Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&m_nInputChannels)) + return false; + + if (!pIO->Read16(&m_nOutputChannels)) + return false; + + if (!pIO->Read32(&m_signature)) + return false; + + icUInt32Number dataSize = size - headerSize; + + if (!AllocData(dataSize)) + return false; + + if (dataSize) { + if (pIO->Read8(m_pData, dataSize)!=(icInt32Number)dataSize) + return false; + } + + return true; +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::Write +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccMpeAcs::Write(CIccIO *pIO) +{ + icElemTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (!pIO->Write16(&m_nOutputChannels)) + return false; + + if (!pIO->Write32(&m_signature)) + return false; + + if (m_pData && m_nDataSize) { + if (!pIO->Write8(m_pData, m_nDataSize)!=m_nDataSize) + return false; + } + + return true; +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::Begin +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccMpeAcs::Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE) +{ + if (m_nInputChannels!=m_nOutputChannels) + return false; + + return true; +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::Apply +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +void CIccMpeAcs::Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const +{ + memcpy(dstPixel, srcPixel, m_nInputChannels*sizeof(icFloatNumber)); +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::Validate +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +icValidateStatus CIccMpeAcs::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + icValidateStatus rv = CIccMultiProcessElement::Validate(sig, sReport, pMPE); + + return rv; +} + +/** +****************************************************************************** +* Name: CIccMpeAcs::AllocData +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccMpeAcs::AllocData(icUInt32Number size) +{ + if (m_pData) + free(m_pData); + + if (size) { + m_pData = (icUInt8Number*)malloc(size); + if (m_pData) + m_nDataSize = size; + } + else { + m_pData = NULL; + m_nDataSize = 0; + } + + return (size==0 || m_pData!=NULL); +} + + +/** +****************************************************************************** +* Name: CIccMpeBeginAcs::CIccMpeBeginAcs +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeBAcs::CIccMpeBAcs(icUInt16Number nChannels/* =0 */, icAcsSignature sig /* = icSigUnknownAcs */) +{ + m_signature = sig; + + m_nInputChannels = nChannels; + m_nOutputChannels = nChannels; +} + +/** +****************************************************************************** +* Name: CIccMpeBeginAcs::CIccMpeBeginAcs +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeBAcs::CIccMpeBAcs(const CIccMpeBAcs &elemAcs) +{ + + m_signature = elemAcs.m_signature; + m_nReserved = elemAcs.m_nReserved; + m_nInputChannels = elemAcs.m_nInputChannels; + m_nOutputChannels = elemAcs.m_nOutputChannels; + + m_pData = NULL; + m_nDataSize = 0; + + AllocData(elemAcs.m_nDataSize); + if (m_pData && elemAcs.m_nDataSize) { + memcpy(m_pData, elemAcs.m_pData, m_nDataSize); + } + + m_nReserved = 0; +} + +/** +****************************************************************************** +* Name: &CIccMpeBeginAcs::operator= +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeBAcs &CIccMpeBAcs::operator=(const CIccMpeBAcs &elemAcs) +{ + m_signature = elemAcs.m_signature; + m_nReserved = elemAcs.m_nReserved; + m_nInputChannels = elemAcs.m_nInputChannels; + m_nOutputChannels = elemAcs.m_nOutputChannels; + + AllocData(elemAcs.m_nDataSize); + if (m_pData && elemAcs.m_nDataSize) { + memcpy(m_pData, elemAcs.m_pData, m_nDataSize); + } + + return *this; +} + +/** +****************************************************************************** +* Name: CIccMpeBeginAcs::~CIccMpeBeginAcs +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeBAcs::~CIccMpeBAcs() +{ +} + +/** +****************************************************************************** +* Name: CIccMpeEndAcs::CIccMpeEndAcs +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeEAcs::CIccMpeEAcs(icUInt16Number nChannels/* =0 */, icAcsSignature sig /* = icSigUnknownAcs */) +{ + m_signature = sig; + + m_nInputChannels = nChannels; + m_nOutputChannels = nChannels; +} + +/** +****************************************************************************** +* Name: CIccMpeEndAcs::CIccMpeEndAcs +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeEAcs::CIccMpeEAcs(const CIccMpeEAcs &elemAcs) +{ + m_signature = elemAcs.m_signature; + m_nReserved = elemAcs.m_nReserved; + + m_nInputChannels = elemAcs.m_nInputChannels; + m_nOutputChannels = elemAcs.m_nOutputChannels; + + AllocData(elemAcs.m_nDataSize); + if (m_pData && elemAcs.m_nDataSize) { + memcpy(m_pData, elemAcs.m_pData, m_nDataSize); + } +} + +/** +****************************************************************************** +* Name: &CIccMpeEndAcs::operator= +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeEAcs &CIccMpeEAcs::operator=(const CIccMpeEAcs &elemAcs) +{ + m_signature = elemAcs.m_signature; + m_nReserved = elemAcs.m_nReserved; + m_nInputChannels = elemAcs.m_nInputChannels; + m_nOutputChannels = elemAcs.m_nOutputChannels; + + AllocData(elemAcs.m_nDataSize); + if (m_pData && elemAcs.m_nDataSize) { + memcpy(m_pData, elemAcs.m_pData, m_nDataSize); + } + + return *this; +} + +/** +****************************************************************************** +* Name: CIccMpeEndAcs::~CIccMpeEndAcs +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMpeEAcs::~CIccMpeEAcs() +{ +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccMpeACS.h b/library/src/main/cpp/icc/IccMpeACS.h new file mode 100644 index 00000000..79ff5378 --- /dev/null +++ b/library/src/main/cpp/icc/IccMpeACS.h @@ -0,0 +1,175 @@ +/** @file +File: IccMpeACS.h + +Contains: Header for implementation of CIccTagMultiProcessElement +ACS elements and supporting classes + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2005-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Jan 30, 2005 +// Initial CIccMpeent prototype development +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCMPEACS_H +#define _ICCMPEACS_H + +#include "IccTagMPE.h" + + +//CIccFloatTag support +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** +**************************************************************************** +* Class: CIccMpeAcs +* +* Purpose: The alternate connection space base class element +***************************************************************************** +*/ +class CIccMpeAcs : public CIccMultiProcessElement +{ +public: + virtual ~CIccMpeAcs(); + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual bool Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE); + virtual void Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + + virtual bool IsAcs() { return true; } + + bool AllocData(icUInt32Number size); + icUInt8Number* GetData() { return m_pData; } + icUInt32Number GetDataSize() { return m_nDataSize; } + + virtual icAcsSignature GetAcsSig() { return m_signature; } + +protected: + CIccMpeAcs(); + icAcsSignature m_signature; + + icUInt32Number m_nDataSize; + icUInt8Number *m_pData; +}; + + + +/** +**************************************************************************** +* Class: CIccMpeBAcs +* +* Purpose: The bACS element +***************************************************************************** +*/ +class CIccMpeBAcs : public CIccMpeAcs +{ +public: + CIccMpeBAcs(icUInt16Number nChannels=0, icAcsSignature sig = 0); + CIccMpeBAcs(const CIccMpeBAcs &elemAcs); + CIccMpeBAcs &operator=(const CIccMpeBAcs &elemAcs); + virtual CIccMultiProcessElement *NewCopy() const { return new CIccMpeBAcs(*this);} + virtual ~CIccMpeBAcs(); + + virtual icElemTypeSignature GetType() const { return icSigBAcsElemType; } + virtual const icChar *GetClassName() const { return "CIccMpeBAcs"; } + + virtual icAcsSignature GetBAcsSig() { return m_signature; } + +}; + + +/** +**************************************************************************** +* Class: CIccMpeEndAcs +* +* Purpose: The eAcs element +***************************************************************************** +*/ +class CIccMpeEAcs : public CIccMpeAcs +{ +public: + CIccMpeEAcs(icUInt16Number nChannels=0, icAcsSignature sig = 0); + CIccMpeEAcs(const CIccMpeEAcs &elemAcs); + CIccMpeEAcs &operator=(const CIccMpeEAcs &elemAcs); + virtual CIccMultiProcessElement *NewCopy() const { return new CIccMpeEAcs(*this);} + virtual ~CIccMpeEAcs(); + + virtual icElemTypeSignature GetType() const { return icSigEAcsElemType; } + virtual const icChar *GetClassName() const { return "CIccMpeEAcs"; } + + virtual icAcsSignature GetEAcsSig() { return m_signature;} +}; + + +//CIccMPElements support +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif //_ICCMPEACS_H diff --git a/library/src/main/cpp/icc/IccMpeBasic.cpp b/library/src/main/cpp/icc/IccMpeBasic.cpp new file mode 100644 index 00000000..b1ceba4f --- /dev/null +++ b/library/src/main/cpp/icc/IccMpeBasic.cpp @@ -0,0 +1,2657 @@ +/** @file + File: IccMpeBasic.cpp + + Contains: Implementation of Basic Multi Processing Elements + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 1-30-2006 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) +#pragma warning( disable: 4786) //disable warning in +#endif + +#include +#include +#include +#include +#include "IccMpeBasic.h" +#include "IccIO.h" +#include +#include "IccUtil.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::CIccFormulaCurveSegment + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccFormulaCurveSegment::CIccFormulaCurveSegment(icFloatNumber start, icFloatNumber end) +{ + m_nReserved = 0; + m_nReserved2 = 0; + m_startPoint = start; + m_endPoint = end; + + m_nFunctionType = 0; + m_nParameters = 0; + m_params = NULL; +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::CIccFormulaCurveSegment + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccFormulaCurveSegment::CIccFormulaCurveSegment(const CIccFormulaCurveSegment &seg) +{ + m_nReserved = seg.m_nReserved; + m_nReserved2 = seg.m_nReserved2; + m_startPoint = seg.m_startPoint; + m_endPoint = seg.m_endPoint; + + m_nFunctionType = seg.m_nFunctionType; + m_nParameters = seg.m_nParameters; + + if (seg.m_params) { + m_params = (icFloatNumber*)malloc(m_nParameters*sizeof(icFloatNumber)); + memcpy(m_params, seg.m_params, m_nParameters*sizeof(icFloatNumber)); + } + else + m_params = NULL; +} + +/** + ****************************************************************************** + * Name: &CIccFormulaCurveSegment::operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccFormulaCurveSegment &CIccFormulaCurveSegment::operator=(const CIccFormulaCurveSegment &seg) +{ + if (m_params) + free(m_params); + + m_nReserved = seg.m_nReserved; + m_nReserved2 = seg.m_nReserved2; + m_startPoint = seg.m_startPoint; + m_endPoint = seg.m_endPoint; + + m_nFunctionType = seg.m_nFunctionType; + m_nParameters = seg.m_nParameters; + if (seg.m_params) { + m_params = (icFloatNumber*)malloc(m_nParameters*sizeof(icFloatNumber)); + memcpy(m_params, seg.m_params, m_nParameters*sizeof(icFloatNumber)); + } + else + m_params = NULL; + + return (*this); +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::~CIccFormulaCurveSegment + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccFormulaCurveSegment::~CIccFormulaCurveSegment() +{ + if (m_params) { + free(m_params); + } +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccFormulaCurveSegment::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sDescription += "Segment ["; + if (m_startPoint==icMinFloat32Number) + sDescription += "-Infinity, "; + else { + sprintf(buf, "%.8f, ", m_startPoint); + sDescription += buf; + } + if (m_endPoint==icMaxFloat32Number) + sDescription += "+Infinity"; + else { + sprintf(buf, "%.8f", m_endPoint); + sDescription += buf; + } + sprintf(buf, "]\r\nFunctionType: %04Xh\r\n", m_nFunctionType); + sDescription += buf; + + switch(m_nFunctionType) { + case 0x0000: + if (m_params[1]==0.0 && m_params[2]==0.0) + sprintf(buf, "Y = %.8f\r\n\r\n", m_params[3]); + else if (m_params[0]==1.0 && m_params[1]==1.0 && m_params[2]==0.0 && m_params[3]==0.0) + sprintf(buf, "Y = X\r\n\r\n"); + else if (m_params[0]==1.0 && m_params[2]==0.0) + sprintf(buf, "Y = %.8f * X + %.8f\r\n\r\n", + m_params[1], m_params[3]); + else + sprintf(buf, "Y = (%.8f * X + %.8f)^%.4f + %.8f\r\n\r\n", + m_params[1], m_params[2], m_params[0], m_params[3]); + sDescription += buf; + return; + + case 0x0001: + sprintf(buf, "Y = %.8f * log (%.8f * (X ^ %.8f) + %.8f) + %.8f\r\n\r\n", + m_params[1], m_params[2], m_params[0], m_params[3], m_params[4]); + sDescription += buf; + return; + + case 0x0002: + sprintf(buf, "Y = %.8f * (%.8f ^ (%.8f * X + %.8f)) + %.8f\r\n\r\n", + m_params[0], m_params[1], m_params[2], m_params[3], m_params[4]); + sDescription += buf; + return; + + default: + int i; + sprintf(buf, "Unknown Function with %d parameters:\r\n\r\n", m_nParameters); + sDescription += buf; + + for (i=0; i size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&m_nFunctionType)) + return false; + + if (!pIO->Read16(&m_nReserved2)) + return false; + + if (m_params) { + free(m_params); + } + + switch(m_nFunctionType) { + case 0x0000: + m_nParameters = 4; + break; + + case 0x0001: + case 0x0002: + m_nParameters = 5; + break; + + default: + return false; + } + + if (m_nParameters) { + + m_params = (icFloatNumber*)malloc(m_nParameters * sizeof(icFloatNumber)); + if (!m_params) + return false; + + if (pIO->ReadFloat32Float(m_params, m_nParameters)!= m_nParameters) { + return false; + } + } + else + m_params = NULL; + + return true; +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccFormulaCurveSegment::Write(CIccIO *pIO) +{ + icCurveSegSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nFunctionType)) + return false; + + if (!pIO->Write16(&m_nReserved2)) + return false; + + switch(m_nFunctionType) { + case 0x0000: + if (m_nParameters!=4) + return false; + break; + + case 0x0001: + case 0x0002: + if (m_nParameters!=5) + return false; + break; + } + + if (m_nParameters) { + if (pIO->WriteFloat32Float(m_params, m_nParameters)!=m_nParameters) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccFormulaCurveSegment::Begin(CIccCurveSegment *pPrevSeg = NULL) +{ + switch (m_nFunctionType) { + case 0x0000: + if (!m_params || m_nParameters<4) + return false; + + return true; + + case 0x0001: + if (!m_params || m_nParameters<5) + return false; + + return true; + + case 0x0002: + if (!m_params || m_nParameters<5) + return false; + + return true; + + default: + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icFloatNumber CIccFormulaCurveSegment::Apply(icFloatNumber v) const +{ + switch (m_nFunctionType) { + case 0x0000: + //Y = (a * X + b) ^ g + c : g a b c + return (pow(m_params[1] * v + m_params[2], m_params[0]) + m_params[3]); + + case 0x0001: + // Y = a * log (b * X^g + c) + d : g a b c d + return (m_params[1] * log10(m_params[2] * pow(v, m_params[0]) + m_params[3]) + m_params[4]); + + case 0x0002: + //Y = a * b^(c*X+d) + e : a b c d e + return (m_params[0] * pow(m_params[1], m_params[2] * v + m_params[3]) + m_params[4]); + } + + //Shouldn't get here! + return v; +} + +/** + ****************************************************************************** + * Name: CIccFormulaCurveSegment::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccFormulaCurveSegment::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + icValidateStatus rv = icValidateOK; + if (m_nReserved || m_nReserved2) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " formula curve has non zero reserved data.\r\n"; + rv = icValidateWarning; + } + + switch (m_nFunctionType) { + case 0x0000: + if (!m_params || m_nParameters<4) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " formula curve has Invalid formulaCurveSegment parameters.\r\n"; + rv = icValidateCriticalError; + } + else if (m_nParameters > 4) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " formula curve has too many formulaCurveSegment parameters.\r\n"; + rv = icValidateWarning; + } + break; + + case 0x0001: + if (!m_params || m_nParameters<5) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " formula curve has Invalid formulaCurveSegment parameters.\r\n"; + rv = icValidateCriticalError; + } + else if (m_nParameters > 5) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " formula curve has too many formulaCurveSegment parameters.\r\n"; + rv = icValidateWarning; + } + break; + + case 0x0002: + if (!m_params || m_nParameters<5) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " formula curve has Invalid formulaCurveSegment parameters.\r\n"; + rv = icValidateCriticalError; + } + else if (m_nParameters > 5) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " formula curve has too many formulaCurveSegment parameters.\r\n"; + rv = icValidateWarning; + } + break; + + default: + { + icChar buf[128]; + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sprintf(buf, " formula curve uses unknown formulaCurveSegment function type %d\r\n", m_nFunctionType); + sReport += buf; + rv = icValidateCriticalError; + } + } + + return rv; +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::CIccSampledCurveSegment + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSampledCurveSegment::CIccSampledCurveSegment(icFloatNumber start, icFloatNumber end) +{ + m_nReserved = 0; + m_startPoint = start; + m_endPoint = end; + m_nCount = 0; + m_pSamples = 0; +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::CIccSampledCurveSegment + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSampledCurveSegment::CIccSampledCurveSegment(const CIccSampledCurveSegment &curve) +{ + m_nReserved = curve.m_nReserved; + m_startPoint = curve.m_startPoint; + m_endPoint = curve.m_endPoint; + m_nCount = curve.m_nCount; + + if (m_nCount) { + m_pSamples = (icFloatNumber*)malloc(m_nCount * sizeof(icFloatNumber)); + if (m_pSamples) + memcpy(m_pSamples, curve.m_pSamples, m_nCount * sizeof(icFloatNumber)); + else + m_nCount = 0; + } + else{ + m_pSamples = NULL; + } +} + +/** + ****************************************************************************** + * Name: &CIccSampledCurveSegment::operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSampledCurveSegment &CIccSampledCurveSegment::operator=(const CIccSampledCurveSegment &curve) +{ + if (m_pSamples) + free(m_pSamples); + + m_nReserved = curve.m_nReserved; + m_startPoint = curve.m_startPoint; + m_endPoint = curve.m_endPoint; + m_nCount = curve.m_nCount; + + if (m_nCount) { + m_pSamples = (icFloatNumber*)malloc(m_nCount * sizeof(icFloatNumber)); + if (m_pSamples) + memcpy(m_pSamples, curve.m_pSamples, m_nCount * sizeof(icFloatNumber)); + else + m_nCount = 0; + } + else { + m_pSamples = NULL; + } + return (*this); +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::~CIccSampledCurveSegment + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSampledCurveSegment::~CIccSampledCurveSegment() +{ + if (m_pSamples) + free(m_pSamples); +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::SetSize + * + * Purpose: + * Sets size of sampled lookup table. Previous data (if exists) is lost. + * + * Args: + * nCount = number of elements in lut (must be >= 2). Note: the m_pSample[0] is + * initialized from the the previous segment. It is not saved as part + * of Write(), or loaded as part of Read(). It will be initialized during + * the call to Begin(), The actual count of elements written to the file + * will be nCount-1 + * bZeroAlloc = flag to decide if memory should be set to zero. + * + * Return: + * true if allocation successful. + ******************************************************************************/ +bool CIccSampledCurveSegment::SetSize(icUInt32Number nCount, bool bZeroAlloc/*=true*/) +{ + if (!nCount) { + if (m_pSamples) + free(m_pSamples); + m_pSamples = NULL; + m_nCount = nCount; + return true; + } + + if (m_pSamples) { + free(m_pSamples); + } + + if (bZeroAlloc) + m_pSamples = (icFloatNumber*)calloc(nCount, sizeof(icFloatNumber)); + else + m_pSamples = (icFloatNumber*)malloc(nCount * sizeof(icFloatNumber)); + + if (m_pSamples) + m_nCount = nCount; + else + m_nCount = 0; + + return (m_pSamples != NULL); +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccSampledCurveSegment::Describe(std::string &sDescription) +{ + icChar buf[128]; + + if (m_nCount<2) { + sDescription += "Empty Segment ["; + if (m_startPoint==icMinFloat32Number) + sDescription += "-Infinity, "; + else { + sprintf(buf, "%.8f, ", m_startPoint); + sDescription += buf; + } + if (m_endPoint==icMaxFloat32Number) + sDescription += "+Infinity"; + else { + sprintf(buf, "%.8f", m_endPoint); + sDescription += buf; + } + + sprintf(buf, "]\r\n"); + sDescription += buf; + } + else { + sDescription += "Sampled Segment ["; + if (m_startPoint==icMinFloat32Number) + sDescription += "-Infinity, "; + else { + sprintf(buf, "%.8f, ", m_startPoint); + sDescription += buf; + } + if (m_endPoint==icMaxFloat32Number) + sDescription += "+Infinity"; + else { + sprintf(buf, "%.8f", m_endPoint); + sDescription += buf; + } + sprintf(buf, "]\r\n"); + sDescription += buf; + sDescription += "IN OUT\r\n"; + + icUInt32Number i; + + icFloatNumber range = m_endPoint - m_startPoint; + icFloatNumber last = (icFloatNumber)(m_nCount-1); + + for (i=1; i size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read32(&m_nCount)) + return false; + + //Reserve room for first point who's value comes from previous segment + m_nCount++; + + if (!SetSize(m_nCount, false)) + return false; + + if (m_nCount) { + if (pIO->ReadFloat32Float(m_pSamples+1, m_nCount-1)!=(icInt32Number)(m_nCount-1)) + return false; + } + + //Initialize first point with zero. Properly initialized during Begin() + m_pSamples[0] = 0; + + return true; +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccSampledCurveSegment::Write(CIccIO *pIO) +{ + icCurveSegSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + icUInt32Number nCount; + + if (m_nCount) + nCount = m_nCount -1; + else + nCount = 0; + + if (!pIO->Write32(&nCount)) + return false; + + //First point in samples is ONLY for interpolation (not saved) + if (nCount) { + if (pIO->WriteFloat32Float(m_pSamples+1, nCount)!=(icInt32Number)nCount) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccSampledCurveSegment::Begin(CIccCurveSegment *pPrevSeg = NULL) +{ + if (m_nCount<2) + return false; + + m_range = m_endPoint - m_startPoint; + m_last = (icFloatNumber)(m_nCount - 1); + + if (m_endPoint-m_startPoint == 0.0) + return false; + + if (!pPrevSeg) + return false; + + //Set up interpolation from Application of last segment + m_pSamples[0] = pPrevSeg->Apply(m_startPoint); + + return true; +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icFloatNumber CIccSampledCurveSegment::Apply(icFloatNumber v) const +{ + if (vm_endPoint) + v=m_endPoint; + + icFloatNumber pos = (v-m_startPoint)/m_range * m_last; + icUInt32Number index = (icUInt32Number) pos; + icFloatNumber remainder = pos - (icFloatNumber)index; + + if (remainder==0.0) + return m_pSamples[index]; + + return (icFloatNumber)((1.0-remainder)*m_pSamples[index] + remainder*m_pSamples[index+1]); +} + +/** + ****************************************************************************** + * Name: CIccSampledCurveSegment::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccSampledCurveSegment::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + icValidateStatus rv = icValidateOK; + if (m_nReserved) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " sampled curve has non zero reserved data.\r\n"; + rv = icValidateWarning; + } + + if (m_nCount<2) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " sampled curve has too few sample points.\r\n"; + rv = icValidateCriticalError; + } + else if (m_endPoint-m_startPoint == 0.0) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " sampled curve has a range of zero.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + + return rv; +} + + +/** + ****************************************************************************** + * Name: CIccCurveSegment::Create + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccCurveSegment* CIccCurveSegment::Create(icCurveSegSignature sig, icFloatNumber start, icFloatNumber end) +{ + switch(sig) { + case icSigFormulaCurveSeg: + return new CIccFormulaCurveSegment(start, end); + case icSigSampledCurveSeg: + return new CIccSampledCurveSegment(start, end); + default: + return NULL; + } + +} + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::CIccSegmentedCurve + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSegmentedCurve::CIccSegmentedCurve() +{ + m_list = new CIccCurveSegmentList(); + m_nReserved1 = 0; + m_nReserved2 = 0; + +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::CIccSegmentedCurve + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSegmentedCurve::CIccSegmentedCurve(const CIccSegmentedCurve &curve) +{ + CIccCurveSegmentList::iterator i; + + m_list = new CIccCurveSegmentList(); + + for (i=curve.m_list->begin(); i!=curve.m_list->end(); i++) { + m_list->push_back((*i)->NewCopy()); + } + m_nReserved1 = curve.m_nReserved1; + m_nReserved2 = curve.m_nReserved2; +} + + +/** + ****************************************************************************** + * Name: &CIccSegmentedCurve::operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSegmentedCurve &CIccSegmentedCurve::operator=(const CIccSegmentedCurve &curve) +{ + Reset(); + + CIccCurveSegmentList::iterator i; + + for (i=curve.m_list->begin(); i!=curve.m_list->end(); i++) { + m_list->push_back((*i)->NewCopy()); + } + m_nReserved1 = curve.m_nReserved1; + m_nReserved2 = curve.m_nReserved2; + + return (*this); +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::~CIccSegmentedCurve + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccSegmentedCurve::~CIccSegmentedCurve() +{ + Reset(); + delete m_list; +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccSegmentedCurve::Describe(std::string &sDescription) +{ + CIccCurveSegmentList::iterator i; + + sDescription += "BEGIN_CURVE\r\n"; + for (i=m_list->begin(); i!=m_list->end(); i++) { + (*i)->Describe(sDescription); + } +} + + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccSegmentedCurve::Read(icUInt32Number size, CIccIO *pIO) +{ + icElemTypeSignature sig; + + icUInt32Number startPos = pIO->Tell(); + + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt16Number) + + sizeof(icUInt16Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved1)) + return false; + + icUInt16Number nSegments; + + if (!pIO->Read16(&nSegments)) + return false; + + if (!pIO->Read16(&m_nReserved2)) + return false; + + Reset(); + + icUInt32Number pos = pIO->Tell(); + icCurveSegSignature segSig; + CIccCurveSegment *pSeg; + + if (nSegments==1) { + if (!pIO->Read32(&segSig)) + return false; + pSeg = CIccCurveSegment::Create(segSig, icMinFloat32Number, icMaxFloat32Number); + if (!pSeg) + return false; + + pIO->Seek(pos, icSeekSet); + + if (!pSeg->Read(size-(pos-startPos), pIO)) { + delete pSeg; + return false; + } + + m_list->push_back(pSeg); + } + else if (nSegments) { + icFloatNumber *breakpoints=(icFloatNumber*)calloc(nSegments-1, sizeof(icFloatNumber)); + + if (!breakpoints) + return false; + + if (pIO->ReadFloat32Float(breakpoints, nSegments-1)!=nSegments-1) { + free(breakpoints); + return false; + } + + int i; + for (i=0; iTell(); + if (!pIO->Read32(&segSig)) { + free(breakpoints); + return false; + } + if (pIO->Seek(pos, icSeekSet)!=(icInt32Number)pos) + return false;; + + if (!i) + pSeg = CIccCurveSegment::Create(segSig, icMinFloat32Number, breakpoints[i]); + else if (i==nSegments-1) + pSeg = CIccCurveSegment::Create(segSig, breakpoints[i-1], icMaxFloat32Number); + else + pSeg = CIccCurveSegment::Create(segSig, breakpoints[i-1], breakpoints[i]); + + if (!pSeg) { + free(breakpoints); + return false; + } + + if (!pSeg->Read(size-(pos-startPos), pIO)) { + delete pSeg; + free(breakpoints); + return false; + } + + m_list->push_back(pSeg); + } + + free(breakpoints); + } + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccSegmentedCurve::Write(CIccIO *pIO) +{ + icCurveElemSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved1)) + return false; + + icUInt16Number nSegments = (icUInt16Number)m_list->size(); + + if (!pIO->Write16(&nSegments)) + return false; + + if (!pIO->Write16(&m_nReserved2)) + return false; + + CIccCurveSegmentList::iterator i; + if (nSegments>1) { + icFloatNumber breakpoint; + + i=m_list->begin(); + for (i++; i!=m_list->end(); i++) { + breakpoint = (*i)->StartPoint(); + if (!pIO->WriteFloat32Float(&breakpoint)) + return false; + } + } + for (i=m_list->begin(); i!=m_list->end(); i++) { + if (!(*i)->Write(pIO)) + return false; + } + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Reset + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccSegmentedCurve::Reset() +{ + CIccCurveSegmentList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + delete (*i); + } + m_list->clear(); +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Insert + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccSegmentedCurve::Insert(CIccCurveSegment *pCurveSegment) +{ + CIccCurveSegmentList::reverse_iterator last = m_list->rbegin(); + + if (last!=m_list->rend()) { + if (pCurveSegment->StartPoint() == (*last)->EndPoint()) { + m_list->push_back(pCurveSegment); + return true; + } + } + else { + m_list->push_back(pCurveSegment); + return true; + } + + return false; +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccSegmentedCurve::Begin() +{ + if (m_list->size()==0) + return false; + + CIccCurveSegmentList::iterator i; + CIccCurveSegment *pLast = NULL; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + if (!(*i)->Begin(pLast)) + return false; + pLast = *i; + } + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icFloatNumber CIccSegmentedCurve::Apply(icFloatNumber v) const +{ + CIccCurveSegmentList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + if (v <= (*i)->EndPoint()) + return (*i)->Apply(v); + } + return v; +} + +/** + ****************************************************************************** + * Name: CIccSegmentedCurve::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccSegmentedCurve::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + icValidateStatus rv = icValidateOK; + if (m_nReserved1 || m_nReserved2) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " Segmented curve has non zero reserved data.\r\n"; + rv = icValidateWarning; + } + + if (m_list->size()==0) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " Has Empty CurveSegment!\r\n"; + return icValidateCriticalError; + } + + CIccCurveSegmentList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + rv = icMaxStatus(rv, (*i)->Validate(sig, sReport, pMPE)); + } + + return rv; +} + + +/** + ****************************************************************************** + * Name: CIccCurveSetCurve::Create + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccCurveSetCurve* CIccCurveSetCurve::Create(icCurveElemSignature sig) +{ + switch (sig) { + case icSigSementedCurve: + return new CIccSegmentedCurve(); + default: + return NULL; + } +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::CIccMpeCurveSet + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeCurveSet::CIccMpeCurveSet(int nSize/*=0*/) +{ + m_nReserved = 0; + if (nSize) { + m_nInputChannels = m_nOutputChannels = nSize; + m_curve = (icCurveSetCurvePtr*)calloc(nSize, sizeof(icCurveSetCurvePtr)); + m_position = (icPositionNumber*)calloc(nSize, sizeof(icPositionNumber)); + } + else { + m_nInputChannels = m_nOutputChannels = 0; + m_curve = NULL; + m_position = NULL; + } +} + +typedef std::map icCurveMap; + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::CIccMpeCurveSet + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeCurveSet::CIccMpeCurveSet(const CIccMpeCurveSet &curveSet) +{ + m_nReserved = curveSet.m_nReserved; + + if (curveSet.m_nInputChannels) { + int i; + + m_nInputChannels = m_nOutputChannels = curveSet.m_nInputChannels; + m_curve = (icCurveSetCurvePtr*)calloc(m_nInputChannels, sizeof(icCurveSetCurvePtr)); + m_position = (icPositionNumber*)calloc(m_nInputChannels, sizeof(icPositionNumber)); + + icCurveMap map; + for (i=0; iNewCopy(); + map[ptr] = m_curve[i]; + } + else + m_curve[i] = map[ptr]; + } + } + } + else { + m_nInputChannels = m_nOutputChannels = 0; + m_curve = NULL; + } +} + +/** + ****************************************************************************** + * Name: &CIccMpeCurveSet::operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeCurveSet &CIccMpeCurveSet::operator=(const CIccMpeCurveSet &curveSet) +{ + m_nReserved = m_nReserved; + + if (m_curve) { + delete [] m_curve; + } + + if (curveSet.m_nInputChannels) { + int i; + + m_nInputChannels = m_nOutputChannels = curveSet.m_nInputChannels; + m_curve = (icCurveSetCurvePtr*)calloc(m_nInputChannels, sizeof(icCurveSetCurvePtr)); + m_position = (icPositionNumber*)calloc(m_nInputChannels, sizeof(icPositionNumber)); + + icCurveMap map; + for (i=0; iNewCopy(); + map[ptr] = m_curve[i]; + } + else + m_curve[i] = map[ptr]; + } + } + } + else { + m_nInputChannels = m_nOutputChannels = 0; + m_curve = NULL; + } + + return *this; +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::~CIccMpeCurveSet + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeCurveSet::~CIccMpeCurveSet() +{ + SetSize(0); +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::SetSize + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeCurveSet::SetSize(int nNewSize) +{ + if (m_curve) { + icCurveMap map; + int i; + + for (i=0; im_nInputChannels) + return false; + + if (m_curve) { + int i; + + for (i=0; iDescribe(sDescription); + } + } + } +} + +typedef std::map icCurveOffsetMap; +typedef std::map icCurvePtrMap; + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeCurveSet::Read(icUInt32Number size, CIccIO *pIO) +{ + icElemTypeSignature sig; + + icUInt32Number startPos = pIO->Tell(); + + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt16Number) + + sizeof(icUInt16Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + icUInt16Number nInputChannels, nOutputChannels; + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&nInputChannels)) + return false; + + if (!pIO->Read16(&nOutputChannels)) + return false; + + if (nInputChannels != nOutputChannels) + return false; + + SetSize(nInputChannels); + + if (m_curve) { + int i; + + if (headerSize + m_nInputChannels*2*sizeof(icUInt32Number) > size) + return false; + + for (i=0; iRead32(&m_position[i].offset)) { + return false; + } + if (!pIO->Read32(&m_position[i].size)) { + return false; + } + } + + icCurveOffsetMap map; + icCurveElemSignature curveSig; + for (i=0; iSeek(pos, icSeekSet)!=(icInt32Number)pos) { + return false; + } + + if (!pIO->Read32(&curveSig)) { + return false; + } + m_curve[i] = CIccCurveSetCurve::Create(curveSig); + + if (!m_curve[i]) { + return false; + } + + if (pIO->Seek(pos, icSeekSet)!=(icInt32Number)pos) { + return false; + } + + if (!m_curve[i]->Read(m_position[i].size, pIO)) { + return false; + } + + map[m_position[i].offset] = m_curve[i]; + } + else { + m_curve[i] = map[m_position[i].offset]; + } + } + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeCurveSet::Write(CIccIO *pIO) +{ + icElemTypeSignature sig = GetType(); + + if (!pIO) + return false; + + icUInt32Number elemStart = pIO->Tell(); + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (m_curve && m_nInputChannels) { + int i; + icCurvePtrMap map; + icUInt32Number start, end; + icUInt32Number zeros[2] = { 0, 0}; + icPositionNumber position; + + icUInt32Number startTable = pIO->Tell(); + + //First write empty position table + for (i=0; iWrite32(&zeros[0], 2)!=2) + return false; + } + + //Now Write curves + for (i=0; iTell(); + m_curve[i]->Write(pIO); + end = pIO->Tell(); + pIO->Sync32(); + position.offset = start - elemStart; + position.size = end - start; + map[m_curve[i]] = position; + } + m_position[i] = map[m_curve[i]]; + } + } + end = pIO->Tell(); + + //Back fill position table + pIO->Seek(startTable, icSeekSet); + for (i=0; iWrite32(&m_position[i].offset)) + return false; + if (!pIO->Write32(&m_position[i].size)) + return false; + } + + pIO->Seek(end, icSeekSet); + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeCurveSet::Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE) +{ + if (!m_curve) + return false; + + int i; + for (i=0; iBegin()) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeCurveSet::Apply(CIccApplyMpe *pApply, icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) const +{ + int i; + for (i=0; iApply(*pSrcPixel++); + } +} + +/** + ****************************************************************************** + * Name: CIccMpeCurveSet::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccMpeCurveSet::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + icValidateStatus rv = CIccMultiProcessElement::Validate(sig, sReport, pMPE); + + bool empty=false; + if (m_curve) { + int i; + for (i=0; !empty && iValidate(sig, sReport, pMPE)); + } + } + } + else + empty = true; + + if (empty) { + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Element "; + sSigName = Info.GetSigName(GetType()); + sReport += sSigName; + sReport += " Has Empty Curve Element(s)!\r\n"; + return icValidateCriticalError; + } + + return rv; +} + + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::CIccMpeMatrix + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeMatrix::CIccMpeMatrix() +{ + m_nReserved = 0; + m_nInputChannels = m_nOutputChannels = 0; + m_size = 0; + m_pMatrix = NULL; + m_pConstants = NULL; +} + + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::CIccMpeMatrix + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeMatrix::CIccMpeMatrix(const CIccMpeMatrix &matrix) +{ + m_nReserved = matrix.m_nReserved; + + m_nInputChannels = matrix.m_nInputChannels; + m_nOutputChannels = matrix.m_nOutputChannels; + + m_size = matrix.m_size; + if(matrix.m_pMatrix) { + int num = m_size * sizeof(icFloatNumber); + m_pMatrix = (icFloatNumber*)malloc(num); + memcpy(m_pMatrix, matrix.m_pMatrix, num); + } + else + m_pMatrix = NULL; + + if (matrix.m_pConstants) { + int num = m_nOutputChannels*sizeof(icFloatNumber); + m_pConstants = (icFloatNumber*)malloc(num); + memcpy(m_pConstants, matrix.m_pConstants, num); + } + else + m_pConstants = NULL; +} + +/** + ****************************************************************************** + * Name: &CIccMpeMatrix::operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeMatrix &CIccMpeMatrix::operator=(const CIccMpeMatrix &matrix) +{ + m_nReserved = matrix.m_nReserved; + + m_nInputChannels = matrix.m_nInputChannels; + m_nOutputChannels = matrix.m_nOutputChannels; + + if (m_pMatrix) + free(m_pMatrix); + + m_size = matrix.m_size; + if (matrix.m_pMatrix) { + int num = m_size * sizeof(icFloatNumber); + m_pMatrix = (icFloatNumber*)malloc(num); + memcpy(m_pMatrix, matrix.m_pMatrix, num); + } + else + m_pMatrix = NULL; + + if (m_pConstants) + free(m_pConstants); + + if (matrix.m_pConstants) { + int num = m_nOutputChannels*sizeof(icFloatNumber); + m_pConstants = (icFloatNumber*)malloc(num); + memcpy(m_pConstants, matrix.m_pConstants, num); + } + else + m_pConstants = NULL; + + return *this; +} + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::~CIccMpeMatrix + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeMatrix::~CIccMpeMatrix() +{ + if (m_pMatrix) + free(m_pMatrix); + + if (m_pConstants) + free(m_pConstants); +} + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::SetSize + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeMatrix::SetSize(icUInt16Number nInputChannels, icUInt16Number nOutputChannels) +{ + if (m_pMatrix) + free(m_pMatrix); + + m_size = (icUInt32Number)nInputChannels * nOutputChannels; + + m_pMatrix = (icFloatNumber*)calloc(m_size, sizeof(icFloatNumber)); + m_pConstants = (icFloatNumber*)calloc(nOutputChannels, sizeof(icFloatNumber)); + + m_nInputChannels = nInputChannels; + m_nOutputChannels = nOutputChannels; +} + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeMatrix::Describe(std::string &sDescription) +{ + icChar buf[81]; + int i, j; + icFloatNumber *data = m_pMatrix; + + sprintf(buf, "BEGIN_ELEM_MATRIX %d %d\r\n", m_nInputChannels, m_nOutputChannels); + sDescription += buf; + + for (j=0; j size) + return false; + + if (!pIO) { + return false; + } + + icUInt16Number nInputChannels, nOutputChannels; + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&nInputChannels)) + return false; + + if (!pIO->Read16(&nOutputChannels)) + return false; + + SetSize(nInputChannels, nOutputChannels); + + if (!m_pMatrix) + return false; + + if (headerSize + m_size*sizeof(icFloat32Number) > size) + return false; + + //Read Matrix data + if (pIO->ReadFloat32Float(m_pMatrix, m_size)!=(icInt32Number)m_size) + return false; + + //Read Constant data + if (pIO->ReadFloat32Float(m_pConstants, m_nOutputChannels)!=m_nOutputChannels) + return false; + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeMatrix::Write(CIccIO *pIO) +{ + icElemTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (!pIO->Write16(&m_nOutputChannels)) + return false; + + if (m_pMatrix) { + if (pIO->WriteFloat32Float(m_pMatrix, m_size)!=(icInt32Number)m_size) + return false; + } + + //Write Constant data + if (m_pConstants) { + if (pIO->WriteFloat32Float(m_pConstants, m_nOutputChannels)!=m_nOutputChannels) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeMatrix::Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE) +{ + if (!m_pMatrix || !m_pConstants) + return false; + + if (m_nInputChannels==3 && m_nOutputChannels==3) + m_type = ic3x3Matrix; + else if (m_nInputChannels==3 && m_nOutputChannels==4) + m_type = ic3x4Matrix; + else if (m_nInputChannels==4 && m_nOutputChannels==3) + m_type = ic4x3Matrix; + else if (m_nInputChannels==4 && m_nOutputChannels==4) + m_type = ic4x4Matrix; + else + m_type = icOtherMatrix; + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeMatrix::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeMatrix::Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const +{ + icFloatNumber *data = m_pMatrix; + switch (m_type) { + case ic3x3Matrix: + *dstPixel++ = data[ 0]*srcPixel[0] + data[ 1]*srcPixel[1] + data[ 2]*srcPixel[2] + m_pConstants[0]; + *dstPixel++ = data[ 3]*srcPixel[0] + data[ 4]*srcPixel[1] + data[ 5]*srcPixel[2] + m_pConstants[1]; + *dstPixel = data[ 6]*srcPixel[0] + data[ 7]*srcPixel[1] + data[ 8]*srcPixel[2] + m_pConstants[2]; + break; + + case ic3x4Matrix: + *dstPixel++ = data[ 0]*srcPixel[0] + data[ 1]*srcPixel[1] + data[ 2]*srcPixel[2] + m_pConstants[0]; + *dstPixel++ = data[ 3]*srcPixel[0] + data[ 4]*srcPixel[1] + data[ 5]*srcPixel[2] + m_pConstants[1]; + *dstPixel++ = data[ 6]*srcPixel[0] + data[ 7]*srcPixel[1] + data[ 8]*srcPixel[2] + m_pConstants[2]; + *dstPixel = data[ 9]*srcPixel[0] + data[10]*srcPixel[1] + data[11]*srcPixel[2] + m_pConstants[3]; + break; + + case ic4x3Matrix: + *dstPixel++ = data[ 0]*srcPixel[0] + data[ 1]*srcPixel[1] + data[ 2]*srcPixel[2] + data[ 3]*srcPixel[3] + m_pConstants[0]; + *dstPixel++ = data[ 4]*srcPixel[0] + data[ 5]*srcPixel[1] + data[ 6]*srcPixel[2] + data[ 7]*srcPixel[3] + m_pConstants[1]; + *dstPixel = data[ 8]*srcPixel[0] + data[ 9]*srcPixel[1] + data[10]*srcPixel[2] + data[11]*srcPixel[3] + m_pConstants[2]; + break; + + case ic4x4Matrix: + *dstPixel++ = data[ 0]*srcPixel[0] + data[ 1]*srcPixel[1] + data[ 2]*srcPixel[2] + data[ 3]*srcPixel[3] + m_pConstants[0]; + *dstPixel++ = data[ 4]*srcPixel[0] + data[ 5]*srcPixel[1] + data[ 6]*srcPixel[2] + data[ 7]*srcPixel[3] + m_pConstants[1]; + *dstPixel++ = data[ 8]*srcPixel[0] + data[ 9]*srcPixel[1] + data[10]*srcPixel[2] + data[11]*srcPixel[3] + m_pConstants[2]; + *dstPixel = data[12]*srcPixel[0] + data[13]*srcPixel[1] + data[14]*srcPixel[2] + data[15]*srcPixel[3] + m_pConstants[3]; + break; + + case icOtherMatrix: + default: + { + int i, j; + + for (j=0; jSetClipFunc(NoClip); + m_nInputChannels = pCLUT->GetInputDim(); + m_nOutputChannels = pCLUT->GetOutputChannels(); + } +} + +/** + ****************************************************************************** + * Name: CIccMpeCLUT::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeCLUT::Describe(std::string &sDescription) +{ + if (m_pCLUT) { + m_pCLUT->DumpLut(sDescription, "ELEM_CLUT", icSigUnknownData, icSigUnknownData); + } +} + +/** + ****************************************************************************** + * Name: CIccMpeCLUT::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeCLUT::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt16Number) + + sizeof(icUInt16Number) + + 16 * sizeof(icUInt8Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&m_nInputChannels)) + return false; + + if (!pIO->Read16(&m_nOutputChannels)) + return false; + + icUInt8Number gridPoints[16]; + + if (pIO->Read8(gridPoints, 16)!=16) { + return false; + } + + m_pCLUT = new CIccCLUT((icUInt8Number)m_nInputChannels, (icUInt8Number)m_nOutputChannels, 4); + + if (!m_pCLUT) + return false; + + m_pCLUT->SetClipFunc(NoClip); + + m_pCLUT->Init(gridPoints); + + icFloatNumber *pData = m_pCLUT->GetData(0); + + if (!pData) + return false; + + icInt32Number nPoints = m_pCLUT->NumPoints()*m_nOutputChannels; + + if (pIO->ReadFloat32Float(pData,nPoints)!= nPoints) + return false; + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeCLUT::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeCLUT::Write(CIccIO *pIO) +{ + icElemTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (!pIO->Write16(&m_nOutputChannels)) + return false; + + if (m_pCLUT) { + icUInt8Number gridPoints[16]; + int i; + + for (i=0; i<16; i++) + gridPoints[i] = m_pCLUT->GridPoint(i); + + if (pIO->Write8(gridPoints, 16)!=16) + return false; + + icFloatNumber *pData = m_pCLUT->GetData(0); + icInt32Number nPoints = m_pCLUT->NumPoints()*m_nOutputChannels; + + if (pIO->WriteFloat32Float(pData, nPoints) != nPoints) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeCLUT::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeCLUT::Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE) +{ + if (!m_pCLUT) + return false; + + m_pCLUT->Begin(); + + switch (m_nInputChannels) { + case 3: + if (nInterp==icElemInterpTetra) + m_interpType = ic3dInterpTetra; + else + m_interpType = ic3dInterp; + break; + case 4: + m_interpType = ic4dInterp; + break; + case 5: + m_interpType = ic5dInterp; + break; + case 6: + m_interpType = ic6dInterp; + break; + default: + m_interpType = icNdInterp; + break; + } + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeCLUT::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeCLUT::Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const +{ + const CIccCLUT *pCLUT = m_pCLUT; + + switch(m_interpType) { + case ic3dInterpTetra: + pCLUT->Interp3dTetra(dstPixel, srcPixel); + break; + case ic3dInterp: + pCLUT->Interp3d(dstPixel, srcPixel); + break; + case ic4dInterp: + pCLUT->Interp4d(dstPixel, srcPixel); + break; + case ic5dInterp: + pCLUT->Interp5d(dstPixel, srcPixel); + break; + case ic6dInterp: + pCLUT->Interp6d(dstPixel, srcPixel); + break; + case icNdInterp: + pCLUT->InterpND(dstPixel, srcPixel); + break; + } +} + +/** + ****************************************************************************** + * Name: CIccMpeCLUT::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccMpeCLUT::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + icValidateStatus rv = CIccMultiProcessElement::Validate(sig, sReport, pMPE); + + if (!m_pCLUT) { + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Element "; + sSigName = Info.GetSigName(GetType()); + sReport += sSigName; + sReport += " Has No CLUT!\r\n"; + return icValidateCriticalError; + } + + return rv; + +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccMpeBasic.h b/library/src/main/cpp/icc/IccMpeBasic.h new file mode 100644 index 00000000..f146b909 --- /dev/null +++ b/library/src/main/cpp/icc/IccMpeBasic.h @@ -0,0 +1,417 @@ +/** @file +File: IccMpeBasic.h + +Contains: Header for implementation of Basic CIccTagMPE elements + and supporting classes + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2005-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Jan 30, 2005 +// Initial CIccMpe prototype development +// +// -Nov 6, 2006 +// Prototype Merged into release +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCELEMBASIC_H +#define _ICCELEMBASIC_H + +#include "IccTagMPE.h" + + +//CIccFloatTag support +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** +**************************************************************************** +* Class: CIccCurveSegment +* +* Purpose: +***************************************************************************** +*/ +class CIccCurveSegment +{ +public: + virtual ~CIccCurveSegment() {} + + static CIccCurveSegment* Create(icCurveSegSignature sig, icFloatNumber start, icFloatNumber end); + virtual CIccCurveSegment* NewCopy() const = 0; + + virtual icCurveSegSignature GetType() const = 0; + virtual const icChar *GetClassName() const = 0; + + virtual void Describe(std::string &sDescription)=0; + + virtual bool Read(icUInt32Number size, CIccIO *pIO)=0; + virtual bool Write(CIccIO *pIO)=0; + + virtual bool Begin(CIccCurveSegment *pPrevSeg) = 0; + virtual icFloatNumber Apply(icFloatNumber v) const =0; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const = 0; + + icFloatNumber StartPoint() { return m_startPoint; } + icFloatNumber EndPoint() { return m_endPoint;} + +protected: + icFloatNumber m_startPoint; + icFloatNumber m_endPoint; + icUInt32Number m_nReserved; +}; + + +/** +**************************************************************************** +* Class: CIccTagFormulaCurveSegment +* +* Purpose: The parametric curve segment +***************************************************************************** +*/ +class CIccFormulaCurveSegment : public CIccCurveSegment +{ +public: + CIccFormulaCurveSegment(icFloatNumber start, icFloatNumber end); + CIccFormulaCurveSegment(const CIccFormulaCurveSegment &seg); + CIccFormulaCurveSegment &operator=(const CIccFormulaCurveSegment &seg); + virtual CIccCurveSegment *NewCopy() const { return new CIccFormulaCurveSegment(*this);} + virtual ~CIccFormulaCurveSegment(); + + virtual icCurveSegSignature GetType() const { return icSigFormulaCurveSeg; } + virtual const icChar *GetClassName() const { return "CIccFormulaCurveSegment"; } + + virtual void Describe(std::string &sDescription); + + void SetFunction(icUInt16Number functionType, icUInt8Number num_parameters, icFloatNumber *parameters); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual bool Begin(CIccCurveSegment *pPrevSeg); + virtual icFloatNumber Apply(icFloatNumber v) const; + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + +protected: + icUInt16Number m_nReserved2; + icUInt8Number m_nParameters; + icUInt16Number m_nFunctionType; + icFloatNumber *m_params; +}; + + +/** +**************************************************************************** +* Class: CIccSampledCurveSegment +* +* Purpose: The sampled curve segment +***************************************************************************** +*/ +class CIccSampledCurveSegment : public CIccCurveSegment +{ +public: + CIccSampledCurveSegment(icFloatNumber start, icFloatNumber end); + CIccSampledCurveSegment(const CIccSampledCurveSegment &ITPC); + CIccSampledCurveSegment &operator=(const CIccSampledCurveSegment &ParamCurveTag); + virtual CIccCurveSegment *NewCopy() const { return new CIccSampledCurveSegment(*this);} + virtual ~CIccSampledCurveSegment(); + + virtual icCurveSegSignature GetType() const { return icSigSampledCurveSeg; } + virtual const icChar *GetClassName() const { return "CIccSampledCurveSegment"; } + + virtual bool SetSize(icUInt32Number nSize, bool bZeroAlloc=true); //nSize must be >= 2 + virtual icUInt32Number GetSize() { return m_nCount; } + + virtual icFloatNumber *GetSamples() { return m_pSamples; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual bool Begin(CIccCurveSegment *pPrevSeg); + virtual icFloatNumber Apply(icFloatNumber v) const; + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const ; + +protected: + icUInt32Number m_nCount; //number of samples used for interpolation + icFloatNumber *m_pSamples; //interpolation values - Note m_pSamples[0] is initialized from previous segment in Begin() + + icFloatNumber m_range; + icFloatNumber m_last; +}; + + +/** +**************************************************************************** +* Class: CIccCurveSetCurve +* +* Purpose: Base class for Curve Set Curves +***************************************************************************** +*/ +class CIccCurveSetCurve +{ +public: + virtual ~CIccCurveSetCurve() {} + + static CIccCurveSetCurve *Create(icCurveElemSignature sig); + virtual CIccCurveSetCurve *NewCopy() const = 0; + + virtual icCurveElemSignature GetType() const = 0; + virtual const icChar *GetClassName() const = 0; + + virtual void Describe(std::string &sDescription) = 0; + + virtual bool Read(icUInt32Number size, CIccIO *pIO) = 0; + virtual bool Write(CIccIO *pIO) = 0; + + virtual bool Begin() = 0; + virtual icFloatNumber Apply(icFloatNumber v) const = 0; + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const = 0; + +protected: +}; + +typedef std::list CIccCurveSegmentList; + +/** +**************************************************************************** +* Class: CIccSegmentedCurve +* +* Purpose: The Curve Set Segmented Curve Type +***************************************************************************** +*/ +class CIccSegmentedCurve : public CIccCurveSetCurve +{ +public: + CIccSegmentedCurve(); + CIccSegmentedCurve(const CIccSegmentedCurve &ITPC); + CIccSegmentedCurve &operator=(const CIccSegmentedCurve &ParamCurveTag); + virtual CIccCurveSetCurve *NewCopy() const { return new CIccSegmentedCurve(*this);} + virtual ~CIccSegmentedCurve(); + + virtual icCurveElemSignature GetType() const { return icSigSementedCurve; } + virtual const icChar *GetClassName() const { return "CIccSegmentedCurve"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + void Reset(); + bool Insert(CIccCurveSegment *pCurveSegment); + + virtual bool Begin(); + virtual icFloatNumber Apply(icFloatNumber v) const; + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + +protected: + CIccCurveSegmentList *m_list; + icUInt32Number m_nReserved1; + icUInt32Number m_nReserved2; +}; + +typedef CIccCurveSetCurve* icCurveSetCurvePtr; + +/** +**************************************************************************** +* Class: CIccMpeCurveSet +* +* Purpose: The curve set process element +***************************************************************************** +*/ +class CIccMpeCurveSet : public CIccMultiProcessElement +{ +public: + CIccMpeCurveSet(int nSize=0); + CIccMpeCurveSet(const CIccMpeCurveSet &curveSet); + CIccMpeCurveSet &operator=(const CIccMpeCurveSet &curveSet); + virtual CIccMultiProcessElement *NewCopy() const { return new CIccMpeCurveSet(*this);} + virtual ~CIccMpeCurveSet(); + + void SetSize(int nNewSize); + + bool SetCurve(int nIndex, icCurveSetCurvePtr newCurve); + + virtual icElemTypeSignature GetType() const { return icSigCurveSetElemType; } + virtual const icChar *GetClassName() const { return "CIccMpeCurveSet"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual bool Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE); + virtual void Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + +protected: + icCurveSetCurvePtr *m_curve; + + icPositionNumber *m_position; +}; + + +typedef enum { + ic3x3Matrix, + ic3x4Matrix, + ic4x3Matrix, + ic4x4Matrix, + icOtherMatrix +} icMatrixElemType; + +/** +**************************************************************************** +* Class: CIccMpeMatrix +* +* Purpose: The sampled float curve segment tag +***************************************************************************** +*/ +class CIccMpeMatrix : public CIccMultiProcessElement +{ +public: + CIccMpeMatrix(); + CIccMpeMatrix(const CIccMpeMatrix &ITPC); + CIccMpeMatrix &operator=(const CIccMpeMatrix &ParamCurveTag); + virtual CIccMultiProcessElement *NewCopy() const { return new CIccMpeMatrix(*this);} + virtual ~CIccMpeMatrix(); + + virtual icElemTypeSignature GetType() const { return icSigMatrixElemType; } + virtual const icChar *GetClassName() const { return "CIccMpeMatrix"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + void SetSize(icUInt16Number nInputChannels, icUInt16Number nOutputChannels); + + icFloatNumber *GetMatrix() {return m_pMatrix;} + icFloatNumber *GetConstants() {return m_pConstants;} + + virtual bool Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE); + virtual void Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + +protected: + icFloatNumber *m_pMatrix; + icFloatNumber *m_pConstants; + icUInt32Number m_size; + icMatrixElemType m_type; +}; + +typedef enum { + ic3dInterpTetra, + ic3dInterp, + ic4dInterp, + ic5dInterp, + ic6dInterp, + icNdInterp, +} icCLUTElemType; + +/** +**************************************************************************** +* Class: CIccMpeCLUT +* +* Purpose: The sampled float curve segment tag +***************************************************************************** +*/ +class CIccMpeCLUT : public CIccMultiProcessElement +{ +public: + CIccMpeCLUT(); + CIccMpeCLUT(const CIccMpeCLUT &clut); + CIccMpeCLUT &operator=(const CIccMpeCLUT &clut); + virtual CIccMultiProcessElement *NewCopy() const { return new CIccMpeCLUT(*this);} + virtual ~CIccMpeCLUT(); + + virtual icElemTypeSignature GetType() const { return icSigCLutElemType; } + virtual const icChar *GetClassName() const { return "CIccMpeCLUT"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual bool Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE); + virtual void Apply(CIccApplyMpe *pApply, icFloatNumber *dstPixel, const icFloatNumber *srcPixel) const; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + + CIccCLUT *GetCLUT() { return m_pCLUT; } + void SetCLUT(CIccCLUT *pCLUT); + +protected: + CIccCLUT *m_pCLUT; + icCLUTElemType m_interpType; +}; + + +//CIccMPElements support +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif //_ICCELEMBASIC_H diff --git a/library/src/main/cpp/icc/IccMpeFactory.cpp b/library/src/main/cpp/icc/IccMpeFactory.cpp new file mode 100644 index 00000000..fefdca5e --- /dev/null +++ b/library/src/main/cpp/icc/IccMpeFactory.cpp @@ -0,0 +1,195 @@ +/** @file + File: IccMpeFactory.cpp + + Contains: Implementation of the CIccProcessElement class and creation factories + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Feb 4, 2006 +// Added CIccProcessElement Creation using factory support +// +////////////////////////////////////////////////////////////////////// + +#include "IccTagMPE.h" +#include "IccMpeBasic.h" +#include "IccMpeACS.h" +#include "IccMpeFactory.h" +#include "IccUtil.h" +#include "IccProfile.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +CIccMultiProcessElement* CIccBasicMpeFactory::CreateElement(icElemTypeSignature elemTypeSig) +{ + switch(elemTypeSig) { + case icSigCurveSetElemType: + return new CIccMpeCurveSet(); + + case icSigMatrixElemType: + return new CIccMpeMatrix(); + + case icSigCLutElemType: + return new CIccMpeCLUT(); + + case icSigBAcsElemType: + return new CIccMpeBAcs(); + + case icSigEAcsElemType: + return new CIccMpeEAcs(); + + default: + return new CIccMpeUnknown(); + } +} + +bool CIccBasicMpeFactory::GetElementSigName(std::string &elemName, icElemTypeSignature elemTypeSig) +{ + switch(elemTypeSig) { + case icSigCurveSetElemType: + elemName = "Curve Set Element"; + break; + + case icSigMatrixElemType: + elemName = "Matrix Element"; + break; + + case icSigCLutElemType: + elemName = "CLUT Element"; + break; + + default: + elemName = "Unknown Element Type"; + break; + } + + return true; +} + +std::auto_ptr CIccMpeCreator::theElementCreator; + +CIccMpeCreator::~CIccMpeCreator() +{ + IIccMpeFactory *pFactory = DoPopFactory(true); + + while (pFactory) { + delete pFactory; + pFactory = DoPopFactory(true); + } +} + +CIccMpeCreator* CIccMpeCreator::GetInstance() +{ + if (!theElementCreator.get()) { + theElementCreator = CIccMpeCreatorPtr(new CIccMpeCreator); + + theElementCreator->DoPushFactory(new CIccBasicMpeFactory); + } + + return theElementCreator.get(); +} + +CIccMultiProcessElement* CIccMpeCreator::DoCreateElement(icElemTypeSignature elemTypeSig) +{ + CIccMpeFactoryList::iterator i; + CIccMultiProcessElement *rv = NULL; + + for (i=factoryStack.begin(); i!=factoryStack.end(); i++) { + rv = (*i)->CreateElement(elemTypeSig); + if (rv) + break; + } + return rv; +} + +bool CIccMpeCreator::DoGetElementSigName(std::string &elemName, icElemTypeSignature elemTypeSig) +{ + CIccMpeFactoryList::iterator i; + + for (i=factoryStack.begin(); i!=factoryStack.end(); i++) { + if ((*i)->GetElementSigName(elemName, elemTypeSig)) + return true; + } + + return false; +} + +void CIccMpeCreator::DoPushFactory(IIccMpeFactory *pFactory) +{ + factoryStack.push_front(pFactory); +} + +IIccMpeFactory* CIccMpeCreator::DoPopFactory(bool bAll /*=false*/) +{ + if (factoryStack.size()>0) { + CIccMpeFactoryList::iterator i=factoryStack.begin(); + IIccMpeFactory* rv = (*i); + factoryStack.pop_front(); + return rv; + } + return NULL; +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccMpeFactory.h b/library/src/main/cpp/icc/IccMpeFactory.h new file mode 100644 index 00000000..b5a413f7 --- /dev/null +++ b/library/src/main/cpp/icc/IccMpeFactory.h @@ -0,0 +1,296 @@ +/** @file + File: IccMpeFactory.h + + Contains: Header for implementation of CIccMpeFactory class and + creation factories + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2005-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Feb 4, 2006 +// A CIccMpeCreator singleton class has been added to provide general +// support for dynamically creating element classes using a element signature. +// Prototype and private element type support can be added to the system +// by pushing additional IIccMpeFactory based objects to the +// singleton CIccMpeCreator object. +// +// -Nov 6, 2006 +// Merged into release +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCMPEFACTORY_H +#define _ICCMPEFACTORY_H + +#include "IccDefs.h" +#include +#include + +//CIccProcessElement factory support +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +class CIccMultiProcessElement; + +/** + *********************************************************************** + * Class: IIccMpeFactory + * + * Purpose: + * IIccMpeFactory is a factory pattern interface for CIccProcessElement + * creation. + * This class is pure virtual. + *********************************************************************** + */ +class ICCPROFLIB_API IIccMpeFactory +{ +public: + virtual ~IIccMpeFactory() {} + + /** + * Function: CreateElement(elemTypeSig) + * Create a element of type elemTypeSig. + * + * Parameter(s): + * elemTypeSig = signature of the ICC element type for the element to + * be created + * + * Returns a new CIccProcessElement object of the given signature type. + * If the element factory doesn't support creation of elements of type + * elemTypeSig then it should return NULL. + */ + virtual CIccMultiProcessElement* CreateElement(icElemTypeSignature elemTypeSig)=0; + + /** + * Function: GetElementSigName(elemTypeSig) + * Get display name of elemTypeSig. + * + * Parameter(s): + * elemName = string to put element name into, + * elemTypeSig = signature of the ICC element type to get a name for + * + * Returns true if element type is recognized by the factory, false if + * the factory doesn't create elemTypeSig elements. + */ + virtual bool GetElementSigName(std::string &elemName, icElemTypeSignature elemTypeSig)=0; +}; + + +//A CIccMpeFactoryList is used by CIccMpeCreator to keep track of element +//creation factories +typedef std::list CIccMpeFactoryList; + + +/** + *********************************************************************** + * Class: CIccBasicMpeFactory + * + * Purpose: + * CIccBasicMpeFactory provides creation of CIccProcessElement's + * defined by the ICC profile specification. The CIccMpeCreator always + * creates a CIccBasicElemFactory. + *********************************************************************** + */ +class CIccBasicMpeFactory : public IIccMpeFactory +{ +public: + /** + * Function: CreateElement(elemTypeSig) + * Create a element of type elemTypeSig. + * + * Parameter(s): + * elemTypeSig = signature of the ICC element type for the element to be created + * + * Returns a new CIccProcessElement object of the given signature type. + * Unrecognized elemTypeSig's will be created as a CIccProcessElementUnknown object. + */ + virtual CIccMultiProcessElement* CreateElement(icElemTypeSignature elementSig); + + /** + * Function: GetElementSigName(elemTypeSig) + * Get display name of elemTypeSig. + * + * Parameter(s): + * elemName = string to put element name into, + * elemTypeSig = signature of the ICC element type to get a name for + * + * Returns true if element type is recognized by the factory, false if the + * factory doesn't create elemTypeSig elements. + */ + virtual bool GetElementSigName(std::string &elemName, icElemTypeSignature elemTypeSig); +}; + +class CIccMpeCreator; + +typedef std::auto_ptr CIccMpeCreatorPtr; + +/** + *********************************************************************** + * Class: CIccMpeCreator + * + * Purpose: + * CIccMpeCreator uses a singleton pattern to provide dynamically + * upgradeable CIccProcessElement derived object creation based on + * element signature. + *********************************************************************** + */ +class CIccMpeCreator +{ +public: + ~CIccMpeCreator(); + + /** + * Function: CreateElement(elemTypeSig) + * Create a element of type elemTypeSig. + * + * Parameter(s): + * elemTypeSig = signature of the ICC element type for the element to + * be created + * + * Returns a new CIccProcessElement object of the given signature type. + * Each factory in the factoryStack is used until a factory supports the + * signature type. + */ + static CIccMultiProcessElement* CreateElement(icElemTypeSignature elemTypeSig) + { return CIccMpeCreator::GetInstance()->DoCreateElement(elemTypeSig); } + + /** + * Function: GetElementSigName(elemTypeSig) + * Get display name of elemTypeSig. + * + * Parameter(s): + * elemName = string to put element name into + * elemTypeSig = signature of the ICC element type to get a name for + * + * Returns true if element type is recognized by any factory, false if all + * factories do not create elemTypeSig elements. If element type is not + * recognized by any factories a suitable display name will be placed in + * elemName. + */ + static bool GetElementSigName(std::string &elemName, icElemTypeSignature elemTypeSig) + { return CIccMpeCreator::GetInstance()->DoGetElementSigName(elemName, elemTypeSig); } + + /** + * Function: PushFactory(pFactory) + * Add an IIccMpeFactory to the stack of element factories tracked by + * the system. + * + * Parameter(s): + * pFactory = pointer to an IIccMpeFactory object to add to the + * system. The pFactory must be created with new, and will be owned + * CIccMpeCreator until popped off the stack using PopFactory(). + * Any factories not popped off will be taken care of properly on + * application shutdown. + * + */ + static void PushFactory(IIccMpeFactory *pFactory) + { CIccMpeCreator::GetInstance()->CIccMpeCreator::DoPushFactory(pFactory); } + + /** + * Function: PopFactory() + * Remove the top IIccMpeFactory from the stack of element factories + * tracked by the system. + * + * Parameter(s): + * None + * + * Returns the top IIccMpeFactory from the stack of element factories + * tracked by the system. The returned element factory is no longer + * owned by the system and needs to be deleted to avoid memory leaks. + * + * Note: The initial CIccBasicElemFactory cannot be popped off the stack. + */ + static IIccMpeFactory* PopFactory() + { return CIccMpeCreator::GetInstance()->DoPopFactory(); } + +private: + /**Only GetInstance() can create the singleton*/ + CIccMpeCreator() { } + + /** + * Function: GetInstance() + * Private static function to access singleton CiccElementCreator Object. + * + * Parameter(s): + * None + * + * Returns the singleton CIccMpeCreator object. It will allocate + * a new one and push a single CIccSpecElement Factory object onto the + * factory stack if the singleton has not been intialized. + */ + static CIccMpeCreator* GetInstance(); + + CIccMultiProcessElement* DoCreateElement(icElemTypeSignature elemTypeSig); + bool DoGetElementSigName(std::string &elemName, icElemTypeSignature elemTypeSig); + void DoPushFactory(IIccMpeFactory *pFactory); + IIccMpeFactory* DoPopFactory(bool bAll=false); + + static CIccMpeCreatorPtr theElementCreator; + + CIccMpeFactoryList factoryStack; +}; + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif //_ICCMPEFACTORY_H diff --git a/library/src/main/cpp/icc/IccPrmg.cpp b/library/src/main/cpp/icc/IccPrmg.cpp new file mode 100644 index 00000000..fba1ebec --- /dev/null +++ b/library/src/main/cpp/icc/IccPrmg.cpp @@ -0,0 +1,298 @@ +/** @file +File: IccPRMG.cpp + +Contains: Implementation of CIccPRMG class + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2005-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +#include "IccPrmg.h" +#include "IccUtil.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/********************************************************************** + * The following table is from the PRMG specification. + * + * The first dimension corresponds to hue values going from 0 to 360 + * degrees in ten degree intervals (with 360 duplicating 0 for + * interpolation purposes. + * + * The second dimension corresponds to increasing lightness values. The + * first entry is for 3.5 L*, succeeding entries are for L* values + * increasing by 5 L* from 5 to 100. L* values below 3.5 or above 100 + * are considered to be out of gamut. + */ +static icFloatNumber icPRMG_Chroma[37][21] = { + {0, 11, 26, 39, 52, 64, 74, 83, 91, 92, 91, 87, 82, 75, 67, 57, 47, 37, 25, 13, 0}, + {0, 10, 24, 38, 50, 62, 73, 82, 90, 92, 91, 87, 82, 75, 67, 58, 48, 37, 26, 13, 0}, + {0, 10, 23, 37, 50, 62, 73, 84, 93, 94, 94, 90, 85, 78, 70, 60, 50, 39, 27, 14, 0}, + {0, 9, 22, 35, 48, 61, 74, 86, 98, 100, 101, 96, 90, 83, 75, 65, 54, 42, 30, 15, 0}, + {0, 8, 21, 34, 47, 60, 73, 83, 93, 97, 101, 99, 97, 90, 83, 73, 61, 47, 34, 17, 0}, + {0, 8, 20, 32, 43, 55, 66, 77, 88, 95, 99, 101, 100, 98, 92, 85, 72, 56, 40, 20, 0}, + {0, 7, 17, 27, 37, 47, 57, 67, 76, 84, 91, 96, 100, 102, 103, 98, 90, 72, 51, 26, 0}, + {0, 6, 16, 25, 34, 43, 52, 60, 68, 76, 83, 90, 96, 100, 104, 107, 109, 100, 74, 37, 0}, + {0, 6, 15, 23, 32, 40, 48, 57, 64, 71, 78, 85, 91, 97, 103, 107, 110, 113, 110, 70, 0}, + {0, 6, 14, 22, 30, 39, 47, 55, 62, 68, 75, 82, 88, 95, 101, 106, 112, 117, 120, 123, 0}, + {0, 6, 14, 22, 30, 38, 46, 54, 61, 68, 74, 81, 88, 94, 100, 106, 109, 112, 112, 92, 0}, + {0, 6, 14, 22, 31, 39, 47, 55, 63, 69, 76, 83, 89, 96, 100, 103, 106, 107, 102, 75, 0}, + {0, 6, 15, 24, 32, 41, 49, 58, 66, 73, 80, 87, 93, 98, 101, 102, 99, 91, 73, 50, 0}, + {0, 6, 16, 25, 35, 44, 54, 63, 72, 80, 87, 93, 97, 101, 99, 94, 86, 73, 56, 34, 0}, + {0, 7, 18, 28, 38, 48, 57, 67, 77, 86, 95, 98, 101, 97, 93, 85, 75, 61, 44, 26, 0}, + {0, 7, 19, 30, 40, 51, 62, 72, 83, 92, 97, 99, 96, 91, 85, 76, 66, 52, 37, 22, 0}, + {0, 7, 20, 32, 44, 56, 68, 80, 92, 96, 99, 97, 92, 87, 79, 70, 59, 46, 33, 19, 0}, + {0, 8, 20, 32, 43, 53, 64, 75, 85, 91, 96, 93, 89, 82, 75, 65, 55, 42, 30, 17, 0}, + {0, 8, 20, 31, 41, 52, 62, 72, 81, 87, 92, 90, 86, 79, 71, 61, 52, 40, 28, 15, 0}, + {0, 8, 20, 30, 40, 50, 60, 68, 76, 82, 87, 85, 82, 76, 69, 60, 50, 39, 27, 14, 0}, + {0, 8, 20, 30, 38, 47, 56, 63, 70, 76, 82, 81, 77, 72, 66, 58, 49, 38, 27, 14, 0}, + {0, 8, 20, 29, 37, 46, 53, 60, 66, 73, 79, 80, 75, 70, 64, 57, 49, 38, 27, 14, 0}, + {0, 8, 20, 29, 37, 45, 52, 59, 65, 71, 76, 75, 72, 68, 63, 56, 48, 38, 27, 14, 0}, + {0, 9, 20, 29, 38, 46, 53, 59, 65, 70, 75, 73, 71, 66, 61, 54, 46, 36, 26, 13, 0}, + {0, 10, 22, 31, 40, 48, 55, 61, 67, 71, 74, 70, 66, 61, 56, 49, 41, 32, 23, 12, 0}, + {0, 11, 24, 34, 43, 51, 59, 65, 70, 73, 71, 68, 63, 58, 52, 45, 38, 30, 21, 11, 0}, + {0, 14, 27, 38, 48, 57, 64, 69, 73, 73, 70, 66, 61, 56, 50, 43, 35, 28, 20, 10, 0}, + {0, 17, 32, 45, 55, 65, 70, 75, 75, 73, 70, 66, 61, 55, 49, 42, 34, 27, 19, 10, 0}, + {0, 21, 42, 55, 68, 75, 81, 80, 79, 76, 72, 67, 61, 55, 49, 41, 34, 26, 18, 9, 0}, + {0, 26, 52, 68, 83, 86, 89, 87, 84, 80, 75, 69, 63, 57, 50, 42, 35, 27, 18, 10, 0}, + {0, 25, 69, 82, 95, 94, 93, 91, 88, 85, 79, 73, 66, 59, 52, 44, 36, 28, 19, 10, 0}, + {0, 21, 51, 74, 91, 97, 100, 98, 95, 90, 84, 77, 70, 63, 55, 47, 39, 30, 20, 10, 0}, + {0, 18, 41, 62, 79, 91, 102, 101, 98, 95, 89, 83, 76, 68, 60, 51, 42, 32, 22, 11, 0}, + {0, 16, 35, 53, 71, 82, 91, 100, 104, 102, 98, 91, 84, 76, 67, 57, 47, 36, 24, 12, 0}, + {0, 14, 31, 46, 61, 73, 83, 92, 101, 103, 99, 95, 89, 80, 71, 61, 50, 38, 26, 13, 0}, + {0, 12, 28, 42, 55, 68, 77, 86, 94, 96, 93, 90, 85, 77, 68, 58, 48, 37, 25, 13, 0}, + {0, 11, 26, 39, 52, 64, 74, 83, 91, 92, 91, 87, 82, 75, 67, 57, 47, 37, 25, 13, 0}, +}; + +CIccPRMG::CIccPRMG() +{ + m_nTotal = m_nDE1 = m_nDE2 = m_nDE3 = m_nDE5 = m_nDE10 = 0; + + m_bPrmgImplied = false; +} + +icFloatNumber CIccPRMG::GetChroma(icFloatNumber L, icFloatNumber h) +{ + if (L<3.5 || L>100.0) + return -1; + + int nHIndex, nLIndex; + icFloatNumber dHFraction, dLFraction; + + while (h<0.0) + h+=360.0; + + while (h>=360.0) + h-=360.0; + + nHIndex = (int)(h/10.0); + dHFraction = (icFloatNumber)((h - nHIndex*10.0)/10.0); + + if (L<5) { + nLIndex = 0; + dLFraction = (icFloatNumber)((L-3.5) / (5.0-3.5)); + } + else if (L==100.0) { + nLIndex = 19; + dLFraction = 1.0; + } + else { + nLIndex = (int)((L-5.0)/5.0) + 1; + dLFraction = (icFloatNumber)((L-nLIndex*5.0)/5.0); + } + + icFloatNumber dInvLFraction = (icFloatNumber)(1.0 - dLFraction); + + icFloatNumber ch1 = icPRMG_Chroma[nHIndex][nLIndex]*dInvLFraction + icPRMG_Chroma[nHIndex][nLIndex+1]*dLFraction; + icFloatNumber ch2 = icPRMG_Chroma[nHIndex+1][nLIndex]*dInvLFraction + icPRMG_Chroma[nHIndex+1][nLIndex+1]*dLFraction; + + return (icFloatNumber)(ch1*(1.0-dHFraction) + ch2 * 1.0*dHFraction); +} + +bool CIccPRMG::InGamut(icFloatNumber L, icFloatNumber c, icFloatNumber h) +{ + icFloatNumber dChroma = GetChroma(L, h); + + if (dChroma<0.0 || c>dChroma) + return false; + + return true; +} + +bool CIccPRMG::InGamut(icFloatNumber *Lab) +{ + icFloatNumber Lch[3]; + + icLab2Lch(Lch, Lab); + return InGamut(Lch[0], Lch[1], Lch[2]); +} + +icStatusCMM CIccPRMG::EvaluateProfile(CIccProfile *pProfile, icRenderingIntent nIntent/* =icUnknownIntent */, + icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */) +{ + if (!pProfile) + { + return icCmmStatCantOpenProfile; + } + + if (pProfile->m_Header.deviceClass!=icSigInputClass && + pProfile->m_Header.deviceClass!=icSigDisplayClass && + pProfile->m_Header.deviceClass!=icSigOutputClass && + pProfile->m_Header.deviceClass!=icSigColorSpaceClass) + { + return icCmmStatInvalidProfile; + } + + m_bPrmgImplied = false; + if (nIntent==icPerceptual || nIntent==icSaturation) { + icTagSignature rigSig = (icTagSignature)(icSigPerceptualRenderingIntentGamutTag + ((icUInt32Number)nIntent)%4); + CIccTag *pSigTag = pProfile->FindTag(rigSig); + + if (pSigTag && pSigTag->GetType()==icSigSignatureType) { + CIccTagSignature *pSig = (CIccTagSignature*)pSigTag; + + if (pSig->GetValue()==icSigPerceptualReferenceMediumGamut) + m_bPrmgImplied = true; + } + } + + CIccCmm Lab2Dev2Lab(icSigLabData, icSigLabData, false); + + icStatusCMM result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); + if (result != icCmmStatOk) { + return result; + } + + result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); + if (result != icCmmStatOk) { + return result; + } + + result = Lab2Dev2Lab.Begin(); + if (result != icCmmStatOk) { + return result; + } + icFloatNumber pcs[3], Lab1[3], Lab2[3], dE; + + m_nTotal = m_nDE1 = m_nDE2 = m_nDE3 = m_nDE5 = m_nDE10 = 0; + + for (pcs[0]=0.0; pcs[0]<=1.0; pcs[0] += (icFloatNumber)0.01) { + for (pcs[1]=0.0; pcs[1]<=1.0; pcs[1] += (icFloatNumber)0.01) { + for (pcs[2]=0.0; pcs[2]<=1.0; pcs[2] += (icFloatNumber)0.01) { + memcpy(Lab1, pcs, 3*sizeof(icFloatNumber)); + icLabFromPcs(Lab1); + if (InGamut(Lab1)) { + Lab2Dev2Lab.Apply(Lab2, pcs); + icLabFromPcs(Lab2); + + dE = icDeltaE(Lab1, Lab2); + m_nTotal++; + + if (dE<=1.0) { + m_nDE1++; + m_nDE2++; + m_nDE3++; + m_nDE5++; + m_nDE10++; + } + else if (dE<=2.0) { + m_nDE2++; + m_nDE3++; + m_nDE5++; + m_nDE10++; + } + else if (dE<=3.0) { + m_nDE3++; + m_nDE5++; + m_nDE10++; + } + else if (dE<=5.0) { + m_nDE5++; + m_nDE10++; + } + else if (dE<=10.0) { + m_nDE10++; + } + } + } + } + } + + return icCmmStatOk; +} + +icStatusCMM CIccPRMG::EvaluateProfile(const icChar *szProfilePath, icRenderingIntent nIntent/* =icUnknownIntent */, + icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */) +{ + CIccProfile *pProfile = ReadIccProfile(szProfilePath); + + if (!pProfile) + return icCmmStatCantOpenProfile; + + icStatusCMM result = EvaluateProfile(pProfile, nIntent, nInterp, buseMpeTags); + + delete pProfile; + + return result; +} + + +#ifdef USESAMPLEICCNAMESPACE +} +#endif diff --git a/library/src/main/cpp/icc/IccPrmg.h b/library/src/main/cpp/icc/IccPrmg.h new file mode 100644 index 00000000..23338d1e --- /dev/null +++ b/library/src/main/cpp/icc/IccPrmg.h @@ -0,0 +1,105 @@ +/** @file +File: IccPrmg.h + +Contains: Header for implementation of CIccPrmg class + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2007-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Oct 27, 2007 +// Initial implementation of class CIccPRMG +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCPRMG_H +#define _ICCPRMG_H + +#include "IccCmm.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +class CIccPRMG +{ +public: + CIccPRMG(); + + icFloatNumber GetChroma(icFloatNumber L, icFloatNumber h); + + bool InGamut(icFloatNumber *Lab); + bool InGamut(icFloatNumber L, icFloatNumber c, icFloatNumber h); + + icStatusCMM EvaluateProfile(CIccProfile *pProfile, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, bool buseMpeTags=true); + icStatusCMM EvaluateProfile(const icChar *szProfilePath, icRenderingIntent nIntent=icUnknownIntent, + icXformInterp nInterp=icInterpLinear, bool buseMpeTags=true); + + icUInt32Number m_nDE1, m_nDE2, m_nDE3, m_nDE5, m_nDE10, m_nTotal; + + bool m_bPrmgImplied; +}; + +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif \ No newline at end of file diff --git a/library/src/main/cpp/icc/IccProfLib.dsp b/library/src/main/cpp/icc/IccProfLib.dsp new file mode 100644 index 00000000..ba54a5a9 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib.dsp @@ -0,0 +1,270 @@ +# Microsoft Developer Studio Project File - Name="IccProfLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=IccProfLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "IccProfLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "IccProfLib.mak" CFG="IccProfLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "IccProfLib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "IccProfLib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "IccProfLib" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "IccProfLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "IccProfLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "IccProfLib - Win32 Release" +# Name "IccProfLib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\IccApplyBPC.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccCmm.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccConvertUTF.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccEval.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccIO.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccMpeACS.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccMpeBasic.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccMpeFactory.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccPrmg.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccProfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagBasic.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagDict.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagFactory.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagLut.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagMPE.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagProfSeqId.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccUtil.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccXformFactory.cpp +# End Source File +# Begin Source File + +SOURCE=.\md5.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\IccApplyBPC.h +# End Source File +# Begin Source File + +SOURCE=.\IccCmm.h +# End Source File +# Begin Source File + +SOURCE=.\IccConvertUTF.h +# End Source File +# Begin Source File + +SOURCE=.\IccDefs.h +# End Source File +# Begin Source File + +SOURCE=.\IccEval.h +# End Source File +# Begin Source File + +SOURCE=.\IccIO.h +# End Source File +# Begin Source File + +SOURCE=.\IccMpeACS.h +# End Source File +# Begin Source File + +SOURCE=.\IccMpeBasic.h +# End Source File +# Begin Source File + +SOURCE=.\IccMpeFactory.h +# End Source File +# Begin Source File + +SOURCE=.\IccPrmg.h +# End Source File +# Begin Source File + +SOURCE=.\IccProfile.h +# End Source File +# Begin Source File + +SOURCE=.\IccProfLibConf.h +# End Source File +# Begin Source File + +SOURCE=.\IccTag.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagBasic.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagDict.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagFactory.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagLut.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagMPE.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagProfSeqId.h +# End Source File +# Begin Source File + +SOURCE=.\IccUtil.h +# End Source File +# Begin Source File + +SOURCE=.\IccXformFactory.h +# End Source File +# Begin Source File + +SOURCE=.\icProfileHeader.h +# End Source File +# Begin Source File + +SOURCE=.\MainPage.h +# End Source File +# Begin Source File + +SOURCE=.\md5.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Readme.txt +# End Source File +# End Target +# End Project diff --git a/library/src/main/cpp/icc/IccProfLib.vcproj b/library/src/main/cpp/icc/IccProfLib.vcproj new file mode 100644 index 00000000..53038ea5 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib.vcproj @@ -0,0 +1,534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/cpp/icc/IccProfLibConf.h b/library/src/main/cpp/icc/IccProfLibConf.h new file mode 100644 index 00000000..b390cabe --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLibConf.h @@ -0,0 +1,173 @@ +/** @file + File: IccProfLibConf.h + + Contains: Platform Specific Configuration + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +/* Header file guard bands */ +#ifndef ICCCONFIG_h +#define ICCCONFIG_h + +//Define the following to use namespace +//#define USESAMPLEICCNAMESPACE + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +//PC, visual C++ +#if defined(_MSC_VER) && !defined(__MWERKS__) && (defined(_M_IX86) || defined(_M_X64) || defined(__amd64__)) + + //Define how 64 bit integers are represented + #define ICCUINT64 unsigned __int64 + #define ICCINT64 __int64 + #define ICUINT64TYPE unsigned __int64 + #define ICINT64TYPE __int64 + + #define ICCUINT32 unsigned long + #define ICCINT32 long + #define ICUINT32TYPE unsigned long + #define ICINT32TYPE long + + #define USE_WINDOWS_MB_SUPPORT + #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + //#include //For Multibyte Translation Support + + #define ICC_BYTE_ORDER_LITTLE_ENDIAN + + #if defined(ICCPROFLIBDLL_EXPORTS) + #define ICCPROFLIB_API _declspec(dllexport) + #define ICCPROFLIB_EXTERN + #elif defined(ICCPROFLIBDLL_IMPORTS) + #define ICCPROFLIB_API _declspec(dllimport) + #define ICCPROFLIB_EXTERN extern + #else //just a regular lib + #define ICCPROFLIB_API + #define ICCPROFLIB_EXTERN + #endif + + //Since msvc doesn't support cbrtf use pow instead + #define ICC_CBRTF(v) pow((double)(v), 1.0/3.0) + + #if (_MSC_VER < 1300) + #define ICC_UNSUPPORTED_TAG_DICT + #endif + +#else // non-PC, perhaps Mac, Linux, or Solaris + + #define ICCUINT64 unsigned long long + #define ICCINT64 long long + #define ICUINT64TYPE unsigned long long + #define ICINT64TYPE long long + + #include + + //Make sure that 32 bit values are set correctly + #define ICCUINT32 uint32_t + #define ICCINT32 int32_t + #define ICUINT32TYPE uint32_t + #define ICINT32TYPE int32_t + + #if defined(__APPLE__) + #if defined(__LITTLE_ENDIAN__) + #define ICC_BYTE_ORDER_LITTLE_ENDIAN + #else + #define ICC_BYTE_ORDER_BIG_ENDIAN + #endif + + #else // Sun Solaris or Linux + #if defined(__sun__) + #define ICC_BYTE_ORDER_BIG_ENDIAN + #else + #define ICC_BYTE_ORDER_LITTLE_ENDIAN + #endif + #endif + + #define ICCPROFLIB_API + #define ICCPROFLIB_EXTERN + #define stricmp strcasecmp + + //Define ICC_CBRTF as a call to cbrtf (replace with pow if system doesn't support cbrtf) + #define ICC_CBRTF(v) cbrtf(v) + +// #define ICC_WCHAR_32BIT + + #define ICC_ENUM_CONVENIENCE + +#endif + +// remove comment below if you want LAB to XYZ conversions to not clip negative XYZ values +#define SAMPLEICC_NOCLIPLABTOXYZ + +#ifdef SAMPLEICCCMM_EXPORTS +#define MAKE_A_DLL +#endif + +#ifdef MAKE_A_DLL +#define SAMPLEICCEXPORT __declspec( dllexport) +#else +#define SAMPLEICCEXPORT __declspec( dllimport) +#endif + +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif //ICCCOFIG_h diff --git a/library/src/main/cpp/icc/IccProfLibVer.h b/library/src/main/cpp/icc/IccProfLibVer.h new file mode 100644 index 00000000..f7f4e113 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLibVer.h @@ -0,0 +1,3 @@ +#ifndef ICCPROFLIBVER +#define ICCPROFLIBVER "1.6.11" +#endif diff --git a/library/src/main/cpp/icc/IccProfLib_CRTDLL.dsp b/library/src/main/cpp/icc/IccProfLib_CRTDLL.dsp new file mode 100644 index 00000000..27a29710 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib_CRTDLL.dsp @@ -0,0 +1,258 @@ +# Microsoft Developer Studio Project File - Name="IccProfLib_CRTDLL" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=IccProfLib_CRTDLL - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "IccProfLib_CRTDLL.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "IccProfLib_CRTDLL.mak" CFG="IccProfLib_CRTDLL - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "IccProfLib_CRTDLL - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "IccProfLib_CRTDLL - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "IccProfLib_CRTDLL" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "IccProfLib_CRTDLL - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_CRTDLL" +# PROP BASE Intermediate_Dir "Release_CRTDLL" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_CRTDLL" +# PROP Intermediate_Dir "Release_CRTDLL" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "IccProfLib_CRTDLL - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_CRTDLL" +# PROP BASE Intermediate_Dir "Debug_CRTDLL" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_CRTDLL" +# PROP Intermediate_Dir "Debug_CRTDLL" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "IccProfLib_CRTDLL - Win32 Release" +# Name "IccProfLib_CRTDLL - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\IccApplyBPC.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccCmm.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccConvertUTF.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccEval.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccIO.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccMpeACS.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccMpeBasic.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccMpeFactory.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccPrmg.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccProfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagBasic.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagBasic.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagDict.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagFactory.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagLut.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagLut.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagMPE.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccTagProfSeqId.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccUtil.cpp +# End Source File +# Begin Source File + +SOURCE=.\IccXformFactory.cpp +# End Source File +# Begin Source File + +SOURCE=.\md5.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\IccApplyBPC.h +# End Source File +# Begin Source File + +SOURCE=.\IccCmm.h +# End Source File +# Begin Source File + +SOURCE=.\IccConvertUTF.h +# End Source File +# Begin Source File + +SOURCE=.\IccDefs.h +# End Source File +# Begin Source File + +SOURCE=.\IccEval.h +# End Source File +# Begin Source File + +SOURCE=.\IccIO.h +# End Source File +# Begin Source File + +SOURCE=.\IccMpeACS.h +# End Source File +# Begin Source File + +SOURCE=.\IccMpeBasic.h +# End Source File +# Begin Source File + +SOURCE=.\IccMpeFactory.h +# End Source File +# Begin Source File + +SOURCE=.\IccPrmg.h +# End Source File +# Begin Source File + +SOURCE=.\IccProfile.h +# End Source File +# Begin Source File + +SOURCE=.\IccProfLib_CRTDLLConf.h +# End Source File +# Begin Source File + +SOURCE=.\IccTag.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagDict.h +# End Source File +# Begin Source File + +SOURCE=.\IccTagProfSeqId.h +# End Source File +# Begin Source File + +SOURCE=.\IccUtil.h +# End Source File +# Begin Source File + +SOURCE=.\IccXformFactory.h +# End Source File +# Begin Source File + +SOURCE=.\MainPage.h +# End Source File +# Begin Source File + +SOURCE=.\md5.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Readme.txt +# End Source File +# End Target +# End Project diff --git a/library/src/main/cpp/icc/IccProfLib_CRTDLL.vcproj b/library/src/main/cpp/icc/IccProfLib_CRTDLL.vcproj new file mode 100644 index 00000000..17c04d2f --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib_CRTDLL.vcproj @@ -0,0 +1,532 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/cpp/icc/IccProfLib_CRTDLL_v7.vcproj b/library/src/main/cpp/icc/IccProfLib_CRTDLL_v7.vcproj new file mode 100644 index 00000000..355029ae --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib_CRTDLL_v7.vcproj @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/cpp/icc/IccProfLib_CRTDLL_v8.vcproj b/library/src/main/cpp/icc/IccProfLib_CRTDLL_v8.vcproj new file mode 100644 index 00000000..41484103 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib_CRTDLL_v8.vcproj @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/cpp/icc/IccProfLib_v7.vcproj b/library/src/main/cpp/icc/IccProfLib_v7.vcproj new file mode 100644 index 00000000..f0f6e293 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib_v7.vcproj @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/cpp/icc/IccProfLib_v8.vcproj b/library/src/main/cpp/icc/IccProfLib_v8.vcproj new file mode 100644 index 00000000..ab5bddf8 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfLib_v8.vcproj @@ -0,0 +1,533 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/src/main/cpp/icc/IccProfile.cpp b/library/src/main/cpp/icc/IccProfile.cpp new file mode 100644 index 00000000..bf038c47 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfile.cpp @@ -0,0 +1,2458 @@ +/** @file + File: IccProfile.cpp + + Contains: Implementation of the CIccProfile class. + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) + #pragma warning( disable: 4786) //disable warning in +#endif +#include +#include +#include "IccProfile.h" +#include "IccTag.h" +#include "IccIO.h" +#include "IccUtil.h" +#include "md5.h" + + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +/** + ************************************************************************** + * Name: CIccProfile::CIccProfile + * + * Purpose: + * Constructor + ************************************************************************** + */ +CIccProfile::CIccProfile() +{ + m_pAttachIO = NULL; + memset(&m_Header, 0, sizeof(m_Header)); + m_Tags = new(TagEntryList); + m_TagVals = new(TagPtrList); +} + +/** + ************************************************************************** + * Name: CIccProfile::CIccProfile + * + * Purpose: + * Copy Constructor. The copy constructor makes the copy of the + * CIccProfile object in it's present state. It DOES NOT make a + * copy of the m_pAttachIO member variable. Any operation with the + * IO object should be done before making a copy. + * + * Args: + * Profile = CIccProfile object which is to be copied. + ************************************************************************** + */ +CIccProfile::CIccProfile(const CIccProfile &Profile) +{ + m_pAttachIO = NULL; + memset(&m_Header, 0, sizeof(m_Header)); + m_Tags = new(TagEntryList); + m_TagVals = new(TagPtrList); + memcpy(&m_Header, &Profile.m_Header, sizeof(m_Header)); + + if (!Profile.m_TagVals->empty()) { + TagPtrList::const_iterator i; + IccTagPtr tagptr; + for (i=Profile.m_TagVals->begin(); i!=Profile.m_TagVals->end(); i++) { + tagptr.ptr = i->ptr->NewCopy(); + m_TagVals->push_back(tagptr); + } + } + + if (!Profile.m_Tags->empty()) { + TagEntryList::const_iterator i; + IccTagEntry entry; + for (i=Profile.m_Tags->begin(); i!=Profile.m_Tags->end(); i++) { + TagPtrList::const_iterator j, k; + + //Make sure that tag entry values point to shared tags in m_TagVals + for (j=Profile.m_TagVals->begin(), k=m_TagVals->begin(); j!=Profile.m_TagVals->end() && k!=m_TagVals->end(); j++, k++) { + if (i->pTag == j->ptr) { + //k should point to the the corresponding copied tag + entry.pTag = k->ptr; + break; + } + } + + if (j==Profile.m_TagVals->end()) { //Did we not find the tag? + entry.pTag = NULL; + } + + memcpy(&entry.TagInfo, &i->TagInfo, sizeof(icTag)); + m_Tags->push_back(entry); + } + } + + m_pAttachIO = NULL; +} + +/** + ************************************************************************** + * Name: CIccProfile::operator= + * + * Purpose: + * Copy Operator. The copy operator makes the copy of the + * CIccProfile object in it's present state. It DOES NOT make a + * copy of the m_pAttachIO member variable. Any operation with the + * IO object should be done before making a copy. + * + * Args: + * Profile = CIccProfile object which is to be copied. + ************************************************************************** + */ +CIccProfile &CIccProfile::operator=(const CIccProfile &Profile) +{ + if (&Profile == this) + return *this; + + Cleanup(); + + memcpy(&m_Header, &Profile.m_Header, sizeof(m_Header)); + + if (!Profile.m_TagVals->empty()) { + TagPtrList::const_iterator i; + IccTagPtr tagptr; + for (i=Profile.m_TagVals->begin(); i!=Profile.m_TagVals->end(); i++) { + tagptr.ptr = i->ptr->NewCopy(); + m_TagVals->push_back(tagptr); + } + } + + if (!Profile.m_Tags->empty()) { + TagEntryList::const_iterator i; + IccTagEntry entry; + for (i=Profile.m_Tags->begin(); i!=Profile.m_Tags->end(); i++) { + TagPtrList::const_iterator j, k; + + //Make sure that tag entry values point to shared tags in m_TagVals + for (j=Profile.m_TagVals->begin(), k=m_TagVals->begin(); j!=Profile.m_TagVals->end() && k!=m_TagVals->end(); j++, k++) { + if (i->pTag == j->ptr) { + //k should point to the the corresponding copied tag + entry.pTag = k->ptr; + break; + } + } + + if (j==Profile.m_TagVals->end()) { //Did we not find the tag? + entry.pTag = NULL; + } + + memcpy(&entry.TagInfo, &i->TagInfo, sizeof(icTag)); + m_Tags->push_back(entry); + } + } + + m_pAttachIO = NULL; + + return *this; +} + +/** + ************************************************************************** + * Name: CIccProfile::CIccProfile + * + * Purpose: + * Destructor + ************************************************************************** + */ +CIccProfile::~CIccProfile() +{ + Cleanup(); + + delete m_Tags; + delete m_TagVals; +} + +/** + *************************************************************************** + * Name: CIccProfile::Cleanup + * + * Purpose: Detach from a pending IO object + *************************************************************************** + */ +void CIccProfile::Cleanup() +{ + if (m_pAttachIO) { + delete m_pAttachIO; + m_pAttachIO = NULL; + } + + TagPtrList::iterator i; + + for (i=m_TagVals->begin(); i!=m_TagVals->end(); i++) { + if (i->ptr) + delete i->ptr; + } + m_Tags->clear(); + m_TagVals->clear(); + memset(&m_Header, 0, sizeof(m_Header)); +} + +/** + **************************************************************************** + * Name: CIccProfile::GetTag + * + * Purpose: Get a tag entry with a given signature + * + * Args: + * sig - signature id to find in tag directory + * + * Return: + * Pointer to desired tag directory entry, or NULL if not found. + ***************************************************************************** + */ +IccTagEntry* CIccProfile::GetTag(icSignature sig) const +{ + TagEntryList::const_iterator i; + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + if (i->TagInfo.sig==(icTagSignature)sig) + return (IccTagEntry*)&(i->TagInfo); + } + + return NULL; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::AreTagsUnique + * + * Purpose: For each tag it checks to see if any other tags have the same + * signature. + * + * + * Return: + * true if all tags have unique signatures, or false if there are duplicate + * tag signatures. + ******************************************************************************* + */ +bool CIccProfile::AreTagsUnique() const +{ + TagEntryList::const_iterator i, j; + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + j=i; + for (j++; j!= m_Tags->end(); j++) { + if (i->TagInfo.sig == j->TagInfo.sig) + return false; + } + } + + return true; +} + + +/** +****************************************************************************** +* Name: CIccProfile::GetTag +* +* Purpose: Finds the first tag entry that points to the indicated tag object +* +* Args: +* pTag - pointer to tag object desired to be found +* +* Return: +* pointer to first tag directory entry that points to the desired tag object, +* or NULL if tag object is not pointed to by any tag directory entries. +******************************************************************************* +*/ +IccTagEntry* CIccProfile::GetTag(CIccTag *pTag) const +{ + TagEntryList::const_iterator i; + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + if (i->pTag==pTag) + return (IccTagEntry*)&(i->TagInfo); + } + + return NULL; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::FindTag + * + * Purpose: Finds the tag object associated with the directory entry with the + * given signature. If the profile object is attached to an IO object then + * the tag may need to be loaded first. + * + * Args: + * sig - tag signature to find in profile + * + * Return: + * The desired tag object, or NULL if unable to find in the directory or load + * tag object. + ******************************************************************************* + */ +CIccTag* CIccProfile::FindTag(icSignature sig) +{ + IccTagEntry *pEntry = GetTag(sig); + + if (pEntry) { + if (!pEntry->pTag && m_pAttachIO) + LoadTag(pEntry, m_pAttachIO); + return pEntry->pTag; + } + + return NULL; +} + +/** +****************************************************************************** +* Name: CIccProfile::GetTagIO +* +* Purpose: Finds the tag directory entry with the given signature and returns +* a CIccIO object that can be used to read the tag data stored in the profile. +* This only works if the profile is still connected to the file IO object. +* +* Args: +* sig - tag signature to find in profile +* +* Return: +* A CIccIO object that can be used to read the tag data from the file. +* Note: the caller is responsible for deleting the returned CIccIO object. +******************************************************************************* +*/ +CIccMemIO* CIccProfile::GetTagIO(icSignature sig) +{ + IccTagEntry *pEntry = GetTag(sig); + + if (pEntry && m_pAttachIO) { + CIccMemIO *pIO = new CIccMemIO; + + if (!pIO) + return NULL; + + if (!pIO->Alloc(pEntry->TagInfo.size)) { + delete pIO; + return NULL; + } + + m_pAttachIO->Seek(pEntry->TagInfo.offset, icSeekSet); + m_pAttachIO->Read8(pIO->GetData(), pIO->GetLength()); + return pIO; + } + + return NULL; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::AttachTag + * + * Purpose: Assign a tag object to a directory entry in the profile. This + * will assume ownership of the tag object. + * + * Args: + * sig - signature of tag 'name' to use to assign tag object with, + * pTag - pointer to tag object to attach to profile. + * + * Return: + * true = tag assigned to profile, + * false - tag not assigned to profile (tag already exists). + ******************************************************************************* + */ +bool CIccProfile::AttachTag(icSignature sig, CIccTag *pTag) +{ + IccTagEntry *pEntry = GetTag(sig); + + if (pEntry) { + if (pEntry->pTag == pTag) + return true; + + return false; + } + + IccTagEntry Entry; + Entry.TagInfo.sig = (icTagSignature)sig; + Entry.TagInfo.offset = 0; + Entry.TagInfo.size = 0; + Entry.pTag = pTag; + + m_Tags->push_back(Entry); + + TagPtrList::iterator i; + + for (i=m_TagVals->begin(); i!=m_TagVals->end(); i++) + if (i->ptr == pTag) + break; + + if (i==m_TagVals->end()) { + IccTagPtr TagPtr; + TagPtr.ptr = pTag; + m_TagVals->push_back(TagPtr); + } + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::DeleteTag + * + * Purpose: Delete tag directory entry with given signature. If no other tag + * directory entries use the tag object, the tag object will also be deleted. + * + * Args: + * sig - signature of tag directory entry to remove + * + * Return: + * true - desired tag directory entry was found and deleted, + * false - desired tag directory entry was not found + ******************************************************************************* + */ +bool CIccProfile::DeleteTag(icSignature sig) +{ + TagEntryList::iterator i; + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + if (i->TagInfo.sig==(icTagSignature)sig) + break; + } + if (i!=m_Tags->end()) { + CIccTag *pTag = i->pTag; + m_Tags->erase(i); + + if (!GetTag(pTag)) { + DetachTag(pTag); + delete pTag; + } + return true; + } + + return false; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::Attach + * + * Purpose: This allows for deferred IO with a profile. The profile header and + * tag directory will be read, but tag data will not be read. The IO object + * will remain attached to the profile for the purpose of reading data in as + * needed. + * + * Args: + * pIO - pointer to IO object to begin reading profile file with. + * + * Return: + * true - the IO object (file) is an ICC profile, and the CIccProfile object + * is now attached to the object, + * false - the IO object (file) is not an ICC profile. + ******************************************************************************* + */ +bool CIccProfile::Attach(CIccIO *pIO) +{ + if (m_Tags->size()) + Cleanup(); + + if (!ReadBasic(pIO)) { + Cleanup(); + return false; + } + + m_pAttachIO = pIO; + + return true; +} + +/** +****************************************************************************** +* Name: CIccProfile::Detach +* +* Purpose: Discontinues the use of defferred IO with a profile. This can be done +* once all the information needed for performing a transform has been extracted +* from the profile. +* +* Args: +* true - If an IO object was attached to the profile +* false - if no IO object was attached to the profile +******************************************************************************* +*/ +bool CIccProfile::Detach() +{ + if (m_pAttachIO) { + delete m_pAttachIO; + + m_pAttachIO = NULL; + return true; + } + + return false; +} + +/** +****************************************************************************** +* Name: CIccProfile::ReadTags +* +* Purpose: This will read the all the tags from the IO object into the +* CIccProfile object. The IO object must have been attached before +* calling this function. +* +* Return: +* true - CIccProfile object now contains all tag data, +* false - No IO object attached or tags cannot be read. +******************************************************************************* +*/ +bool CIccProfile::ReadTags(CIccProfile* pProfile) +{ + CIccIO *pIO = m_pAttachIO; + + if (pProfile && pProfile->m_pAttachIO) { + pIO = pProfile->m_pAttachIO; + } + + if (!pIO) { + return false; + } + + TagEntryList::iterator i; + icUInt32Number pos = pIO->Tell(); + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + if (!LoadTag((IccTagEntry*)&(i->TagInfo), pIO)) { + pIO->Seek(pos, icSeekSet); + return false; + } + } + + pIO->Seek(pos, icSeekSet); + + return true; +} + +/** + ****************************************************************************** + * Name: CIccProfile::Read + * + * Purpose: This will read the entire ICC profile from the IO object into the + * CIccProfile object + * + * Args: + * pIO - pointer to IO object to read ICC profile from + * + * Return: + * true - the IO object (file) is an ICC profile, and the CIccProfile object + * now contains all its data, + * false - the IO object (file) is not an ICC profile. + ******************************************************************************* + */ +bool CIccProfile::Read(CIccIO *pIO) +{ + if (m_Tags->size()) + Cleanup(); + + if (!ReadBasic(pIO)) { + Cleanup(); + return false; + } + + TagEntryList::iterator i; + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + if (!LoadTag((IccTagEntry*)&(i->TagInfo), pIO)) { + Cleanup(); + return false; + } + } + + return true; +} + +/** +****************************************************************************** +* Name: CIccProfile::ReadValidate +* +* Purpose: This will read the entire ICC profile from the IO object into the +* CIccProfile object +* +* Args: +* pIO - pointer to IO object to read ICC profile from +* sReport - string to put validation report info into. String should be initialized +* before calling +* +* Return: +* icValidateOK if file can be read, bad status otherwise. +******************************************************************************* +*/ +icValidateStatus CIccProfile::ReadValidate(CIccIO *pIO, std::string &sReport) +{ + icValidateStatus rv = icValidateOK; + + if (m_Tags->size()) + Cleanup(); + + if (!ReadBasic(pIO)) { + sReport += icValidateCriticalErrorMsg; + sReport += " - Unable to read profile!**\r\n\tProfile has invalid structure!\r\n"; + Cleanup(); + + return icValidateCriticalError; + } + + // Check profile header + if (!CheckFileSize(pIO)) { + sReport += icValidateNonCompliantMsg; + sReport += "Bad Header File Size\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + CIccInfo Info; + icProfileID profileID; + + // Check profile ID + if (Info.IsProfileIDCalculated(&m_Header.profileID)) { + CalcProfileID(pIO, &profileID); + if (strncmp((char*)profileID.ID8, (char*)m_Header.profileID.ID8, 16) != 0) { + sReport += icValidateNonCompliantMsg; + sReport += "Bad Profile ID\r\n"; + + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + + TagEntryList::iterator i; + + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + if (!LoadTag((IccTagEntry*)&(i->TagInfo), pIO)) { + sReport += icValidateCriticalErrorMsg; + sReport += " - "; + sReport += Info.GetTagSigName(i->TagInfo.sig); + sReport += " - Tag has invalid structure!\r\n"; + + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + if (rv==icValidateCriticalError) + Cleanup(); + + return rv; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::Write + * + * Purpose: Write the data associated with the CIccProfile object to an IO + * IO object. + * + * Args: + * pIO - pointer to IO object to write data to + * + * Return: + * true - success, false - failure + ******************************************************************************* + */ +bool CIccProfile::Write(CIccIO *pIO, icProfileIDSaveMethod nWriteId) +{ + //Write Header + pIO->Seek(0, icSeekSet); + + pIO->Write32(&m_Header.size); + pIO->Write32(&m_Header.cmmId); + pIO->Write32(&m_Header.version); + pIO->Write32(&m_Header.deviceClass); + pIO->Write32(&m_Header.colorSpace); + pIO->Write32(&m_Header.pcs); + pIO->Write16(&m_Header.date.year); + pIO->Write16(&m_Header.date.month); + pIO->Write16(&m_Header.date.day); + pIO->Write16(&m_Header.date.hours); + pIO->Write16(&m_Header.date.minutes); + pIO->Write16(&m_Header.date.seconds); + pIO->Write32(&m_Header.magic); + pIO->Write32(&m_Header.platform); + pIO->Write32(&m_Header.flags); + pIO->Write32(&m_Header.manufacturer); + pIO->Write32(&m_Header.model); + pIO->Write64(&m_Header.attributes); + pIO->Write32(&m_Header.renderingIntent); + pIO->Write32(&m_Header.illuminant.X); + pIO->Write32(&m_Header.illuminant.Y); + pIO->Write32(&m_Header.illuminant.Z); + pIO->Write32(&m_Header.creator); + pIO->Write8(&m_Header.profileID, sizeof(m_Header.profileID)); + pIO->Write8(&m_Header.reserved[0], sizeof(m_Header.reserved)); + + TagEntryList::iterator i, j; + icUInt32Number count; + + for (count=0, i=m_Tags->begin(); i!= m_Tags->end(); i++) { + if (i->pTag) + count++; + } + + pIO->Write32(&count); + + icUInt32Number dirpos = pIO->GetLength(); + + //Write Unintialized TagDir + for (i=m_Tags->begin(); i!= m_Tags->end(); i++) { + if (i->pTag) { + i->TagInfo.offset = 0; + i->TagInfo.size = 0; + + pIO->Write32(&i->TagInfo.sig); + pIO->Write32(&i->TagInfo.offset); + pIO->Write32(&i->TagInfo.size); + } + } + + //Write Tags + for (i=m_Tags->begin(); i!= m_Tags->end(); i++) { + if (i->pTag) { + for (j=m_Tags->begin(); j!=i; j++) { + if (i->pTag == j->pTag) + break; + } + + if (i==j) { + i->TagInfo.offset = pIO->GetLength(); + i->pTag->Write(pIO); + i->TagInfo.size = pIO->GetLength() - i->TagInfo.offset; + + pIO->Align32(); + } + else { + i->TagInfo.offset = j->TagInfo.offset; + i->TagInfo.size = j->TagInfo.size; + } + } + } + + pIO->Seek(dirpos, icSeekSet); + + //Write TagDir with offsets and sizes + for (i=m_Tags->begin(); i!= m_Tags->end(); i++) { + if (i->pTag) { + pIO->Write32(&i->TagInfo.sig); + pIO->Write32(&i->TagInfo.offset); + pIO->Write32(&i->TagInfo.size); + } + } + + //Update header with size + m_Header.size = pIO->GetLength(); + pIO->Seek(0, icSeekSet); + pIO->Write32(&m_Header.size); + + bool bWriteId; + + switch (nWriteId) { + case icVersionBasedID: + default: + bWriteId = (m_Header.version>=icVersionNumberV4); + break; + case icAlwaysWriteID: + bWriteId = true; + break; + case icNeverWriteID: + bWriteId = false; + } + + //Write the profile ID if version 4 profile + if(bWriteId) { + CalcProfileID(pIO, &m_Header.profileID); + pIO->Seek(84, icSeekSet); + pIO->Write8(&m_Header.profileID, sizeof(m_Header.profileID)); + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccProfile::InitHeader + * + * Purpose: Initializes the data to be written in the profile header. + * + ******************************************************************************* + */ +void CIccProfile::InitHeader() +{ + m_Header.size = 0; + m_Header.cmmId = icSigSampleICC; + m_Header.version=icVersionNumberV4; + m_Header.deviceClass = (icProfileClassSignature)0; + m_Header.colorSpace = (icColorSpaceSignature)0; + m_Header.pcs = icSigLabData; + + struct tm *newtime; + time_t long_time; + + time( &long_time ); /* Get time as long integer. */ + newtime = gmtime( &long_time ); + + m_Header.date.year = newtime->tm_year+1900; + m_Header.date.month = newtime->tm_mon+1; + m_Header.date.day = newtime->tm_mday; + m_Header.date.hours = newtime->tm_hour; + m_Header.date.minutes = newtime->tm_min; + m_Header.date.seconds = newtime->tm_sec; + + m_Header.magic = icMagicNumber; + m_Header.platform = (icPlatformSignature)0; + m_Header.flags = 0; + m_Header.manufacturer=0; + m_Header.model=0; + m_Header.attributes=0; + m_Header.renderingIntent=icPerceptual; + m_Header.illuminant.X = icDtoF((icFloatNumber)0.9642); + m_Header.illuminant.Y = icDtoF((icFloatNumber)1.0000); + m_Header.illuminant.Z = icDtoF((icFloatNumber)0.8249); + m_Header.creator = icSigSampleICC; + + memset(&m_Header.profileID, 0, sizeof(m_Header.profileID)); + memset(&m_Header.reserved[0], 0, sizeof(m_Header.reserved)); +} + + +/** + ***************************************************************************** + * Name: CIccProfile::ReadBasic + * + * Purpose: Read in ICC header and tag directory entries. + * + * Args: + * pIO - pointer to IO object to read data with + * + * Return: + * true - valid ICC header and tag directory, false - failure + ****************************************************************************** + */ +bool CIccProfile::ReadBasic(CIccIO *pIO) +{ + //Read Header + if (pIO->Seek(0, icSeekSet)<0 || + !pIO->Read32(&m_Header.size) || + !pIO->Read32(&m_Header.cmmId) || + !pIO->Read32(&m_Header.version) || + !pIO->Read32(&m_Header.deviceClass) || + !pIO->Read32(&m_Header.colorSpace) || + !pIO->Read32(&m_Header.pcs) || + !pIO->Read16(&m_Header.date.year) || + !pIO->Read16(&m_Header.date.month) || + !pIO->Read16(&m_Header.date.day) || + !pIO->Read16(&m_Header.date.hours) || + !pIO->Read16(&m_Header.date.minutes) || + !pIO->Read16(&m_Header.date.seconds) || + !pIO->Read32(&m_Header.magic) || + !pIO->Read32(&m_Header.platform) || + !pIO->Read32(&m_Header.flags) || + !pIO->Read32(&m_Header.manufacturer) || + !pIO->Read32(&m_Header.model) || + !pIO->Read64(&m_Header.attributes) || + !pIO->Read32(&m_Header.renderingIntent) || + !pIO->Read32(&m_Header.illuminant.X) || + !pIO->Read32(&m_Header.illuminant.Y) || + !pIO->Read32(&m_Header.illuminant.Z) || + !pIO->Read32(&m_Header.creator) || + pIO->Read8(&m_Header.profileID, sizeof(m_Header.profileID))!=sizeof(m_Header.profileID) || + pIO->Read8(&m_Header.reserved[0], sizeof(m_Header.reserved))!=sizeof(m_Header.reserved)) { + return false; + } + + if (m_Header.magic != icMagicNumber) + return false; + + icUInt32Number count, i; + IccTagEntry TagEntry; + + TagEntry.pTag = NULL; + + if (!pIO->Read32(&count)) + return false; + + //Read TagDir + for (i=0; iRead32(&TagEntry.TagInfo.sig) || + !pIO->Read32(&TagEntry.TagInfo.offset) || + !pIO->Read32(&TagEntry.TagInfo.size)) { + return false; + } + m_Tags->push_back(TagEntry); + } + + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::LoadTag + * + * Purpose: This will load from the indicated IO object and associate a tag + * object to a tag directory entry. Nothing happens if tag directory entry + * is associated with a tag object. + * + * Args: + * pTagEntry - pointer to tag directory entry, + * pIO - pointer to IO object to read tag object data from + * + * Return: + * true - tag directory object associated with tag directory entry, + * false - failure + ******************************************************************************* + */ +bool CIccProfile::LoadTag(IccTagEntry *pTagEntry, CIccIO *pIO) +{ + if (!pTagEntry) + return false; + + if (pTagEntry->pTag) + return true; + + if (pTagEntry->TagInfo.offsetTagInfo.size) { + return false; + } + + icTagTypeSignature sigType; + + //First we need to get the tag type to create the right kind of tag + if (pIO->Seek(pTagEntry->TagInfo.offset, icSeekSet)!=(icInt32Number)pTagEntry->TagInfo.offset) + return false; + + if (!pIO->Read32(&sigType)) + return false; + + CIccTag *pTag = CIccTag::Create(sigType); + + if (!pTag) + return false; + + //Now seek back to where the tag starts so the created tag object can read + //in its data. + //First we need to get the tag type to create the right kind of tag + if (pIO->Seek(pTagEntry->TagInfo.offset, icSeekSet)!=(icInt32Number)pTagEntry->TagInfo.offset) { + delete pTag; + return false; + } + + if (!pTag->Read(pTagEntry->TagInfo.size, pIO)) { + delete pTag; + return false; + } + + switch(pTagEntry->TagInfo.sig) { + case icSigAToB0Tag: + case icSigAToB1Tag: + case icSigAToB2Tag: + if (pTag->IsMBBType()) + ((CIccMBB*)pTag)->SetColorSpaces(m_Header.colorSpace, m_Header.pcs); + break; + + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + if (pTag->IsMBBType()) + ((CIccMBB*)pTag)->SetColorSpaces(m_Header.pcs, m_Header.colorSpace); + break; + + case icSigGamutTag: + if (pTag->IsMBBType()) + ((CIccMBB*)pTag)->SetColorSpaces(m_Header.pcs, icSigGamutData); + break; + + case icSigNamedColor2Tag: + ((CIccTagNamedColor2*)pTag)->SetColorSpaces(m_Header.pcs, m_Header.colorSpace); + + default: + break; + } + + pTagEntry->pTag = pTag; + + IccTagPtr TagPtr; + + TagPtr.ptr = pTag; + + m_TagVals->push_back(TagPtr); + + TagEntryList::iterator i; + + for (i=m_Tags->begin(); i!= m_Tags->end(); i++) { + if (i->TagInfo.offset == pTagEntry->TagInfo.offset && + i->pTag != pTag) + i->pTag = pTag; + } + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccProfile::DetachTag + * + * Purpose: Remove association of a tag object from all tag directory entries. + * Associated tag directory entries will be removed from the tag directory. + * The tag object is NOT deleted from memory, but is considered to be + * no longer associated with the CIccProfile object. The caller assumes + * ownership of the tag object. + * + * Args: + * pTag - pointer to tag object unassociate with the profile object + * + * Return: + * true - tag object found and unassociated with profile object, + * false - tag object not found + ******************************************************************************* + */ +bool CIccProfile::DetachTag(CIccTag *pTag) +{ + if (!pTag) + return false; + + TagPtrList::iterator i; + + for (i=m_TagVals->begin(); i!=m_TagVals->end(); i++) { + if (i->ptr == pTag) + break; + } + + if (i==m_TagVals->end()) + return false; + + m_TagVals->erase(i); + + TagEntryList::iterator j; + for (j=m_Tags->begin(); j!=m_Tags->end();) { + if (j->pTag == pTag) { + j=m_Tags->erase(j); + } + else + j++; + } + return true; +} + + +/** +**************************************************************************** +* Name: CIccProfile::CheckHeader +* +* Purpose: Validates profile header. +* +* Return: +* icValidateOK if valid, or other error status. +***************************************************************************** +*/ +icValidateStatus CIccProfile::CheckHeader(std::string &sReport) const +{ + icValidateStatus rv = icValidateOK; + + icChar buf[128]; + CIccInfo Info; + + switch(m_Header.deviceClass) { + case icSigInputClass: + case icSigDisplayClass: + case icSigOutputClass: + case icSigLinkClass: + case icSigColorSpaceClass: + case icSigAbstractClass: + case icSigNamedColorClass: + break; + + default: + sReport += icValidateCriticalErrorMsg; + sprintf(buf, " - %s: Unknown profile class!\r\n", Info.GetProfileClassSigName(m_Header.deviceClass)); + sReport += buf; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + if (!Info.IsValidSpace(m_Header.colorSpace)) { + sReport += icValidateCriticalErrorMsg; + sprintf(buf, " - %s: Unknown color space!\r\n", Info.GetColorSpaceSigName(m_Header.colorSpace)); + sReport += buf; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + if (m_Header.deviceClass==icSigLinkClass) { + if (!Info.IsValidSpace(m_Header.pcs)) { + sReport += icValidateCriticalErrorMsg; + sprintf(buf, " - %s: Unknown pcs color space!\r\n", Info.GetColorSpaceSigName(m_Header.pcs)); + sReport += buf; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + else { + if (m_Header.pcs!=icSigXYZData && m_Header.pcs!=icSigLabData) { + sReport += icValidateCriticalErrorMsg; + sprintf(buf, " - %s: Invalid pcs color space!\r\n", Info.GetColorSpaceSigName(m_Header.pcs)); + sReport += buf; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + rv = icMaxStatus(rv, Info.CheckData(sReport, m_Header.date)); + + switch(m_Header.platform) { + case icSigMacintosh: + case icSigMicrosoft: + case icSigSolaris: + case icSigSGI: + case icSigTaligent: + case icSigUnkownPlatform: + break; + + default: + sReport += icValidateWarningMsg; + sprintf(buf, " - %s: Unknown platform signature.\r\n", Info.GetPlatformSigName(m_Header.platform)); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + + switch((icCmmSignature)m_Header.cmmId) { + //Account for registered CMM's as well: + case icSigAdobe: + case icSigApple: + case icSigColorGear: + case icSigColorGearLite: + case icSigFujiFilm: + case icSigHarlequinRIP: + case icSigArgyllCMS: + case icSigLogoSync: + case icSigHeidelberg: + case icSigLittleCMS: + case icSigKodak: + case icSigKonicaMinolta: + case icSigMutoh: + case icSigSampleICC: + case icSigTheImagingFactory: + break; + + default: + sReport += icValidateWarningMsg; + sprintf(buf, " - %s: Unregisterd CMM signature.\r\n", Info.GetCmmSigName((icCmmSignature)m_Header.cmmId)); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + switch(m_Header.renderingIntent) { + case icPerceptual: + case icRelativeColorimetric: + case icSaturation: + case icAbsoluteColorimetric: + break; + + default: + sReport += icValidateCriticalErrorMsg; + sprintf(buf, " - %s: Unknown rendering intent!\r\n", Info.GetRenderingIntentName((icRenderingIntent)m_Header.renderingIntent)); + sReport += buf; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + rv = icMaxStatus(rv, Info.CheckData(sReport, m_Header.illuminant)); + icFloatNumber X = icFtoD(m_Header.illuminant.X); + icFloatNumber Y = icFtoD(m_Header.illuminant.Y); + icFloatNumber Z = icFtoD(m_Header.illuminant.Z); + if (X<0.9640 || X>0.9644 || Y!=1.0 || Z<0.8247 || Z>0.8251) { + sReport += icValidateNonCompliantMsg; + sReport += " - Non D50 Illuminant XYZ values.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + int sum=0, num = sizeof(m_Header.reserved) / sizeof(m_Header.reserved[0]); + for (int i=0; ibegin(); i!=m_Tags->end(); i++) { + tagsig = i->TagInfo.sig; + typesig = i->pTag->GetType(); + sprintf(buf, "%s", Info.GetSigName(tagsig)); + if (!IsTypeValid(tagsig, typesig)) { + sReport += icValidateNonCompliantMsg; + sReport += buf; + sprintf(buf," - %s: Invalid tag type (Might be critical!).\r\n", Info.GetTagTypeSigName(typesig)); + sReport += buf; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + + return rv; +} + + +/** +**************************************************************************** +* Name: CIccProfile::IsTypeValid +* +* Purpose: Check if tags have allowed tag types. +* +* Return: +* true if valid, else false. +***************************************************************************** +*/ +bool CIccProfile::IsTypeValid(icTagSignature tagSig, icTagTypeSignature typeSig) const +{ + switch(tagSig) { + // A to B tags + case icSigAToB0Tag: + case icSigAToB1Tag: + case icSigAToB2Tag: + { + switch(typeSig) { + case icSigLut8Type: + case icSigLut16Type: + return true; + + case icSigLutAtoBType: + if (m_Header.version >= 0x04000000L) + return true; + else + return false; + + default: + return false; + } + } + + // B to A tags + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + case icSigGamutTag: + case icSigPreview0Tag: + case icSigPreview1Tag: + case icSigPreview2Tag: + { + switch(typeSig) { + case icSigLut8Type: + case icSigLut16Type: + return true; + + case icSigLutBtoAType: + if (m_Header.version >= 0x04000000L) + return true; + else + return false; + + default: + return false; + } + } + + // Matrix column tags - XYZ types + case icSigBlueMatrixColumnTag: + case icSigGreenMatrixColumnTag: + case icSigRedMatrixColumnTag: + case icSigLuminanceTag: + case icSigMediaWhitePointTag: + case icSigMediaBlackPointTag: + { + if (typeSig!=icSigXYZType) { + return false; + } + else return true; + } + + // TRC tags + case icSigBlueTRCTag: + case icSigGreenTRCTag: + case icSigRedTRCTag: + case icSigGrayTRCTag: + { + switch(typeSig) { + case icSigCurveType: + case icSigParametricCurveType: + return true; + + default: + return false; + } + } + + case icSigCalibrationDateTimeTag: + { + if (typeSig!=icSigDateTimeType) + return false; + else return true; + } + + case icSigCharTargetTag: + { + if (typeSig!=icSigTextType) + return false; + else + return true; + } + + case icSigChromaticAdaptationTag: + { + if (typeSig!=icSigS15Fixed16ArrayType) + return false; + else return true; + } + + case icSigChromaticityTag: + { + if (typeSig!=icSigChromaticityType) + return false; + else return true; + } + + case icSigColorantOrderTag: + { + if (typeSig!=icSigColorantOrderType) + return false; + else return true; + } + + case icSigColorantTableTag: + case icSigColorantTableOutTag: + { + if (typeSig!=icSigColorantTableType) + return false; + else return true; + } + + // Multi-localized Unicode type tags + case icSigCopyrightTag: + { + if (m_Header.version>=0x04000000L) { + if (typeSig!=icSigMultiLocalizedUnicodeType) + return false; + else return true; + } + else { + if (typeSig!=icSigTextType) + return false; + else return true; + } + } + + case icSigViewingCondDescTag: + case icSigDeviceMfgDescTag: + case icSigDeviceModelDescTag: + case icSigProfileDescriptionTag: + { + if (m_Header.version>=0x04000000L) { + if (typeSig!=icSigMultiLocalizedUnicodeType) + return false; + else return true; + } + else { + if (typeSig!=icSigTextDescriptionType) + return false; + else return true; + } + } + + case icSigMeasurementTag: + { + if (typeSig!=icSigMeasurementType) + return false; + else return true; + } + + case icSigNamedColor2Tag: + { + if (typeSig!=icSigNamedColor2Type) + return false; + else return true; + } + + case icSigOutputResponseTag: + { + if (typeSig!=icSigResponseCurveSet16Type) + return false; + else return true; + } + + case icSigProfileSequenceDescTag: + { + if (typeSig!=icSigProfileSequenceDescType) + return false; + else return true; + } + + case icSigTechnologyTag: + case icSigPerceptualRenderingIntentGamutTag: + case icSigSaturationRenderingIntentGamutTag: + { + if (typeSig!=icSigSignatureType) + return false; + else return true; + } + + case icSigViewingConditionsTag: + { + if (typeSig!=icSigViewingConditionsType) + return false; + else return true; + } + + //The Private Tag case + default: + { + return true; + } + } +} + + +/** + **************************************************************************** + * Name: CIccProfile::CheckRequiredTags + * + * Purpose: Check if the Profile has the required tags + * for the specified Profile/Device class. + * + * Return: + * icValidateOK if valid, or other error status. + ***************************************************************************** + */ +icValidateStatus CIccProfile::CheckRequiredTags(std::string &sReport) const +{ + if (m_Tags->size() <= 0) { + sReport += icValidateCriticalErrorMsg; + sReport += "No tags present.\r\n"; + return icValidateCriticalError; + } + + icValidateStatus rv = icValidateOK; + + if (!GetTag(icSigProfileDescriptionTag) || + !GetTag(icSigCopyrightTag)) { + sReport += icValidateNonCompliantMsg; + sReport += "Required tags missing.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + icProfileClassSignature sig = m_Header.deviceClass; + + if (sig != icSigLinkClass) { + if (!GetTag(icSigMediaWhitePointTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Media white point tag missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + switch(sig) { + case icSigInputClass: + if (m_Header.colorSpace == icSigGrayData) { + if (!GetTag(icSigGrayTRCTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Gray TRC tag missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + else { + if (!GetTag(icSigAToB0Tag)) { + if (!GetTag(icSigRedMatrixColumnTag) || !GetTag(icSigGreenMatrixColumnTag) || + !GetTag(icSigBlueMatrixColumnTag) || !GetTag(icSigRedTRCTag) || + !GetTag(icSigGreenTRCTag) || !GetTag(icSigBlueTRCTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + break; + + case icSigDisplayClass: + if (m_Header.colorSpace == icSigGrayData) { + if (!GetTag(icSigGrayTRCTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Gray TRC tag missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + else { + if (!GetTag(icSigAToB0Tag) || !GetTag(icSigBToA0Tag)) { + if (!GetTag(icSigRedMatrixColumnTag) || !GetTag(icSigGreenMatrixColumnTag) || + !GetTag(icSigBlueMatrixColumnTag) || !GetTag(icSigRedTRCTag) || + !GetTag(icSigGreenTRCTag) || !GetTag(icSigBlueTRCTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + break; + + case icSigOutputClass: + if (m_Header.colorSpace == icSigGrayData) { + if (!GetTag(icSigGrayTRCTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Gray TRC tag missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + else { + if (!GetTag(icSigAToB0Tag) || !GetTag(icSigBToA0Tag) || + !GetTag(icSigAToB1Tag) || !GetTag(icSigBToA1Tag) || + !GetTag(icSigAToB2Tag) || !GetTag(icSigBToA2Tag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + if (!GetTag(icSigGamutTag)) { + sReport += icValidateNonCompliantMsg; + sReport += "Gamut tag missing.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + if (m_Header.version >= 0x04000000L) { + switch (m_Header.colorSpace) { + case icSig2colorData: + case icSig3colorData: + case icSig4colorData: + case icSig5colorData: + case icSig6colorData: + case icSig7colorData: + case icSig8colorData: + case icSig9colorData: + case icSig10colorData: + case icSig11colorData: + case icSig12colorData: + case icSig13colorData: + case icSig14colorData: + case icSig15colorData: + case icSig16colorData: + if (!GetTag(icSigColorantTableTag)) { + sReport += icValidateNonCompliantMsg; + sReport += "xCLR output profile is missing colorantTableTag\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + default: + break; + } + } + } + break; + + case icSigLinkClass: + if (!GetTag(icSigAToB0Tag) || !GetTag(icSigProfileSequenceDescTag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + if (icIsSpaceCLR(m_Header.colorSpace)) { + if (!GetTag(icSigColorantTableTag)) { + sReport += icValidateNonCompliantMsg; + sReport += "Required tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + + if (icIsSpaceCLR(m_Header.pcs)) { + if (!GetTag(icSigColorantTableOutTag)) { + sReport += icValidateNonCompliantMsg; + sReport += "Required tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + break; + + case icSigColorSpaceClass: + if (!GetTag(icSigAToB0Tag) || !GetTag(icSigBToA0Tag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + + case icSigAbstractClass: + if (!GetTag(icSigAToB0Tag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + + case icSigNamedColorClass: + if (!GetTag(icSigNamedColor2Tag)) { + sReport += icValidateCriticalErrorMsg; + sReport += "Critical tag(s) missing.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + break; + + default: + sReport += icValidateCriticalErrorMsg; + sReport += "Unknown Profile Class.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + break; + } + + if (!CheckTagExclusion(sReport)) { + rv = icMaxStatus(rv, icValidateWarning); + } + + return rv; +} + +/** + ***************************************************************************** + * Name: CIccProfile::CheckFileSize() + * + * Purpose: Check if the Profile file size matches with the size mentioned + * in the header and is evenly divisible by four. + * + * Args: + * + * Return: + * true - size matches, + * false - size mismatches + ****************************************************************************** + */ +bool CIccProfile::CheckFileSize(CIccIO *pIO) const +{ + icUInt32Number FileSize; + icUInt32Number curPos = pIO->Tell(); + + if (!pIO->Seek(0, icSeekEnd)) + return false; + + FileSize = pIO->Tell(); + + if (!FileSize) + return false; + + if (!pIO->Seek(curPos, icSeekSet)) + return false; + + if (FileSize != m_Header.size) + return false; + + if ((m_Header.version>=icVersionNumberV4_2) && ((FileSize%4 != 0) || (m_Header.size%4 != 0))) + return false; + + + return true; +} + + +/** + **************************************************************************** + * Name: CIccProfile::Validate + * + * Purpose: Check the data integrity of the profile, and conformance to + * the ICC specification + * + * Args: + * sReport = String to put report into + * + * Return: + * icValidateOK if profile is valid, warning/error level otherwise + ***************************************************************************** + */ +icValidateStatus CIccProfile::Validate(std::string &sReport) const +{ + icValidateStatus rv = icValidateOK; + + //Check header + rv = icMaxStatus(rv, CheckHeader(sReport)); + + // Check for duplicate tags + if (!AreTagsUnique()) { + sReport += icValidateWarning; + sReport += " - There are duplicate tags.\r\n"; + rv =icMaxStatus(rv, icValidateWarning); + } + + // Check Required Tags which includes exclusion tests + rv = icMaxStatus(rv, CheckRequiredTags(sReport)); + + // Per Tag tests + rv = icMaxStatus(rv, CheckTagTypes(sReport)); + TagEntryList::iterator i; + for (i=m_Tags->begin(); i!=m_Tags->end(); i++) { + rv = icMaxStatus(rv, i->pTag->Validate(i->TagInfo.sig, sReport, this)); + } + + return rv; +} + +/** + **************************************************************************** + * Name: CIccProfile::GetSpaceSamples + * + * Purpose: Get the number of device channels from the color space + * of data. + * + * Return: Number of device channels. + * + ***************************************************************************** + */ +icUInt16Number CIccProfile::GetSpaceSamples() const +{ + switch(m_Header.colorSpace) { + case icSigXYZData: + case icSigLabData: + case icSigLuvData: + case icSigYCbCrData: + case icSigYxyData: + case icSigRgbData: + case icSigHsvData: + case icSigHlsData: + case icSigCmyData: + case icSig3colorData: + return 3; + + case icSigCmykData: + case icSig4colorData: + return 4; + + case icSig5colorData: + return 5; + + case icSig6colorData: + return 6; + + case icSig7colorData: + return 7; + + case icSig8colorData: + return 8; + + case icSig9colorData: + return 9; + + case icSig10colorData: + return 10; + + case icSig11colorData: + return 11; + + case icSig12colorData: + return 12; + + case icSig13colorData: + return 13; + + case icSig14colorData: + return 14; + + case icSig15colorData: + return 15; + + default: + return 0; + } + +} + +////////////////////////////////////////////////////////////////////// +// Function Definitions +////////////////////////////////////////////////////////////////////// + +/** + ***************************************************************************** + * Name: ReadIccProfile + * + * Purpose: Read an ICC profile file. + * + * Args: + * szFilename - zero terminated string with filename of ICC profile to read + * + * Return: + * Pointer to icc profile object, or NULL on failure + ****************************************************************************** + */ +CIccProfile* ReadIccProfile(const icChar *szFilename) +{ + CIccFileIO *pFileIO = new CIccFileIO; + + if (!pFileIO->Open(szFilename, "rb")) { + delete pFileIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc->Read(pFileIO)) { + delete pIcc; + delete pFileIO; + return NULL; + } + delete pFileIO; + + return pIcc; +} + + +#if defined(WIN32) || defined(WIN64) +/** +***************************************************************************** +* Name: ReadIccProfile +* +* Purpose: Read an ICC profile file. +* +* Args: +* szFilename - zero terminated string with filename of ICC profile to read +* +* Return: +* Pointer to icc profile object, or NULL on failure +****************************************************************************** +*/ +CIccProfile* ReadIccProfile(const icWChar *szFilename) +{ + CIccFileIO *pFileIO = new CIccFileIO; + + if (!pFileIO->Open(szFilename, L"rb")) { + delete pFileIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc->Read(pFileIO)) { + delete pIcc; + delete pFileIO; + return NULL; + } + delete pFileIO; + + return pIcc; +} + +#endif + +/** +***************************************************************************** +* Name: ReadIccProfile +* +* Purpose: Read an ICC profile file. +* +* Args: +* pMem = pointer to memory containing profile data +* nSize = size of memory related to profile +* +* Return: +* Pointer to icc profile object, or NULL on failure +****************************************************************************** +*/ +CIccProfile* ReadIccProfile(const icUInt8Number *pMem, icUInt32Number nSize) +{ + CIccMemIO *pMemIO = new CIccMemIO(); + + if (!pMemIO->Attach((icUInt8Number*)pMem, nSize)) { + delete pMemIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc->Read(pMemIO)) { + delete pIcc; + delete pMemIO; + return NULL; + } + delete pMemIO; + + return pIcc; +} + + +/** + ****************************************************************************** + * Name: OpenIccProfile + * + * Purpose: Open an ICC profile file. This will only read the profile header + * and tag directory. Loading of actual tags will be deferred until the + * tags are actually referenced by FindTag(). + * + * Args: + * szFilename - zero terminated string with filename of ICC profile to read + * + * Return: + * Pointer to icc profile object, or NULL on failure + ******************************************************************************* + */ +CIccProfile* OpenIccProfile(const icChar *szFilename) +{ + CIccFileIO *pFileIO = new CIccFileIO; + + if (!pFileIO->Open(szFilename, "rb")) { + delete pFileIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc->Attach(pFileIO)) { + delete pIcc; + delete pFileIO; + return NULL; + } + + return pIcc; +} + +#if defined(WIN32) || defined(WIN64) +/** +****************************************************************************** +* Name: OpenIccProfile +* +* Purpose: Open an ICC profile file. This will only read the profile header +* and tag directory. Loading of actual tags will be deferred until the +* tags are actually referenced by FindTag(). +* +* Args: +* szFilename - zero terminated string with filename of ICC profile to read +* +* Return: +* Pointer to icc profile object, or NULL on failure +******************************************************************************* +*/ +CIccProfile* OpenIccProfile(const icWChar *szFilename) +{ + CIccFileIO *pFileIO = new CIccFileIO; + + if (!pFileIO->Open(szFilename, L"rb")) { + delete pFileIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc->Attach(pFileIO)) { + delete pIcc; + delete pFileIO; + return NULL; + } + + return pIcc; +} +#endif + +/** +****************************************************************************** +* Name: OpenIccProfile +* +* Purpose: Open an ICC profile file. This will only read the profile header +* and tag directory. Loading of actual tags will be deferred until the +* tags are actually referenced by FindTag(). +* +* Args: +* pMem = pointer to memory containing profile data +* nSize = size of memory related to profile +* +* Return: +* Pointer to icc profile object, or NULL on failure +******************************************************************************* +*/ +CIccProfile* OpenIccProfile(const icUInt8Number *pMem, icUInt32Number nSize) +{ + CIccMemIO *pMemIO = new CIccMemIO; + + if (!pMemIO->Attach((icUInt8Number*)pMem, nSize)) { + delete pMemIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc->Attach(pMemIO)) { + delete pIcc; + delete pMemIO; + return NULL; + } + + return pIcc; +} + +/** +****************************************************************************** +* Name: ValidateIccProfile +* +* Purpose: Open an ICC profile file. This will only read the profile header +* and tag directory. Loading of actual tags will be deferred until the +* tags are actually referenced by FindTag(). +* +* Args: +* pIO - Handle to IO access object (Not ValidateIccProfile assumes ownership of this object) +* sReport - std::string to put report into +* nStatus - return status value +* +* Return: +* Pointer to icc profile object, or NULL on failure +******************************************************************************* +*/ +CIccProfile* ValidateIccProfile(CIccIO *pIO, std::string &sReport, icValidateStatus &nStatus) +{ + if (!pIO) { + sReport = icValidateCriticalErrorMsg; + sReport += " - "; + sReport += "- Invalid I/O Handle\r\n"; + delete pIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc) { + delete pIO; + return NULL; + } + + nStatus = pIcc->ReadValidate(pIO, sReport); + + if (nStatus>=icValidateCriticalError) { + delete pIcc; + delete pIO; + return NULL; + } + + delete pIO; + + nStatus = pIcc->Validate(sReport); + + return pIcc; +} + +#if defined(WIN32) || defined(WIN64) +/** +****************************************************************************** +* Name: ValidateIccProfile +* +* Purpose: Open an ICC profile file. This will only read the profile header +* and tag directory. Loading of actual tags will be deferred until the +* tags are actually referenced by FindTag(). +* +* Args: +* szFilename - zero terminated string with filename of ICC profile to read +* sReport - std::string to put report into +* nStatus - return status value +* +* Return: +* Pointer to icc profile object, or NULL on failure +******************************************************************************* +*/ +CIccProfile* ValidateIccProfile(const icWChar *szFilename, std::string &sReport, icValidateStatus &nStatus) +{ + CIccFileIO *pFileIO = new CIccFileIO; + + if (!pFileIO->Open(szFilename, L"rb")) { + delete pFileIO; + return NULL; + } + + return ValidateIccProfile(pFileIO, sReport, nStatus); +} +#endif + + +/** +****************************************************************************** +* Name: ValidateIccProfile +* +* Purpose: Open an ICC profile file. This will only read the profile header +* and tag directory. Loading of actual tags will be deferred until the +* tags are actually referenced by FindTag(). +* +* Args: +* szFilename - zero terminated string with filename of ICC profile to read +* sReport - std::string to put report into +* nStatus - return status value +* +* Return: +* Pointer to icc profile object, or NULL on failure +******************************************************************************* +*/ +CIccProfile* ValidateIccProfile(const icChar *szFilename, std::string &sReport, icValidateStatus &nStatus) +{ + CIccFileIO *pFileIO = new CIccFileIO; + + if (!pFileIO->Open(szFilename, "rb")) { + sReport = icValidateCriticalErrorMsg; + sReport += " - "; + sReport += szFilename; + sReport += "- Invalid Filename\r\n"; + delete pFileIO; + return NULL; + } + + CIccProfile *pIcc = new CIccProfile; + + if (!pIcc) { + delete pFileIO; + return NULL; + } + + nStatus = pIcc->ReadValidate(pFileIO, sReport); + + if (nStatus>=icValidateCriticalError) { + delete pIcc; + delete pFileIO; + return NULL; + } + + delete pFileIO; + + nStatus = pIcc->Validate(sReport); + + return pIcc; +} + + + +/** + ****************************************************************************** + * Name: SaveIccProfile + * + * Purpose: Save an ICC profile file. + * + * Args: + * szFilename - zero terminated string with filename of ICC profile to create + * + * Return: + * true = success, false = failure + ******************************************************************************* + */ +bool SaveIccProfile(const icChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId) +{ + CIccFileIO FileIO; + + if (!pIcc) + return false; + + if (!FileIO.Open(szFilename, "w+b")) { + return false; + } + + if (!pIcc->Write(&FileIO, nWriteId)) { + return false; + } + + return true; +} + +#if defined(WIN32) || defined(WIN64) +/** +****************************************************************************** +* Name: SaveIccProfile +* +* Purpose: Save an ICC profile file. +* +* Args: +* szFilename - zero terminated string with filename of ICC profile to create +* +* Return: +* true = success, false = failure +******************************************************************************* +*/ +bool SaveIccProfile(const icWChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId) +{ + CIccFileIO FileIO; + + if (!pIcc) + return false; + + if (!FileIO.Open(szFilename, L"w+b")) { + return false; + } + + if (!pIcc->Write(&FileIO, nWriteId)) { + return false; + } + + return true; +} +#endif + +/** + **************************************************************************** + * Name: CalcProfileID + * + * Purpose: Calculate the Profile ID using MD5 Fingerprinting method. + * + * Args: + * pIO = The CIccIO object, + * pProfileID = array where the profileID will be stored + * + **************************************************************************** + */ +void CalcProfileID(CIccIO *pIO, icProfileID *pProfileID) +{ + icUInt32Number len, num, nBlock, pos; + MD5_CTX context; + icUInt8Number buffer[1024]; + + //remember where we are + pos = pIO->Tell(); + + //Get length and set up to read entire file + len = pIO->GetLength(); + pIO->Seek(0, icSeekSet); + + //read file updating checksum as we go + icMD5Init(&context); + nBlock = 0; + while(len) { + num = pIO->Read8(&buffer[0],1024); + if (!nBlock) { // Zero out 3 header contents in Profile ID calculation + memset(buffer+44, 0, 4); //Profile flags + memset(buffer+64, 0, 4); //Rendering Intent + memset(buffer+84, 0, 16); //Profile Id + } + icMD5Update(&context,buffer,num); + nBlock++; + len -=num; + } + icMD5Final(&pProfileID->ID8[0],&context); + + //go back where we were + pIO->Seek(pos, icSeekSet); +} + +/** + **************************************************************************** + * Name: CalcProfileID + * + * Purpose: Calculate the Profile ID using MD5 Fingerprinting method. + * + * Args: + * szFileName = name of the file whose profile ID has to be calculated, + * pProfileID = array where the profileID will be stored + ***************************************************************************** + */ +bool CalcProfileID(const icChar *szFilename, icProfileID *pProfileID) +{ + CIccFileIO FileIO; + + if (!FileIO.Open(szFilename, "rb")) { + memset(pProfileID, 0, sizeof(icProfileID)); + return false; + } + + CalcProfileID(&FileIO, pProfileID); + return true; +} + +#if defined(WIN32) || defined(WIN64) +/** +**************************************************************************** +* Name: CalcProfileID +* +* Purpose: Calculate the Profile ID using MD5 Fingerprinting method. +* +* Args: +* szFileName = name of the file whose profile ID has to be calculated, +* pProfileID = array where the profileID will be stored +***************************************************************************** +*/ +bool CalcProfileID(const icWChar *szFilename, icProfileID *pProfileID) +{ + CIccFileIO FileIO; + + if (!FileIO.Open(szFilename, L"rb")) { + memset(pProfileID, 0, sizeof(icProfileID)); + return false; + } + + CalcProfileID(&FileIO, pProfileID); + return true; +} +#endif + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccProfile.h b/library/src/main/cpp/icc/IccProfile.h new file mode 100644 index 00000000..41d52e81 --- /dev/null +++ b/library/src/main/cpp/icc/IccProfile.h @@ -0,0 +1,225 @@ +/** @file + File: IccProfile.h + + Contains: Header for implementation of the CIccProfile class. + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCPROFILE_H) +#define _ICCPROFILE_H + +#include "IccDefs.h" +#include +#include + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +class ICCPROFLIB_API CIccTag; +class ICCPROFLIB_API CIccIO; +class ICCPROFLIB_API CIccMemIO; + +/** + ************************************************************************** + * Type: Structure + * + * Purpose: + * This structure stores all the information of an individual tag + * including the header information (tag signature, offset and size). + ************************************************************************** + */ +struct IccTagEntry +{ + + icTag TagInfo; + CIccTag* pTag; +}; + +/** + ************************************************************************** + * Type: List + * + * Purpose: List of all the tag entries. + * + ************************************************************************** + */ +typedef std::list TagEntryList; + +/** + ************************************************************************** + * Type: Structure + * + * Purpose: Contains pointer to a tag. + ************************************************************************** + */ +typedef struct {CIccTag *ptr;} IccTagPtr; + +/** + ************************************************************************** + * Type: List + * + * Purpose: List of pointers to the tags. + * + ************************************************************************** + */ +typedef std::list TagPtrList; + +typedef enum { + icVersionBasedID, + icAlwaysWriteID, + icNeverWriteID, +}icProfileIDSaveMethod; + +/** + ************************************************************************** + * Type: Class + * + * Purpose: + * This is the base class for an ICC profile. All the operations + * on a profile is done using this object. + ************************************************************************** + */ +class ICCPROFLIB_API CIccProfile +{ +public: + CIccProfile(); + CIccProfile(const CIccProfile &Profile); + CIccProfile &operator=(const CIccProfile &Profile); + virtual ~CIccProfile(); + + icHeader m_Header; + + TagEntryList *m_Tags; + + CIccTag* FindTag(icSignature sig); + bool AttachTag(icSignature sig, CIccTag *pTag); + bool DeleteTag(icSignature sig); + CIccMemIO* GetTagIO(icSignature sig); //caller should delete returned result + bool ReadTags(CIccProfile* pProfile); // will read in all the tags using the IO of the passed profile + + bool Attach(CIccIO *pIO); + bool Detach(); + bool Read(CIccIO *pIO); + icValidateStatus ReadValidate(CIccIO *pIO, std::string &sReport); + bool Write(CIccIO *pIO, icProfileIDSaveMethod nWriteId=icVersionBasedID); + + void InitHeader(); + icValidateStatus Validate(std::string &sReport) const; + + icUInt16Number GetSpaceSamples() const; + + bool AreTagsUnique() const; + bool IsTagPresent(icSignature sig) const { return (GetTag(sig)!=NULL); } + +protected: + + void Cleanup(); + IccTagEntry* GetTag(icSignature sig) const; + IccTagEntry* GetTag(CIccTag *pTag) const; + bool ReadBasic(CIccIO *pIO); + bool LoadTag(IccTagEntry *pTagEntry, CIccIO *pIO); + bool DetachTag(CIccTag *pTag); + + // Profile Validation functions + icValidateStatus CheckRequiredTags(std::string &sReport) const; + bool CheckTagExclusion(std::string &sReport) const; + icValidateStatus CheckHeader(std::string &sReport) const; + icValidateStatus CheckTagTypes(std::string &sReport) const; + bool IsTypeValid(icTagSignature tagSig, icTagTypeSignature typeSig) const; + bool CheckFileSize(CIccIO *pIO) const; + + CIccIO *m_pAttachIO; + + TagPtrList *m_TagVals; +}; + +CIccProfile ICCPROFLIB_API *ReadIccProfile(const icChar *szFilename); +CIccProfile ICCPROFLIB_API *ReadIccProfile(const icUInt8Number *pMem, icUInt32Number nSize); +CIccProfile ICCPROFLIB_API *OpenIccProfile(const icChar *szFilename); +CIccProfile ICCPROFLIB_API *OpenIccProfile(const icUInt8Number *pMem, icUInt32Number nSize); //pMem must be available for entire life of returned CIccProfile Object + +CIccProfile ICCPROFLIB_API *ValidateIccProfile(CIccIO *pIO, std::string &sReport, icValidateStatus &nStatus); +CIccProfile ICCPROFLIB_API *ValidateIccProfile(const icChar *szFilename, std::string &sReport, icValidateStatus &nStatus); + +bool ICCPROFLIB_API SaveIccProfile(const icChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId=icVersionBasedID); + +void ICCPROFLIB_API CalcProfileID(CIccIO *pIO, icProfileID *profileID); +bool ICCPROFLIB_API CalcProfileID(const icChar *szFilename, icProfileID *profileID); + +#if defined(WIN32) || defined(WIN64) +CIccProfile ICCPROFLIB_API *ReadIccProfile(const icWChar *szFilename); +CIccProfile ICCPROFLIB_API *OpenIccProfile(const icWChar *szFilename); +CIccProfile ICCPROFLIB_API *ValidateIccProfile(const icWChar *szFilename, std::string &sReport, icValidateStatus &nStatus); +bool ICCPROFLIB_API SaveIccProfile(const icWChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId=icVersionBasedID); +bool ICCPROFLIB_API CalcProfileID(const icWChar *szFilename, icProfileID *profileID); +#endif + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif // !defined(_ICCPROFILE_H) diff --git a/library/src/main/cpp/icc/IccTag.h b/library/src/main/cpp/icc/IccTag.h new file mode 100644 index 00000000..0d003032 --- /dev/null +++ b/library/src/main/cpp/icc/IccTag.h @@ -0,0 +1,94 @@ +/** @file + File: IccTag.h + + Contains: Header for implementation of CIccTag class and + creation factories + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2005-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Separated tags to separate files and created this single header +// file to declare them all +// +// -Oct 30, 2005 +// A CIccTagCreator singleton class has been added to provide general +// support for dynamically creating tag classes using a tag signature. +// Prototype and private tag type support can be added to the system +// by pushing additional IIccTagFactory based objects to the +// singleton CIccTagCreator object. +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCTAG_H +#define _ICCTAG_H + +#include "IccDefs.h" +#include "IccIO.h" +#include +#include + +#include "IccTagBasic.h" +#include "IccTagLut.h" +#include "IccTagMPE.h" +#include "IccTagProfSeqId.h" +#include "IccTagDict.h" + +#endif //_ICCTAG_H diff --git a/library/src/main/cpp/icc/IccTagBasic.cpp b/library/src/main/cpp/icc/IccTagBasic.cpp new file mode 100644 index 00000000..f930c869 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagBasic.cpp @@ -0,0 +1,6959 @@ +/** @file + File: IccTagBasic.cpp + + Contains: Implementation of the CIccTag class and basic inherited classes + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) + #pragma warning( disable: 4786) //disable warning in + #include +#endif +#include +#include +#include +#include +#include "IccTag.h" +#include "IccUtil.h" +#include "IccProfile.h" +#include "IccTagFactory.h" +#include "IccConvertUTF.h" + +#ifndef __min +#include +using std::min; +#define __min min +#endif + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + + +/** + **************************************************************************** + * Name: CIccTag::CIccTag + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTag::CIccTag() +{ + m_nReserved = 0; +} + +/** + **************************************************************************** + * Name: CIccTag::CIccTag + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTag::~CIccTag() +{ + +} + +/** + **************************************************************************** + * Name: CIccTag::Create + * + * Purpose: This is a static tag creator based upon tag signature type + * + * Args: + * sig = tag type signature + * + * Return: Pointer to Allocated tag + ***************************************************************************** + */ +CIccTag* CIccTag::Create(icTagTypeSignature sig) +{ + return CIccTagCreator::CreateTag(sig); +} + + +/** + ****************************************************************************** + * Name: CIccTag::Validate + * + * Purpose: Check tag data validity. In base class we only look at the + * tag's reserved data value + * + * Args: + * sig = signature of tag being validated, + * sReport = String to add report information to + * + * Return: + * icValidateStatusOK if valid, or other error status. + ****************************************************************************** + */ +icValidateStatus CIccTag::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = icValidateOK; + + if (m_nReserved != 0) { + CIccInfo Info; + sReport += icValidateNonCompliantMsg; + sReport += Info.GetSigName(sig); + sReport += " - Reserved Value must be zero.\r\n"; + + rv = icValidateNonCompliant; + } + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccTagUnknown::CIccTagUnknown + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagUnknown::CIccTagUnknown() +{ + m_nType = icSigUnknownType; + m_pData = NULL; +} + +/** + **************************************************************************** + * Name: CIccTagUnknown::CIccTagUnknown + * + * Purpose: Copy Constructor + * + * Args: + * ITU = The CIccTagUnknown object to be copied + ***************************************************************************** + */ +CIccTagUnknown::CIccTagUnknown(const CIccTagUnknown &ITU) +{ + m_nSize = ITU.m_nSize; + m_nType = ITU.m_nType; + + m_pData = new icUInt8Number[m_nSize]; + memcpy(m_pData, ITU.m_pData, sizeof(icUInt8Number)*m_nSize); +} + +/** + **************************************************************************** + * Name: CIccTagUnknown::operator= + * + * Purpose: Copy Operator + * + * Args: + * UnknownTag = The CIccTagUnknown object to be copied + ***************************************************************************** + */ +CIccTagUnknown &CIccTagUnknown::operator=(const CIccTagUnknown &UnknownTag) +{ + if (&UnknownTag == this) + return *this; + + m_nSize = UnknownTag.m_nSize; + m_nType = UnknownTag.m_nType; + + if (m_pData) + delete [] m_pData; + m_pData = new icUInt8Number[m_nSize]; + memcpy(m_pData, UnknownTag.m_pData, sizeof(icUInt8Number)*m_nSize); + + return *this; +} + +/** + **************************************************************************** + * Name: CIccTagUnknown::~CIccTagUnknown + * + * Purpose: Destructor + ***************************************************************************** + */ +CIccTagUnknown::~CIccTagUnknown() +{ + if (m_pData) + delete [] m_pData; +} + + +/** + **************************************************************************** + * Name: CIccTagUnknown::Read + * + * Purpose: Read in an unknown tag type into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagUnknown::Read(icUInt32Number size, CIccIO *pIO) +{ + if (m_pData) { + delete [] m_pData; + m_pData = NULL; + } + + if (sizeRead32(&m_nType)) + return false; + + m_nSize = size - sizeof(icTagTypeSignature); + + if (m_nSize) { + + m_pData = new icUInt8Number[m_nSize]; + + if (pIO->Read8(m_pData, m_nSize) != (icInt32Number)m_nSize) { + return false; + } + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagUnknown::Write + * + * Purpose: Write an unknown tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagUnknown::Write(CIccIO *pIO) +{ + if (!pIO) + return false; + + if (!pIO->Write32(&m_nType)) + return false; + + if (m_nSize && m_pData) { + if (pIO->Write8(m_pData, m_nSize) != (icInt32Number)m_nSize) + return false; + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagUnknown::Describe + * + * Purpose: Dump data associated with unknown tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagUnknown::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sDescription = "Unknown Tag Type of "; + sprintf(buf, "%u Bytes.", m_nSize-4); + sDescription += buf; + + sDescription += "\r\n\r\nData Follows:\r\n"; + + icMemDump(sDescription, m_pData+4, m_nSize-4); +} + +/** + **************************************************************************** + * Name: CIccTagText::CIccTagText + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagText::CIccTagText() +{ + m_szText = (icChar*)malloc(1); + m_szText[0] = '\0'; + m_nBufSize = 1; +} + +/** + **************************************************************************** + * Name: CIccTagText::CIccTagText + * + * Purpose: Copy Constructor + * + * Args: + * ITT = The CIccTagText object to be copied + ***************************************************************************** + */ +CIccTagText::CIccTagText(const CIccTagText &ITT) +{ + m_szText = (icChar*)malloc(1); + m_szText[0] = '\0'; + m_nBufSize = 1; + SetText(ITT.m_szText); +} + +/** + **************************************************************************** + * Name: CIccTagText::operator= + * + * Purpose: Copy Operator + * + * Args: + * TextTag = The CIccTagText object to be copied + ***************************************************************************** + */ +CIccTagText &CIccTagText::operator=(const CIccTagText &TextTag) +{ + if (&TextTag == this) + return *this; + + m_szText = (icChar*)malloc(1); + m_szText[0] = '\0'; + m_nBufSize = 1; + SetText(TextTag.m_szText); + + return *this; +} + +/** + **************************************************************************** + * Name: CIccTagText::~CIccTagText + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagText::~CIccTagText() +{ + free(m_szText); +} + +/** + **************************************************************************** + * Name: CIccTagText::Read + * + * Purpose: Read in a text type tag into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagText::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeRead32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number nSize = size - sizeof(icTagTypeSignature) - sizeof(icUInt32Number); + + icChar *pBuf = GetBuffer(nSize); + + if (nSize) { + if (pIO->Read8(pBuf, nSize) != (icInt32Number)nSize) { + return false; + } + } + + Release(); + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagText::Write + * + * Purpose: Write a text type tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagText::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!m_szText) + return false; + + icUInt32Number nSize = (icUInt32Number)strlen(m_szText)+1; + + if (pIO->Write8(m_szText, nSize) != (icInt32Number)nSize) + return false; + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagText::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagText::Describe(std::string &sDescription) +{ + sDescription += "\""; + if (m_szText && *m_szText) + sDescription += m_szText; + + sDescription += "\"\r\n"; +} + + +/** + **************************************************************************** + * Name: CIccTagText::SetText + * + * Purpose: Allows text data associated with the tag to be set. + * + * Args: + * szText - zero terminated string to put in tag + ***************************************************************************** + */ +void CIccTagText::SetText(const icChar *szText) +{ + if (!szText) + SetText(""); + + icUInt32Number len=(icUInt32Number)strlen(szText) + 1; + icChar *szBuf = GetBuffer(len); + + strcpy(szBuf, szText); + Release(); +} + +/** + **************************************************************************** + * Name: *CIccTagText::operator= + * + * Purpose: Define assignment operator to associate text with tag. + * + * Args: + * szText - zero terminated string to put in the tag + * + * Return: A pointer to the string assigned to the tag. + ***************************************************************************** + */ +const icChar *CIccTagText::operator=(const icChar *szText) +{ + SetText(szText); + return m_szText; +} + +/** + ****************************************************************************** + * Name: CIccTagText::GetBuffer + * + * Purpose: This function allocates room and returns pointer to data buffer to + * put string into + * + * Args: + * nSize = Requested size of data buffer. + * + * Return: The character buffer array + ******************************************************************************* + */ +icChar *CIccTagText::GetBuffer(icUInt32Number nSize) +{ + if (m_nBufSize < nSize) { + m_szText = (icChar*)realloc(m_szText, nSize+1); + + m_szText[nSize] = '\0'; + + m_nBufSize = nSize; + } + + return m_szText; +} + +/** + **************************************************************************** + * Name: CIccTagText::Release + * + * Purpose: This will resize the buffer to fit the zero terminated string in + * the buffer. + ***************************************************************************** + */ +void CIccTagText::Release() +{ + icUInt32Number nSize = (icUInt32Number)strlen(m_szText)+1; + + if (nSize < m_nBufSize-1) { + m_szText=(icChar*)realloc(m_szText, nSize+1); + m_nBufSize = nSize+1; + } +} + + +/** +****************************************************************************** +* Name: CIccTagText::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagText::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (m_nBufSize) { + switch(sig) { + case icSigCopyrightTag: + break; + case icSigCharTargetTag: + if (m_nBufSize<7) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Tag must have at least seven text characters.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + break; + default: + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Unknown Tag.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + int i; + for (i=0; m_szText[i] && i<(int)m_nBufSize; i++) { + if (m_szText[i]&0x80) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Text do not contain 7bit data.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + } + } + else { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Empty Tag.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + + + return rv; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::CIccTagTextDescription + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagTextDescription::CIccTagTextDescription() +{ + m_szText = (icChar*)malloc(1); + m_szText[0] = '\0'; + m_nASCIISize = 1; + + m_uzUnicodeText = (icUInt16Number*)malloc(sizeof(icUInt16Number)); + m_uzUnicodeText[0] = 0; + m_nUnicodeSize = 1; + m_nUnicodeLanguageCode = 0; + + m_nScriptSize = 0; + m_nScriptCode = 0; + memset(m_szScriptText, 0, sizeof(m_szScriptText)); + + m_bInvalidScript = false; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::CIccTagTextDescription + * + * Purpose: Copy Constructor + * + * Args: + * ITTD = The CIccTagTextDescription object to be copied + ***************************************************************************** + */ +CIccTagTextDescription::CIccTagTextDescription(const CIccTagTextDescription &ITTD) +{ + m_nASCIISize = ITTD.m_nASCIISize; + m_nUnicodeSize = ITTD.m_nUnicodeSize; + m_nUnicodeLanguageCode = ITTD.m_nUnicodeLanguageCode; + m_nScriptSize = ITTD.m_nScriptSize; + m_nScriptCode = ITTD.m_nScriptCode; + + if (m_nASCIISize) { + m_szText = (icChar*)malloc(m_nASCIISize * sizeof(icChar)); + memcpy(m_szText, ITTD.m_szText, m_nASCIISize*sizeof(icChar)); + } + else { + m_nASCIISize = 1; + m_szText = (icChar*)calloc(m_nASCIISize, sizeof(icChar)); + m_szText[0] = '\0'; + } + + if (m_nUnicodeSize) { + m_uzUnicodeText = (icUInt16Number*)malloc((m_nUnicodeSize) * sizeof(icUInt16Number)); + memcpy(m_uzUnicodeText, ITTD.m_uzUnicodeText, m_nUnicodeSize*sizeof(icUInt16Number)); + } + else { + m_nUnicodeSize = 1; + m_uzUnicodeText = (icUInt16Number*)calloc(m_nUnicodeSize, sizeof(icUInt16Number)); + m_uzUnicodeText[0] = 0; + } + + memcpy(m_szScriptText, ITTD.m_szScriptText, sizeof(m_szScriptText)); + + m_bInvalidScript = ITTD.m_bInvalidScript; +} + + +/** + **************************************************************************** + * Name: CIccTagTextDescription::operator= + * + * Purpose: Copy Operator + * + * Args: + * TextDescTag = The CIccTagTextDescription object to be copied + ***************************************************************************** + */ +CIccTagTextDescription &CIccTagTextDescription::operator=(const CIccTagTextDescription& TextDescTag) +{ + if (&TextDescTag == this) + return *this; + + m_nASCIISize = TextDescTag.m_nASCIISize; + m_nUnicodeSize = TextDescTag.m_nUnicodeSize; + m_nUnicodeLanguageCode = TextDescTag.m_nUnicodeLanguageCode; + m_nScriptSize = TextDescTag.m_nScriptSize; + m_nScriptCode = TextDescTag.m_nScriptCode; + + if (m_szText) + free(m_szText); + if (m_nASCIISize) { + m_szText = (icChar*)calloc(m_nASCIISize, sizeof(icChar)); + memcpy(m_szText, TextDescTag.m_szText, m_nASCIISize*sizeof(icChar)); + } + else { + m_nASCIISize = 1; + m_szText = (icChar*)calloc(m_nASCIISize, sizeof(icChar)); + m_szText[0] = '\0'; + } + + if (m_uzUnicodeText) + free(m_uzUnicodeText); + if (m_nUnicodeSize) { + m_uzUnicodeText = (icUInt16Number*)calloc(m_nUnicodeSize, sizeof(icUInt16Number)); + memcpy(m_uzUnicodeText, TextDescTag.m_uzUnicodeText, m_nUnicodeSize*sizeof(icUInt16Number)); + } + else { + m_nUnicodeSize = 1; + m_uzUnicodeText = (icUInt16Number*)calloc(m_nUnicodeSize, sizeof(icUInt16Number)); + m_uzUnicodeText[0] = 0; + } + + memcpy(m_szScriptText, TextDescTag.m_szScriptText, sizeof(m_szScriptText)); + + m_bInvalidScript = TextDescTag.m_bInvalidScript; + + return *this; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::~CIccTagTextDescription + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagTextDescription::~CIccTagTextDescription() +{ + free(m_szText); + free(m_uzUnicodeText); +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagTextDescription::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nEnd; + + nEnd = pIO->Tell() + size; + + if (size<3*sizeof(icUInt32Number) || !pIO) { + m_szText[0] = '\0'; + return false; + } + + icUInt32Number nSize; + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read32(&nSize)) + return false; + + if (3*sizeof(icUInt32Number) + nSize > size) + return false; + + icChar *pBuf = GetBuffer(nSize); + + if (nSize) { + if (pIO->Read8(pBuf, nSize) != (icInt32Number)nSize) { + return false; + } + } + else + m_szText[0] = '\0'; + + Release(); + + if (pIO->Tell() + 2 * sizeof(icUInt32Number) > nEnd) + return false; + + if (!pIO->Read32(&m_nUnicodeLanguageCode) || + !pIO->Read32(&nSize)) + return false; + + icUInt16Number *pBuf16 = GetUnicodeBuffer(nSize); + + if (nSize) { + if (pIO->Read16(pBuf16, nSize) != (icInt32Number)nSize) { + return false; + } + } + else + pBuf16[0] = 0; + + ReleaseUnicode(); + + if (pIO->Tell()+3 > (icInt32Number)nEnd) + return false; + + if (!pIO->Read16(&m_nScriptCode) || + !pIO->Read8(&m_nScriptSize)) + return false; + + if (pIO->Tell() + m_nScriptSize> (icInt32Number)nEnd || + m_nScriptSize > sizeof(m_szScriptText)) + return false; + + int nScriptLen = pIO->Read8(m_szScriptText, 67); + + if (!nScriptLen) + return false; + + if (nScriptLen<67) { + memset(&m_szScriptText[0], 0, 67-nScriptLen); + m_bInvalidScript = true; + } + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagTextDescription::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt32Number zero = 0; + + if (!pIO) + return false; + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write32(&m_nASCIISize)) + return false; + + if (m_nASCIISize) { + if (pIO->Write8(m_szText, m_nASCIISize) != (icInt32Number)m_nASCIISize) + return false; + } + + if (!pIO->Write32(&m_nUnicodeLanguageCode)) + return false; + + if (m_nUnicodeSize > 1) { + if (!pIO->Write32(&m_nUnicodeSize) || + pIO->Write16(m_uzUnicodeText, m_nUnicodeSize) != (icInt32Number)m_nUnicodeSize) + return false; + } + else { + if (!pIO->Write32(&zero)) + return false; + } + + if (!pIO->Write16(&m_nScriptCode) || + !pIO->Write8(&m_nScriptSize) || + pIO->Write8(m_szScriptText, 67)!= 67) + return false; + + m_bInvalidScript = false; + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagTextDescription::Describe(std::string &sDescription) +{ + sDescription += "\""; + if (m_szText && *m_szText) + sDescription += m_szText; + + sDescription += "\"\r\n"; +} + + +/** + **************************************************************************** + * Name: CIccTagTextDescription::SetText + * + * Purpose: Allows text data associated with the tag to be set. + * + * Args: + * szText - zero terminated string to put in tag + ***************************************************************************** + */ +void CIccTagTextDescription::SetText(const icChar *szText) +{ + m_bInvalidScript = false; + + if (!szText) + SetText(""); + + icUInt32Number len=(icUInt32Number)strlen(szText) + 1; + icChar *szBuf = GetBuffer(len); + + strcpy(szBuf, szText); + Release(); +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::operator= + * + * Purpose: Define assignment operator to associate text with tag. + * + * Args: + * szText - zero terminated string to put in the tag + * + * Return: A pointer to the string assigned to the tag. + ***************************************************************************** + */ +const icChar *CIccTagTextDescription::operator=(const icChar *szText) +{ + SetText(szText); + return m_szText; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::GetBuffer + * + * Purpose: This function allocates room and returns pointer to data buffer to + * put string into + * + * Args: + * nSize = Requested size of data buffer. + * + * Return: + ***************************************************************************** + */ +icChar *CIccTagTextDescription::GetBuffer(icUInt32Number nSize) +{ + if (m_nASCIISize < nSize) { + m_szText = (icChar*)realloc(m_szText, nSize+1); + + m_szText[nSize] = '\0'; + + m_nASCIISize = nSize; + } + + return m_szText; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::Release + * + * Purpose: This will resize the buffer to fit the zero terminated string in + * the buffer. + ***************************************************************************** + */ +void CIccTagTextDescription::Release() +{ + icUInt32Number nSize = (icUInt32Number)strlen(m_szText); + + if (nSize < m_nASCIISize-1) { + m_szText=(icChar*)realloc(m_szText, nSize+1); + m_nASCIISize = nSize+1; + } +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::GetUnicodeBuffer + * + * Purpose: This function allocates room and returns pointer to data buffer to + * put string into + * + * Args: + * nSize = Requested size of data buffer. + * + * Return: + ***************************************************************************** + */ +icUInt16Number *CIccTagTextDescription::GetUnicodeBuffer(icUInt32Number nSize) +{ + if (m_nUnicodeSize < nSize) { + m_uzUnicodeText = (icUInt16Number*)realloc(m_uzUnicodeText, (nSize+1)*sizeof(icUInt16Number)); + + m_uzUnicodeText[nSize] = 0; + + m_nUnicodeSize = nSize; + } + + return m_uzUnicodeText; +} + +/** + **************************************************************************** + * Name: CIccTagTextDescription::ReleaseUnicode + * + * Purpose: This will resize the buffer to fit the zero terminated string in + * the buffer. + ***************************************************************************** + */ +void CIccTagTextDescription::ReleaseUnicode() +{ + int i; + for (i=0; m_uzUnicodeText[i]; i++); + + icUInt32Number nSize = i+1; + + if (nSize < m_nUnicodeSize-1) { + m_uzUnicodeText=(icUInt16Number*)realloc(m_uzUnicodeText, (nSize+1)*sizeof(icUInt16Number)); + m_nUnicodeSize = nSize+1; + } +} + + +/** +****************************************************************************** +* Name: CIccTagTextDescription::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagTextDescription::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (m_nScriptSize>67) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - ScriptCode count must not be greater than 67.\r\n"; + + rv =icMaxStatus(rv, icValidateNonCompliant); + } + + if (m_bInvalidScript) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - ScriptCode must contain 67 bytes.\r\n"; + + rv =icMaxStatus(rv, icValidateNonCompliant); + } + + return rv; +} + +/** + **************************************************************************** + * Name: CIccTagSignature::CIccTagSignature + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagSignature::CIccTagSignature() +{ + m_nSig = 0x3f3f3f3f; //'????'; +} + + + +/** + **************************************************************************** + * Name: CIccTagSignature::CIccTagSignature + * + * Purpose: Copy Constructor + * + * Args: + * ITS = The CIccTagSignature object to be copied + ***************************************************************************** + */ +CIccTagSignature::CIccTagSignature(const CIccTagSignature &ITS) +{ + m_nSig = ITS.m_nSig; +} + + + +/** + **************************************************************************** + * Name: CIccTagSignature::operator= + * + * Purpose: Copy Operator + * + * Args: + * SignatureTag = The CIccTagSignature object to be copied + ***************************************************************************** + */ +CIccTagSignature &CIccTagSignature::operator=(const CIccTagSignature &SignatureTag) +{ + if (&SignatureTag == this) + return *this; + + m_nSig = SignatureTag.m_nSig; + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagSignature::~CIccTagSignature + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagSignature::~CIccTagSignature() +{ +} + +/** + **************************************************************************** + * Name: CIccTagSignature::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagSignature::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + 2*sizeof(icUInt32Number) > size) + return false; + + if (!pIO) { + m_nSig = 0x3f3f3f3f; //'????'; + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read32(&m_nSig)) + return false; + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagSignature::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagSignature::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write32(&m_nSig)) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagSignature::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagSignature::Describe(std::string &sDescription) +{ + CIccInfo Fmt; + + sDescription += Fmt.GetSigName(m_nSig); + sDescription += "\r\n"; +} + + +/** +****************************************************************************** +* Name: CIccTagSignature::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagSignature::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + char buf[128]; + + if (sig==icSigTechnologyTag) { + switch(m_nSig) { + case icSigFilmScanner: + case icSigDigitalCamera: + case icSigReflectiveScanner: + case icSigInkJetPrinter: + case icSigThermalWaxPrinter: + case icSigElectrophotographicPrinter: + case icSigElectrostaticPrinter: + case icSigDyeSublimationPrinter: + case icSigPhotographicPaperPrinter: + case icSigFilmWriter: + case icSigVideoMonitor: + case icSigVideoCamera: + case icSigProjectionTelevision: + case icSigCRTDisplay: + case icSigPMDisplay: + case icSigAMDisplay: + case icSigPhotoCD: + case icSigPhotoImageSetter: + case icSigGravure: + case icSigOffsetLithography: + case icSigSilkscreen: + case icSigFlexography: + case icSigMotionPictureFilmScanner: + case icSigMotionPictureFilmRecorder: + case icSigDigitalMotionPictureCamera: + case icSigDigitalCinemaProjector: + break; + + default: + { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sprintf(buf, " - %s: Unknown Technology.\r\n", Info.GetSigName(m_nSig)); + sReport += buf; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + } + else if (sig==icSigPerceptualRenderingIntentGamutTag || + sig==icSigSaturationRenderingIntentGamutTag) { + switch(m_nSig) { + case icSigPerceptualReferenceMediumGamut: + break; + + default: + { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sprintf(buf, " - %s: Unknown Reference Medium Gamut.\r\n", Info.GetSigName(m_nSig)); + sReport += buf; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + } + else if (sig==icSigColorimetricIntentImageStateTag) { + switch(m_nSig) { + case icSigSceneColorimetryEstimates: + case icSigSceneAppearanceEstimates: + case icSigFocalPlaneColorimetryEstimates: + case icSigReflectionHardcopyOriginalColorimetry: + case icSigReflectionPrintOutputColorimetry: + break; + + default: + { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sprintf(buf, " - %s: Unknown Colorimetric Intent Image State.\r\n", Info.GetSigName(m_nSig)); + sReport += buf; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + } + + + return rv; +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::CIccTagNamedColor2 + * + * Purpose: Constructor + * + * Args: + * nSize = number of named color entries, + * nDeviceCoords = number of device channels + ***************************************************************************** + */ +CIccTagNamedColor2::CIccTagNamedColor2(int nSize/*=1*/, int nDeviceCoords/*=0*/) +{ + m_nSize = nSize; + m_nVendorFlags = 0; + m_nDeviceCoords = nDeviceCoords; + if (m_nSize <1) + m_nSize = 1; + if (m_nDeviceCoords<0) + m_nDeviceCoords = nDeviceCoords = 0; + + if (nDeviceCoords>0) + nDeviceCoords--; + + m_szPrefix[0] = '\0'; + m_szSufix[0] = '\0'; + m_csPCS = icSigUnknownData; + m_csDevice = icSigUnknownData; + + m_nColorEntrySize = 32/*rootName*/ + (3/*PCS*/ + 1/*iAny*/ + nDeviceCoords)*sizeof(icFloatNumber); + + m_NamedColor = (SIccNamedColorEntry*)calloc(nSize, m_nColorEntrySize); + + m_NamedLab = NULL; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::CIccTagNamedColor2 + * + * Purpose: Copy Constructor + * + * Args: + * ITNC = The CIccTagNamedColor2 object to be copied + ***************************************************************************** + */ +CIccTagNamedColor2::CIccTagNamedColor2(const CIccTagNamedColor2 &ITNC) +{ + m_nColorEntrySize = ITNC.m_nColorEntrySize; + m_nVendorFlags = ITNC.m_nVendorFlags; + m_nDeviceCoords = ITNC.m_nDeviceCoords; + m_nSize = ITNC.m_nSize; + + m_csPCS = ITNC.m_csPCS; + m_csDevice = ITNC.m_csDevice; + + memcpy(m_szPrefix, ITNC.m_szPrefix, sizeof(m_szPrefix)); + memcpy(m_szSufix, ITNC.m_szSufix, sizeof(m_szSufix)); + + m_NamedColor = (SIccNamedColorEntry*)calloc(m_nSize, m_nColorEntrySize); + memcpy(m_NamedColor, ITNC.m_NamedColor, m_nColorEntrySize*m_nSize); + + m_NamedLab = NULL; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::operator= + * + * Purpose: Copy Operator + * + * Args: + * NamedColor2Tag = The CIccTagNamedColor2 object to be copied + ***************************************************************************** + */ +CIccTagNamedColor2 &CIccTagNamedColor2::operator=(const CIccTagNamedColor2 &NamedColor2Tag) +{ + if (&NamedColor2Tag == this) + return *this; + + m_nColorEntrySize = NamedColor2Tag.m_nColorEntrySize; + m_nVendorFlags = NamedColor2Tag.m_nVendorFlags; + m_nDeviceCoords = NamedColor2Tag.m_nDeviceCoords; + m_nSize = NamedColor2Tag.m_nSize; + + m_csPCS = NamedColor2Tag.m_csPCS; + m_csDevice = NamedColor2Tag.m_csDevice; + + memcpy(m_szPrefix, NamedColor2Tag.m_szPrefix, sizeof(m_szPrefix)); + memcpy(m_szSufix, NamedColor2Tag.m_szSufix, sizeof(m_szSufix)); + + if (m_NamedColor) + free(m_NamedColor); + m_NamedColor = (SIccNamedColorEntry*)calloc(m_nSize, m_nColorEntrySize); + memcpy(m_NamedColor, NamedColor2Tag.m_NamedColor, m_nColorEntrySize*m_nSize); + + m_NamedLab = NULL; + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::~CIccTagNamedColor2 + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagNamedColor2::~CIccTagNamedColor2() +{ + if (m_NamedColor) + free(m_NamedColor); + + if (m_NamedLab) + delete [] m_NamedLab; +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::SetSize + * + * Purpose: Sets the size of the named color array. + * + * Args: + * nSize - number of named color entries, + * nDeviceCoords - number of device channels + ***************************************************************************** + */ +void CIccTagNamedColor2::SetSize(icUInt32Number nSize, icInt32Number nDeviceCoords/*=-1*/) +{ + if (nSize <1) + nSize = 1; + if (nDeviceCoords<0) + nDeviceCoords = m_nDeviceCoords; + + icInt32Number nNewCoords=nDeviceCoords; + + if (nDeviceCoords>0) + nDeviceCoords--; + + icUInt32Number nColorEntrySize = 32/*rootName*/ + (3/*PCS*/ + 1/*iAny*/ + nDeviceCoords)*sizeof(icFloatNumber); + + SIccNamedColorEntry* pNamedColor = (SIccNamedColorEntry*)calloc(nSize, nColorEntrySize); + + icUInt32Number i, nCopy = __min(nSize, m_nSize); + icUInt32Number j, nCoords = __min(nNewCoords, (icInt32Number)m_nDeviceCoords); + + for (i=0; irootName, pFrom->rootName); + for (j=0; j<3; j++) + pTo->pcsCoords[j] = pFrom->pcsCoords[j]; + + for (j=0; jdeviceCoords[j] = pFrom->deviceCoords[j]; + } + } + free(m_NamedColor); + + m_nColorEntrySize = nColorEntrySize; + + m_NamedColor = pNamedColor; + m_nSize = nSize; + m_nDeviceCoords = nNewCoords; + + ResetPCSCache(); +} + + +/** +**************************************************************************** +* Name: CIccTagNamedColor2::SetPrefix +* +* Purpose: Set contents of suffix member field +* +* Args: +* szPrefix - string to set prefix to +***************************************************************************** +*/ +void CIccTagNamedColor2::SetPrefix(const icChar *szPrefix) +{ + strncpy(m_szPrefix, szPrefix, sizeof(m_szPrefix)); + m_szPrefix[sizeof(m_szPrefix)-1]='\0'; +} + + +/** +**************************************************************************** +* Name: CIccTagNamedColor2::SetSufix +* +* Purpose: Set contents of suffix member field +* +* Args: +* szPrefix - string to set prefix to +***************************************************************************** +*/ +void CIccTagNamedColor2::SetSufix(const icChar *szSufix) +{ + strncpy(m_szSufix, szSufix, sizeof(m_szSufix)); + m_szSufix[sizeof(m_szSufix)-1]='\0'; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagNamedColor2::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nNum, nCoords; + + icUInt32Number nTagHdrSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + //m_nReserved=0 + sizeof(icUInt32Number) + //VendorFlags + sizeof(icUInt32Number) + //Num Colors + sizeof(icUInt32Number) + //Num Device Coords + sizeof(m_szPrefix) + + sizeof(m_szSufix); + if (nTagHdrSize > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read32(&m_nVendorFlags) || + !pIO->Read32(&nNum) || + !pIO->Read32(&nCoords) || + pIO->Read8(m_szPrefix, sizeof(m_szPrefix))!=sizeof(m_szPrefix) || + pIO->Read8(m_szSufix, sizeof(m_szSufix))!=sizeof(m_szSufix)) { + return false; + } + + size -= nTagHdrSize; + + icUInt32Number nCount = size / (32+(3+nCoords)*sizeof(icUInt16Number)); + + if (nCount < nNum) + return false; + + SetSize(nNum, nCoords); + + icUInt32Number i; + SIccNamedColorEntry *pNamedColor=m_NamedColor; + + for (i=0; iRead8(&pNamedColor->rootName, sizeof(pNamedColor->rootName))!=sizeof(pNamedColor->rootName) || + pIO->Read16Float(&pNamedColor->pcsCoords, 3)!=3) + return false; + if (nCoords) { + if (pIO->Read16Float(&pNamedColor->deviceCoords, nCoords)!=(icInt32Number)nCoords) + return false; + } + pNamedColor = (SIccNamedColorEntry*)((icChar*)pNamedColor + m_nColorEntrySize); + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagNamedColor2::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write32(&m_nVendorFlags)) + return false; + + if (!pIO->Write32(&m_nSize)) + return false; + + if (!pIO->Write32(&m_nDeviceCoords)) + return false; + + if (!pIO->Write8(m_szPrefix, sizeof(m_szPrefix))) + return false; + + if (!pIO->Write8(m_szSufix, sizeof(m_szSufix))) + return false; + + icUInt32Number i; + SIccNamedColorEntry *pNamedColor=m_NamedColor; + + for (i=0; iWrite8(&pNamedColor->rootName, sizeof(pNamedColor->rootName))!=sizeof(pNamedColor->rootName) || + pIO->Write16Float(&pNamedColor->pcsCoords, 3)!=3) + return false; + if (m_nDeviceCoords) { + if (pIO->Write16Float(&pNamedColor->deviceCoords, m_nDeviceCoords) != (icInt32Number)m_nDeviceCoords) + return false; + } + pNamedColor = (SIccNamedColorEntry*)((icChar*)pNamedColor + m_nColorEntrySize); + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagNamedColor2::Describe(std::string &sDescription) +{ + icChar buf[128], szColorVal[40], szColor[40]; + + icUInt32Number i, j; + SIccNamedColorEntry *pNamedColor=m_NamedColor; + + sDescription.reserve(sDescription.size() + m_nSize*79); + + sprintf(buf, "BEGIN_NAMED_COLORS flags=%08x %u %u\r\n", m_nVendorFlags, m_nSize, m_nDeviceCoords); + sDescription += buf; + + sprintf(buf, "Prefix=\"%s\"\r\n", m_szPrefix); + sDescription += buf; + + sprintf(buf, "Sufix= \"%s\"\r\n", m_szSufix); + sDescription += buf; + + for (i=0; irootName); + sDescription += buf; + + icFloatNumber pcsCoord[3]; + for (j=0; j<3; j++) + pcsCoord[j] = pNamedColor->pcsCoords[j]; + + if (m_csPCS==icSigLabData) { + for (j=0; j<3; j++) + pcsCoord[j] = (icFloatNumber)(pcsCoord[j] * 65535.0 / 65280.0); + } + + for (j=0; j<3; j++) { + icColorIndexName(szColor, m_csPCS, j, 3, "P"); + icColorValue(szColorVal, pcsCoord[j], m_csPCS, j); + sprintf(buf, " %s=%s", szColor, szColorVal); + sDescription += buf; + } + if (m_nDeviceCoords) { + sDescription += " :"; + for (j=0; jdeviceCoords[j], m_csDevice, j); + sprintf(buf, " %s=%s", szColor, szColorVal); + sDescription += buf; + } + } + sDescription += "\r\n"; + + pNamedColor = (SIccNamedColorEntry*)((icChar*)pNamedColor + m_nColorEntrySize); + } +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::SetColorSpaces + * + * Purpose: Set the device and PCS color space of the tag + * + * Args: + * csPCS = PCS color space signature, + * csDevice = Device color space signature + * + ***************************************************************************** + */ +void CIccTagNamedColor2::SetColorSpaces(icColorSpaceSignature csPCS, icColorSpaceSignature csDevice) +{ + m_csPCS = csPCS; + m_csDevice = csDevice; +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::FindRootColor + * + * Purpose: Find the root color name + * + * Args: + * szRootColor = string containing the root color name to be found + * + * Return: Index of the named color array where the root color name was found, + * if the color was not found -1 is returned + ***************************************************************************** + */ +icInt32Number CIccTagNamedColor2::FindRootColor(const icChar *szRootColor) const +{ + for (icUInt32Number i=0; i (icInt32Number)m_nSize-1) + return false; + + sColorName += m_szPrefix; + sColorName += m_NamedColor[index].rootName; + sColorName += m_szSufix; + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::UnitClip + * + * Purpose: Clip number so that its between 0-1 + * + * Args: + * v = number to be clipped + * + * Return: Clipped number + * + ***************************************************************************** + */ +icFloatNumber CIccTagNamedColor2::UnitClip(icFloatNumber v) const +{ + if (v<0) + v = 0; + if (v>1.0) + v = 1.0; + + return v; +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::NegClip + * + * Purpose: Negative numbers are clipped to zero + * + * Args: + * v = number to be clipped + * + * Return: Clipped number + * + ***************************************************************************** + */ +icFloatNumber CIccTagNamedColor2::NegClip(icFloatNumber v) const +{ + if (v<0) + v=0; + + return v; +} + + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::Lab2ToLab4 + * + * Purpose: Convert version 2 Lab to version 4 Lab + * + * Args: + * Dst = array to store version 4 Lab coordinates, + * Src = array containing version 2 Lab coordinates + * + ***************************************************************************** + */ +void CIccTagNamedColor2::Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src) const +{ + Dst[0] = UnitClip((icFloatNumber)(Src[0] * 65535.0 / 65280.0)); + Dst[1] = UnitClip((icFloatNumber)(Src[1] * 65535.0 / 65280.0)); + Dst[2] = UnitClip((icFloatNumber)(Src[2] * 65535.0 / 65280.0)); +} + +/** + **************************************************************************** + * Name: CIccTagNamedColor2::Lab4ToLab2 + * + * Purpose: Convert version 4 Lab to version 2 Lab + * + * Args: + * Dst = array to store version 2 Lab coordinates, + * Src = array containing version 4 Lab coordinates + * + ***************************************************************************** + */ +void CIccTagNamedColor2::Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src) const +{ + Dst[0] = (icFloatNumber)(Src[0] * 65280.0 / 65535.0); + Dst[1] = (icFloatNumber)(Src[1] * 65280.0 / 65535.0); + Dst[2] = (icFloatNumber)(Src[2] * 65280.0 / 65535.0); +} + + +/** +****************************************************************************** +* Name: CIccTagNamedColor2::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagNamedColor2::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!m_nSize) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Empty tag!\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + + if (m_nDeviceCoords) { + if (pProfile) { + icUInt32Number nCoords = icGetSpaceSamples(pProfile->m_Header.colorSpace); + if (m_nDeviceCoords != nCoords) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Incorrect number of device co-ordinates.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + else { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + } + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccTagXYZ::CIccTagXYZ + * + * Purpose: Constructor + * + * Args: + * nSize = number of XYZ entries + * + ***************************************************************************** + */ +CIccTagXYZ::CIccTagXYZ(int nSize/*=1*/) +{ + m_nSize = nSize; + if (m_nSize <1) + m_nSize = 1; + m_XYZ = (icXYZNumber*)calloc(nSize, sizeof(icXYZNumber)); +} + + +/** + **************************************************************************** + * Name: CIccTagXYZ::CIccTagXYZ + * + * Purpose: Copy Constructor + * + * Args: + * ITXYZ = The CIccTagXYZ object to be copied + ***************************************************************************** + */ +CIccTagXYZ::CIccTagXYZ(const CIccTagXYZ &ITXYZ) +{ + m_nSize = ITXYZ.m_nSize; + + m_XYZ = (icXYZNumber*)calloc(m_nSize, sizeof(icXYZNumber)); + memcpy(m_XYZ, ITXYZ.m_XYZ, sizeof(icXYZNumber)*m_nSize); +} + + + +/** + **************************************************************************** + * Name: CIccTagXYZ::operator= + * + * Purpose: Copy Operator + * + * Args: + * XYZTag = The CIccTagXYZ object to be copied + ***************************************************************************** + */ +CIccTagXYZ &CIccTagXYZ::operator=(const CIccTagXYZ &XYZTag) +{ + if (&XYZTag == this) + return *this; + + m_nSize = XYZTag.m_nSize; + + if (m_XYZ) + free(m_XYZ); + m_XYZ = (icXYZNumber*)calloc(m_nSize, sizeof(icXYZNumber)); + memcpy(m_XYZ, XYZTag.m_XYZ, sizeof(icXYZNumber)*m_nSize); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagXYZ::~CIccTagXYZ + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagXYZ::~CIccTagXYZ() +{ + if (m_XYZ) + free(m_XYZ); +} + + +/** + **************************************************************************** + * Name: CIccTagXYZ::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagXYZ::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icXYZNumber) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number nNum=((size-2*sizeof(icUInt32Number)) / sizeof(icXYZNumber)); + icUInt32Number nNum32 = nNum*sizeof(icXYZNumber)/sizeof(icUInt32Number); + + SetSize(nNum); + + if (pIO->Read32(m_XYZ, nNum32) != (icInt32Number)nNum32 ) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagXYZ::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagXYZ::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + icUInt32Number nNum32 = m_nSize * sizeof(icXYZNumber)/sizeof(icUInt32Number); + + if ( + pIO->Write32(m_XYZ, nNum32) != (icInt32Number)nNum32) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagXYZ::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagXYZ::Describe(std::string &sDescription) +{ + icChar buf[128]; + + if (m_nSize == 1 ) { + sprintf(buf, "X=%.4lf, Y=%.4lf, Z=%.4lf\r\n", icFtoD(m_XYZ[0].X), icFtoD(m_XYZ[0].Y), icFtoD(m_XYZ[0].Z)); + sDescription += buf; + } + else { + icUInt32Number i; + sDescription.reserve(sDescription.size() + m_nSize*79); + + for (i=0; i size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&nChannels) || + !pIO->Read16(&m_nColorantType)) + return false; + + icUInt32Number nNum = (size-3*sizeof(icUInt32Number)) / sizeof(icChromaticityNumber); + icUInt32Number nNum32 = nNum*sizeof(icChromaticityNumber)/sizeof(icU16Fixed16Number); + + if (nNum < nChannels) + return false; + + SetSize((icUInt16Number)nNum); + + if (pIO->Read32(&m_xy[0], nNum32) != (icInt32Number)nNum32 ) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagChromaticity::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagChromaticity::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nChannels)) + return false; + + if (!pIO->Write16(&m_nColorantType)) + return false; + + icUInt32Number nNum32 = m_nChannels*sizeof(icChromaticityNumber)/sizeof(icU16Fixed16Number); + + if (pIO->Write32(&m_xy[0], nNum32) != (icInt32Number)nNum32) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagChromaticity::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagChromaticity::Describe(std::string &sDescription) +{ + icChar buf[128]; + CIccInfo Fmt; + + icUInt32Number i; + //sDescription.reserve(sDescription.size() + m_nChannels*79); + sprintf(buf, "Number of Channels : %u\r\n", m_nChannels); + sDescription += buf; + + sprintf(buf, "Colorant Encoding : %s\r\n", Fmt.GetColorantEncoding((icColorantEncoding)m_nColorantType)); + sDescription += buf; + + for (i=0; i m_nChannels) { + memset(&m_xy[m_nChannels], 0, (nSize - m_nChannels)*sizeof(icChromaticityNumber)); + } + + m_nChannels = nSize; +} + + +/** +****************************************************************************** +* Name: CIccTagChromaticity::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagChromaticity::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (m_nColorantType) { + + if (m_nChannels!=3) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Number of device channels must be three.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + switch(m_nColorantType) { + case icColorantITU: + { + if ( (m_xy[0].x != icDtoUF((icFloatNumber)0.640)) || (m_xy[0].y != icDtoUF((icFloatNumber)0.330)) || + (m_xy[1].x != icDtoUF((icFloatNumber)0.300)) || (m_xy[1].y != icDtoUF((icFloatNumber)0.600)) || + (m_xy[2].x != icDtoUF((icFloatNumber)0.150)) || (m_xy[2].y != icDtoUF((icFloatNumber)0.060)) ) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Chromaticity data does not match specification.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + break; + } + + case icColorantSMPTE: + { + if ( (m_xy[0].x != icDtoUF((icFloatNumber)0.630)) || (m_xy[0].y != icDtoUF((icFloatNumber)0.340)) || + (m_xy[1].x != icDtoUF((icFloatNumber)0.310)) || (m_xy[1].y != icDtoUF((icFloatNumber)0.595)) || + (m_xy[2].x != icDtoUF((icFloatNumber)0.155)) || (m_xy[2].y != icDtoUF((icFloatNumber)0.070)) ) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Chromaticity data does not match specification.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + break; + } + + case icColorantEBU: + { + if ( (m_xy[0].x != icDtoUF((icFloatNumber)0.64)) || (m_xy[0].y != icDtoUF((icFloatNumber)0.33)) || + (m_xy[1].x != icDtoUF((icFloatNumber)0.29)) || (m_xy[1].y != icDtoUF((icFloatNumber)0.60)) || + (m_xy[2].x != icDtoUF((icFloatNumber)0.15)) || (m_xy[2].y != icDtoUF((icFloatNumber)0.06)) ) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Chromaticity data does not match specification.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + break; + } + + case icColorantP22: + { + if ( (m_xy[0].x != icDtoUF((icFloatNumber)0.625)) || (m_xy[0].y != icDtoUF((icFloatNumber)0.340)) || + (m_xy[1].x != icDtoUF((icFloatNumber)0.280)) || (m_xy[1].y != icDtoUF((icFloatNumber)0.605)) || + (m_xy[2].x != icDtoUF((icFloatNumber)0.155)) || (m_xy[2].y != icDtoUF((icFloatNumber)0.070)) ) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Chromaticity data does not match specification.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + break; + } + + default: + { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Invalid colorant type encoding.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + } + + return rv; +} + + +/** + **************************************************************************** + * Name: ::CIccTagFixedNum + * + * Purpose: ConstrCIccTagFixedNumuctor + * + * Args: + * nSize = number of data entries + * + ***************************************************************************** + */ +template +CIccTagFixedNum::CIccTagFixedNum(int nSize/*=1*/) +{ + m_nSize = nSize; + if (m_nSize <1) + m_nSize = 1; + m_Num = (T*)calloc(nSize, sizeof(T)); +} + + +/** + **************************************************************************** + * Name: CIccTagFixedNum::CIccTagFixedNum + * + * Purpose: Copy Constructor + * + * Args: + * ITFN = The CIccTagFixedNum object to be copied + ***************************************************************************** + */ +template +CIccTagFixedNum::CIccTagFixedNum(const CIccTagFixedNum &ITFN) +{ + m_nSize = ITFN.m_nSize; + m_Num = (T*)calloc(m_nSize, sizeof(T)); + memcpy(m_Num, ITFN.m_Num, sizeof(T) * m_nSize); +} + + +/** + **************************************************************************** + * Name: CIccTagFixedNum::operator= + * + * Purpose: Copy Operator + * + * Args: + * ITFN = The CIccTagFixedNum object to be copied + ***************************************************************************** + */ +template +CIccTagFixedNum &CIccTagFixedNum::operator=(const CIccTagFixedNum &ITFN) +{ + if (&ITFN == this) + return *this; + + m_nSize = ITFN.m_nSize; + + if (m_Num) + free(m_Num); + m_Num = (T*)calloc(m_nSize, sizeof(T)); + memcpy(m_Num, ITFN.m_Num, sizeof(T) * m_nSize); + + return *this; +} + + + +/** + **************************************************************************** + * Name: CIccTagFixedNum::~CIccTagFixedNum + * + * Purpose: Destructor + * + ***************************************************************************** + */ +template +CIccTagFixedNum::~CIccTagFixedNum() +{ + if (m_Num) + free(m_Num); +} + +/** + **************************************************************************** + * Name: CIccTagFixedNum::GetClassName + * + * Purpose: Returns the tag type class name + * + ***************************************************************************** + */ +template +const icChar* CIccTagFixedNum::GetClassName() const +{ + if (Tsig==icSigS15Fixed16ArrayType) + return "CIccTagS15Fixed16"; + else + return "CIccTagU16Fixed16"; +} + + +/** + **************************************************************************** + * Name: CIccTagFixedNum::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +template +bool CIccTagFixedNum::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(T) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number nSize=((size-2*sizeof(icUInt32Number)) / sizeof(T)); + + SetSize(nSize); + + if (pIO->Read32(m_Num, nSize) != (icInt32Number)nSize ) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagFixedNum::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +template +bool CIccTagFixedNum::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (pIO->Write32(m_Num, m_nSize) != (icInt32Number)m_nSize) + return false; + + return true; +} + +/** + **************************************************************************** + * Name: CIccTagFixedNum::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +template +void CIccTagFixedNum::Describe(std::string &sDescription) +{ + icChar buf[128]; + + if (m_nSize == 1 ) { + if (Tsig==icSigS15Fixed16ArrayType) + sprintf(buf, "Value = %.4lf\r\n", icFtoD(m_Num[0])); + else + sprintf(buf, "Value = %.4lf\r\n", icUFtoD(m_Num[0])); + sDescription += buf; + } + else { + icUInt32Number i; + + if (Tsig==icSigS15Fixed16ArrayType && m_nSize==9) { + sDescription += "Matrix Form:\r\n"; + icMatrixDump(sDescription, (icS15Fixed16Number*)m_Num); + + sDescription += "\r\nArrayForm:\r\n"; + } + sDescription.reserve(sDescription.size() + m_nSize*79); + + for (i=0; i +void CIccTagFixedNum::SetSize(icUInt32Number nSize, bool bZeroNew/*=true*/) +{ + if (nSize==m_nSize) + return; + + m_Num = (T*)realloc(m_Num, nSize*sizeof(T)); + if (bZeroNew && m_nSize < nSize) { + memset(&m_Num[m_nSize], 0, (nSize-m_nSize)*sizeof(T)); + } + m_nSize = nSize; +} + + +//Make sure typedef classes get built +template class CIccTagFixedNum; +template class CIccTagFixedNum; + + +/** + **************************************************************************** + * Name: CIccTagNum::CIccTagNum + * + * Purpose: Constructor + * + * Args: + * nSize = number of data entries + ***************************************************************************** + */ +template +CIccTagNum::CIccTagNum(int nSize/*=1*/) +{ + m_nSize = nSize; + if (m_nSize <1) + m_nSize = 1; + m_Num = (T*)calloc(nSize, sizeof(T)); +} + + +/** + **************************************************************************** + * Name: CIccTagNum::CIccTagNum + * + * Purpose: Copy Constructor + * + * Args: + * ITNum = The CIccTagNum object to be copied + ***************************************************************************** + */ +template +CIccTagNum::CIccTagNum(const CIccTagNum &ITNum) +{ + m_nSize = ITNum.m_nSize; + + m_Num = (T*)calloc(m_nSize, sizeof(T)); + memcpy(m_Num, ITNum.m_Num, sizeof(T)*m_nSize); +} + + +/** + **************************************************************************** + * Name: CIccTagNum::operator= + * + * Purpose: Copy Operator + * + * Args: + * ITNum = The CIccTagNum object to be copied + ***************************************************************************** + */ +template +CIccTagNum &CIccTagNum::operator=(const CIccTagNum &ITNum) +{ + if (&ITNum == this) + return *this; + + m_nSize = ITNum.m_nSize; + + m_Num = (T*)calloc(m_nSize, sizeof(T)); + memcpy(m_Num, ITNum.m_Num, sizeof(T)*m_nSize); + + return *this; +} + + + +/** + **************************************************************************** + * Name: CIccTagNum::~CIccTagNum + * + * Purpose: Destructor + * + ***************************************************************************** + */ +template +CIccTagNum::~CIccTagNum() +{ + if (m_Num) + free(m_Num); +} + +/** + **************************************************************************** + * Name: CIccTagNum::GetClassName + * + * Purpose: Returns the tag type class name + * + ***************************************************************************** + */ +template +const icChar *CIccTagNum::GetClassName() const +{ + if (sizeof(T)==sizeof(icUInt8Number)) + return "CIccTagUInt8"; + else if (sizeof(T)==sizeof(icUInt16Number)) + return "CIccTagUInt16"; + else if (sizeof(T)==sizeof(icUInt32Number)) + return "CIccTagUInt32"; + else if (sizeof(T)==sizeof(icUInt64Number)) + return "CIccTagUInt64"; + else + return "CIccTagNum<>"; +} + + +/** + **************************************************************************** + * Name: CIccTagNum::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +template +bool CIccTagNum::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(T) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number nSize=((size-2*sizeof(icUInt32Number)) / sizeof(T)); + + SetSize(nSize); + + if (sizeof(T)==sizeof(icUInt8Number)) { + if (pIO->Read8(m_Num, nSize) != (icInt32Number)nSize ) + return false; + } + else if (sizeof(T)==sizeof(icUInt16Number)) { + if (pIO->Read16(m_Num, nSize) != (icInt32Number)nSize ) + return false; + } + else if (sizeof(T)==sizeof(icUInt32Number)) { + if (pIO->Read32(m_Num, nSize) != (icInt32Number)nSize ) + return false; + } + else if (sizeof(T)==sizeof(icUInt64Number)) { + if (pIO->Read64(m_Num, nSize) != (icInt32Number)nSize ) + return false; + } + else + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagNum::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +template +bool CIccTagNum::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (sizeof(T)==sizeof(icUInt8Number)) { + if (pIO->Write32(m_Num, m_nSize) != (icInt32Number)m_nSize) + return false; + } + else if (sizeof(T)==sizeof(icUInt16Number)) { + if (pIO->Write32(m_Num, m_nSize) != (icInt32Number)m_nSize) + return false; + } + else if (sizeof(T)==sizeof(icUInt32Number)) { + if (pIO->Write32(m_Num, m_nSize) != (icInt32Number)m_nSize) + return false; + } + else if (sizeof(T)==sizeof(icUInt64Number)) { + if (pIO->Write32(m_Num, m_nSize) != (icInt32Number)m_nSize) + return false; + } + else + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagNum::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +template +void CIccTagNum::Describe(std::string &sDescription) +{ + icChar buf[128]; + + if (m_nSize == 1 ) { + switch (sizeof(T)) { + case 1: + sprintf(buf, "Value = %u (0x02%x)\r\n", m_Num[0], m_Num[0]); + break; + case 2: + sprintf(buf, "Value = %u (0x04%x)\r\n", m_Num[0], m_Num[0]); + break; + case 4: + sprintf(buf, "Value = %u (0x08%x)\r\n", m_Num[0], m_Num[0]); + break; + case 8: + sprintf(buf, "Value = %u (0x016%x)\r\n", m_Num[0], m_Num[0]); + break; + default: + sprintf(buf, "Value = %u (0x%x)\r\n", m_Num[0], m_Num[0]); + break; + } + sDescription += buf; + } + else { + icUInt32Number i; + sDescription.reserve(sDescription.size() + m_nSize*79); + + for (i=0; i +void CIccTagNum::Describe(std::string &sDescription) +{ + icChar buf[128]; + + if (m_nSize == 1 ) { + sprintf(buf, "Value = %llu (0x016%llx)\r\n", m_Num[0], m_Num[0]); + sDescription += buf; + } + else { + icUInt32Number i; + sDescription.reserve(sDescription.size() + m_nSize*79); + + for (i=0; i +void CIccTagNum::SetSize(icUInt32Number nSize, bool bZeroNew/*=true*/) +{ + if (nSize==m_nSize) + return; + + m_Num = (T*)realloc(m_Num, nSize*sizeof(T)); + if (bZeroNew && m_nSize < nSize) { + memset(&m_Num[m_nSize], 0, (nSize-m_nSize)*sizeof(T)); + } + m_nSize = nSize; +} + +//Make sure typedef classes get built +template class CIccTagNum; +template class CIccTagNum; +template class CIccTagNum; +template class CIccTagNum; + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::CIccTagMeasurement + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagMeasurement::CIccTagMeasurement() +{ + memset(&m_Data, 0, sizeof(m_Data)); +} + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::CIccTagMeasurement + * + * Purpose: Copy Constructor + * + * Args: + * ITM = The CIccTagMeasurement object to be copied + ***************************************************************************** + */ +CIccTagMeasurement::CIccTagMeasurement(const CIccTagMeasurement &ITM) +{ + memcpy(&m_Data, &ITM.m_Data, sizeof(m_Data)); +} + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::operator= + * + * Purpose: Copy Operator + * + * Args: + * MeasTag = The CIccTagMeasurement object to be copied + ***************************************************************************** + */ +CIccTagMeasurement &CIccTagMeasurement::operator=(const CIccTagMeasurement &MeasTag) +{ + if (&MeasTag == this) + return *this; + + memcpy(&m_Data, &MeasTag.m_Data, sizeof(m_Data)); + + return *this; +} + + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::~CIccTagMeasurement + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagMeasurement::~CIccTagMeasurement() +{ +} + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagMeasurement::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(m_Data) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number nSize=sizeof(m_Data)/sizeof(icUInt32Number); + + if (pIO->Read32(&m_Data,nSize) != (icInt32Number)nSize) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagMeasurement::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + icUInt32Number nSize=sizeof(m_Data)/sizeof(icUInt32Number); + + if (pIO->Write32(&m_Data,nSize) != (icInt32Number)nSize) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagMeasurement::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagMeasurement::Describe(std::string &sDescription) +{ + CIccInfo Fmt; + icChar buf[128]; + + sDescription += Fmt.GetStandardObserverName(m_Data.stdObserver); sDescription += "\r\n"; + sprintf(buf, "Backing measurement: X=%.4lf, Y=%.4lf, Z=%.4lf\r\n", + icFtoD(m_Data.backing.X), + icFtoD(m_Data.backing.Y), + icFtoD(m_Data.backing.Z)); + sDescription += buf; + sDescription += Fmt.GetMeasurementGeometryName(m_Data.geometry); sDescription += "\r\n"; + sDescription += Fmt.GetMeasurementFlareName(m_Data.flare); sDescription += "\r\n"; + sDescription += Fmt.GetIlluminantName(m_Data.illuminant); sDescription += "\r\n"; +} + + +/** +****************************************************************************** +* Name: CIccTagMeasurement::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagMeasurement::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + switch(m_Data.stdObserver) { + case icStdObsUnknown: + case icStdObs1931TwoDegrees: + case icStdObs1964TenDegrees: + break; + + default: + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Invalid standard observer encoding.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + switch(m_Data.geometry) { + case icGeometryUnknown: + case icGeometry045or450: + case icGeometry0dord0: + break; + + default: + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Invalid measurement geometry encoding.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + switch(m_Data.illuminant) { + case icIlluminantUnknown: + case icIlluminantD50: + case icIlluminantD65: + case icIlluminantD93: + case icIlluminantF2: + case icIlluminantD55: + case icIlluminantA: + case icIlluminantEquiPowerE: + case icIlluminantF8: + break; + + default: + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Invalid standard illuminant encoding.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccLocalizedUnicode::CIccLocalizedUnicode + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccLocalizedUnicode::CIccLocalizedUnicode() +{ + m_pBuf = (icUInt16Number*)malloc(1*sizeof(icUInt16Number)); + *m_pBuf = 0; + m_nLength = 0; +} + + +/** + **************************************************************************** + * Name: CIccLocalizedUnicode::CIccLocalizedUnicode + * + * Purpose: Copy Constructor + * + * Args: + * ILU = The CIccLocalizedUnicode object to be copied + ***************************************************************************** + */ +CIccLocalizedUnicode::CIccLocalizedUnicode(const CIccLocalizedUnicode& ILU) +{ + m_nLength = ILU.GetLength(); + m_pBuf = (icUInt16Number*)malloc((m_nLength+1) * sizeof(icUInt16Number)); + if (m_nLength) + memcpy(m_pBuf, ILU.GetBuf(), m_nLength*sizeof(icUInt16Number)); + m_pBuf[m_nLength] = 0; + m_nLanguageCode = ILU.m_nLanguageCode; + m_nCountryCode = ILU.m_nCountryCode; +} + + +/** + **************************************************************************** + * Name: CIccLocalizedUnicode::operator= + * + * Purpose: Copy Operator + * + * Args: + * UnicodeText = The CIccLocalizedUnicode object to be copied + ***************************************************************************** + */ +CIccLocalizedUnicode &CIccLocalizedUnicode::operator=(const CIccLocalizedUnicode &UnicodeText) +{ + if (&UnicodeText == this) + return *this; + + SetSize(UnicodeText.GetLength()); + memcpy(m_pBuf, UnicodeText.GetBuf(), m_nLength*sizeof(icUInt16Number)); + m_nLanguageCode = UnicodeText.m_nLanguageCode; + m_nCountryCode = UnicodeText.m_nCountryCode; + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccLocalizedUnicode::~CIccLocalizedUnicode + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccLocalizedUnicode::~CIccLocalizedUnicode() +{ + if (m_pBuf) + free(m_pBuf); +} + +/** + **************************************************************************** + * Name: CIccLocalizedUnicode::GetAnsiSize + * + * Purpose: Returns the size of the ANSI data buffer + * + ***************************************************************************** + */ +icUInt32Number CIccLocalizedUnicode::GetAnsiSize() +{ + icUInt32Number len; +#ifdef USE_WINDOWS_MB_SUPPORT + len = WideCharToMultiByte(CP_ACP, 0x00000400, (LPCWSTR)m_pBuf, m_nLength, NULL, 0, NULL, NULL); +#else + len = m_nLength; +#endif + + return len; +} + +/** + **************************************************************************** + * Name: CIccLocalizedUnicode::GetAnsi + * + * Purpose: Extracts the ANSI data buffer + * + * Args: + * szBuf = pointer where the returned string buffer is to be stored + * nBufSize = size of the buffer to be extracted + * + * Return: + * Pointer to the ANSI data string + ***************************************************************************** + */ +const icChar *CIccLocalizedUnicode::GetAnsi(icChar *szBuf, icUInt32Number nBufSize) +{ + if (!szBuf) + return NULL; + + if (!m_nLength) { + *szBuf='\0'; + } + else { +#ifdef USE_WINDOWS_MB_SUPPORT + int len = WideCharToMultiByte(CP_ACP, 0x00000400, (LPCWSTR)m_pBuf, m_nLength, szBuf, nBufSize, NULL, NULL); + szBuf[len]='\0'; +#else + icUInt32Number i; + + for (i=0; iclear(); + *m_Strings = *MultiLocalizedTag.m_Strings; + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagMultiLocalizedUnicode::~CIccTagMultiLocalizedUnicode + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagMultiLocalizedUnicode::~CIccTagMultiLocalizedUnicode() +{ + delete m_Strings; +} + + +/** + **************************************************************************** + * Name: CIccTagMultiLocalizedUnicode::Read + * + * Purpose: Read in the tag contents into a data block + * + * Since MultiLocalizedUnicode tags can be embedded in other tags + * this function ensures that the current read pointer will be set to the + * position just after the last name record. + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagMultiLocalizedUnicode::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nNumRec, nRecSize; + icLanguageCode nLanguageCode; + icCountryCode nRegionCode; + icUInt32Number nLength, nOffset, nNumChar; + + if (!m_Strings->empty()) + m_Strings->clear(); + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number)*3 > size) + return false; + + if (!pIO) { + return false; + } + + icUInt32Number nTagPos = pIO->Tell(); + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read32(&nNumRec) || + !pIO->Read32(&nRecSize)) + return false; + + + if (nRecSize!=12) { //Recognized version name records are 12 bytes each + return false; + } + + icUInt32Number i; + CIccLocalizedUnicode Unicode; + icUInt32Number nLastPos = 0; + + for (i=0; i size) + return false; + + pIO->Seek(nTagPos+4*sizeof(icUInt32Number) + i*12, icSeekSet); + + if (!pIO->Read16(&nLanguageCode) || + !pIO->Read16(&nRegionCode) || + !pIO->Read32(&nLength) || + !pIO->Read32(&nOffset)) + return false; + + if (nOffset+nLength > size) + return false; + + //Find out position of the end of last named record + if (nOffset+nLength > nLastPos) + nLastPos = nOffset + nLength; + + nNumChar = nLength / sizeof(icUInt16Number); + + Unicode.SetSize(nNumChar); + Unicode.m_nLanguageCode = nLanguageCode; + Unicode.m_nCountryCode = nRegionCode; + + pIO->Seek(nTagPos+nOffset, icSeekSet); + + if (pIO->Read16(Unicode.GetBuf(), nNumChar) != (icInt32Number)nNumChar) + return false; + + m_Strings->push_back(Unicode); + } + + //Now seek past the last named record + if (nLastPos > 0) + pIO->Seek(nTagPos+nLastPos, icSeekSet); + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagMultiLocalizedUnicode::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagMultiLocalizedUnicode::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt32Number nNumRec=(icUInt32Number)m_Strings->size(), nRecSize=12; + icUInt32Number nLength; + + if (!pIO) { + return false; + } + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write32(&nNumRec) || + !pIO->Write32(&nRecSize)) + return false; + + + icUInt32Number nPos = 4*sizeof(icUInt32Number) + nNumRec*12; + + CIccMultiLocalizedUnicode::iterator i; + + for (i=m_Strings->begin(); i!=m_Strings->end(); i++) { + nLength = i->GetLength() * sizeof(icUInt16Number); + + if (!pIO->Write16(&i->m_nLanguageCode) || + !pIO->Write16(&i->m_nCountryCode) || + !pIO->Write32(&nLength) || + !pIO->Write32(&nPos)) + return false; + nPos += nLength; + } + + for (i=m_Strings->begin(); i!=m_Strings->end(); i++) { + nLength = i->GetLength(); + + if (nLength) { + if (pIO->Write16(i->GetBuf(), nLength) != (icInt32Number)nLength) + return false; + } + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagMultiLocalizedUnicode::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagMultiLocalizedUnicode::Describe(std::string &sDescription) +{ + icChar *szBuf = (icChar*)malloc(128); + int nSize = 127, nAnsiSize; + CIccMultiLocalizedUnicode::iterator i; + + for (i=m_Strings->begin(); i!=m_Strings->end(); i++) { + if (i!=m_Strings->begin()) + sDescription += "\r\n"; + + sprintf(szBuf, "Language = '%c%c', Region = '%c%c'\r\n", + i->m_nLanguageCode>>8, i->m_nLanguageCode, + i->m_nCountryCode>>8, i->m_nCountryCode); + + sDescription += szBuf; + + nAnsiSize = i->GetAnsiSize(); + + if (nAnsiSize>nSize) { + szBuf = (icChar*)realloc(szBuf, nAnsiSize+1); + nSize = nAnsiSize; + } + i->GetAnsi(szBuf, nSize); + sDescription += "\""; + sDescription += szBuf; + sDescription += "\"\r\n"; + } +} + + +/** +****************************************************************************** +* Name: CIccTagMultiLocalizedUnicode::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagMultiLocalizedUnicode::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!m_Strings->size()) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Empty tag!\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + + // TODO: Look at the ISO-639 and ISO-3166 documents for valid + // Language and Region codes +/* + CIccMultiLocalizedUnicode::iterator i; + for (i=m_Strings->begin(); i!=m_Strings->end(); i++) { + switch(i->m_nLanguageCode) { + case : + break; + default: + } + + switch(i->m_nRegionCode) { + case : + break; + default: + } + } +*/ + + return rv; +} + +/** +**************************************************************************** +* Name: sampleICC::CIccTagMultiLocalizedUnicode::Find +* +* Purpose: +* +* Args: +* nLanguageCode +* nRegionCode +* +* Return: +* Pointer to CIccLocalizedUnicode object associated with the nLanguageCode +* and nRegionCode or NULL if not found +***************************************************************************** +*/ +CIccLocalizedUnicode *CIccTagMultiLocalizedUnicode::Find(icLanguageCode nLanguageCode /* = icLanguageCodeEnglish */, + icCountryCode nRegionCode /* = icCountryCodeUSA */) +{ + CIccMultiLocalizedUnicode::iterator i; + + for (i=m_Strings->begin(); i!=m_Strings->end(); i++) { + if (i->m_nLanguageCode == nLanguageCode && + i->m_nCountryCode == nRegionCode) { + return &(*i); + } + } + + return NULL; +} + +/** +**************************************************************************** +* Name: sampleICC::CIccTagMultiLocalizedUnicode::SetText +* +* Purpose: +* +* Args: +* sszUnicodeText +* nLanguageCode +* RegionCode +***************************************************************************** +*/ +void CIccTagMultiLocalizedUnicode::SetText(const icChar *szText, + icLanguageCode nLanguageCode /* = icLanguageCodeEnglish */, + icCountryCode nRegionCode /* = icCountryCodeUSA */) +{ + CIccLocalizedUnicode *pText = Find(nLanguageCode, nRegionCode); + + if (!pText) { + CIccLocalizedUnicode newText; + newText.SetText(szText, nLanguageCode, nRegionCode); + m_Strings->push_back(newText); + } + else { + pText->SetText(szText, nLanguageCode, nRegionCode); + } +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccTagMultiLocalizedUnicode::SetText +* +* Purpose: +* +* Args: +* sszUnicodeText +* nLanguageCode +* RegionCode +***************************************************************************** +*/ +void CIccTagMultiLocalizedUnicode::SetText(const icUInt16Number *sszUnicode16Text, + icLanguageCode nLanguageCode /* = icLanguageCodeEnglish */, + icCountryCode nRegionCode /* = icCountryCodeUSA */) +{ + CIccLocalizedUnicode *pText = Find(nLanguageCode, nRegionCode); + + if (!pText) { + CIccLocalizedUnicode newText; + newText.SetText(sszUnicode16Text, nLanguageCode, nRegionCode); + m_Strings->push_back(newText); + } + else { + pText->SetText(sszUnicode16Text, nLanguageCode, nRegionCode); + } +} + +/** +**************************************************************************** +* Name: sampleICC::CIccTagMultiLocalizedUnicode::SetText +* +* Purpose: +* +* Args: +* sszUnicodeText +* nLanguageCode +* RegionCode +***************************************************************************** +*/ +void CIccTagMultiLocalizedUnicode::SetText(const icUInt32Number *sszUnicode32Text, + icLanguageCode nLanguageCode /* = icLanguageCodeEnglish */, + icCountryCode nRegionCode /* = icCountryCodeUSA */) +{ + CIccLocalizedUnicode *pText = Find(nLanguageCode, nRegionCode); + + if (!pText) { + CIccLocalizedUnicode newText; + newText.SetText(sszUnicode32Text, nLanguageCode, nRegionCode); + m_Strings->push_back(newText); + } + else { + pText->SetText(sszUnicode32Text, nLanguageCode, nRegionCode); + } +} + +// +// MD: Moved Curve and LUT tags to IccTagLut.cpp (4-30-05) +// + + +/** + **************************************************************************** + * Name: CIccTagData::CIccTagData + * + * Purpose: Constructor + * + * Args: + * nSize = number of data entries + * + ***************************************************************************** + */ +CIccTagData::CIccTagData(int nSize/*=1*/) +{ + m_nSize = nSize; + if (m_nSize <1) + m_nSize = 1; + m_pData = (icUInt8Number*)calloc(nSize, sizeof(icUInt8Number)); +} + + +/** + **************************************************************************** + * Name: CIccTagData::CIccTagData + * + * Purpose: Copy Constructor + * + * Args: + * ITD = The CIccTagData object to be copied + ***************************************************************************** + */ +CIccTagData::CIccTagData(const CIccTagData &ITD) +{ + m_nDataFlag = ITD.m_nDataFlag; + m_nSize = ITD.m_nSize; + + m_pData = (icUInt8Number*)calloc(m_nSize, sizeof(icUInt8Number)); + memcpy(m_pData, ITD.m_pData, sizeof(icUInt8Number)*m_nSize); +} + + +/** + **************************************************************************** + * Name: CIccTagData::operator= + * + * Purpose: Copy Operator + * + * Args: + * DataTag = The CIccTagData object to be copied + ***************************************************************************** + */ +CIccTagData &CIccTagData::operator=(const CIccTagData &DataTag) +{ + if (&DataTag == this) + return *this; + + m_nDataFlag = DataTag.m_nDataFlag; + m_nSize = DataTag.m_nSize; + + if (m_pData) + free(m_pData); + m_pData = (icUInt8Number*)calloc(m_nSize, sizeof(icUInt8Number)); + memcpy(m_pData, DataTag.m_pData, sizeof(icUInt8Number)*m_nSize); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagData::~CIccTagData + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagData::~CIccTagData() +{ + if (m_pData) + free(m_pData); +} + + +/** + **************************************************************************** + * Name: CIccTagData::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagData::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number) + + sizeof(icUInt8Number) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read32(&m_nDataFlag)) + return false; + + icUInt32Number nNum = size-3*sizeof(icUInt32Number); + + SetSize(nNum); + + if (pIO->Read8(m_pData, nNum) != (icInt32Number)nNum) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagData::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagData::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write32(&m_nDataFlag)) + return false; + + if (pIO->Write8(m_pData, m_nSize) != (icInt32Number)m_nSize) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagData::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagData::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sDescription = "\r\nData:\r\n"; + + if (IsTypeAscii()) { + sprintf(buf, "%s\r\n", (icChar*)m_pData); + sDescription += buf; + } + else + for (int i = 0; i<(int)m_nSize; i++) { + sprintf(buf, "%d\r\n", m_pData[i]); + sDescription += buf; + } + +} + +/** + **************************************************************************** + * Name: CIccTagData::SetSize + * + * Purpose: Sets the size of the data array. + * + * Args: + * nSize - number of data entries, + * bZeroNew - flag to zero newly formed values + ***************************************************************************** + */ +void CIccTagData::SetSize(icUInt32Number nSize, bool bZeroNew/*=true*/) +{ + if (m_nSize == nSize) + return; + + m_pData = (icUInt8Number*)realloc(m_pData, nSize*sizeof(icUInt8Number)); + if (bZeroNew && nSize > m_nSize) { + memset(&m_pData[m_nSize], 0, (nSize-m_nSize)*sizeof(icUInt8Number)); + } + m_nSize = nSize; +} + + +/** +****************************************************************************** +* Name: CIccTagData::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagData::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + switch(m_nDataFlag) { + case 0x00000000: + case 0x00000001: + break; + default: + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Invalid data flag encoding.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + return rv; +} + +/** + **************************************************************************** + * Name: CIccTagDateTime::CIccTagDateTime + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagDateTime::CIccTagDateTime() +{ + memset(&m_DateTime, 0, sizeof(m_DateTime)); +} + + +/** + **************************************************************************** + * Name: CIccTagDateTime::CIccTagDateTime + * + * Purpose: Copy Constructor + * + * Args: + * ITDT = The CIccTagDateTime object to be copied + ***************************************************************************** + */ +CIccTagDateTime::CIccTagDateTime(const CIccTagDateTime &ITDT) +{ + memcpy(&m_DateTime, &ITDT.m_DateTime, sizeof(m_DateTime)); +} + + +/** + **************************************************************************** + * Name: CIccTagDateTime::operator= + * + * Purpose: Copy Operator + * + * Args: + * DateTimeTag = The CIccTagDateTime object to be copied + ***************************************************************************** + */ +CIccTagDateTime &CIccTagDateTime::operator=(const CIccTagDateTime &DateTimeTag) +{ + if (&DateTimeTag == this) + return *this; + + memcpy(&m_DateTime, &DateTimeTag.m_DateTime, sizeof(m_DateTime)); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagDateTime::~CIccTagDateTime + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagDateTime::~CIccTagDateTime() +{ +} + + + +/** + **************************************************************************** + * Name: CIccTagDateTime::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagDateTime::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icDateTimeNumber) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + + icUInt32Number nsize = (size-2*sizeof(icUInt32Number))/sizeof(icUInt16Number); + + if (pIO->Read16(&m_DateTime,nsize) != (icInt32Number)nsize) + return false; + + return true; +} + + + +/** + **************************************************************************** + * Name: CIccTagDateTime::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagDateTime::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (pIO->Write16(&m_DateTime,6) != 6) + return false; + + return true; +} + + + +/** + **************************************************************************** + * Name: CIccTagDateTime::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagDateTime::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sDescription = "Date = "; + sprintf(buf, "%u-%u-%u\r\n", m_DateTime.month, m_DateTime.day, m_DateTime.year); + sDescription += buf; + + sDescription += "Time = "; + sprintf(buf, "%u:%u:%u\r\n", m_DateTime.hours, m_DateTime.minutes, m_DateTime.seconds); + sDescription += buf; +} + + +/** +****************************************************************************** +* Name: CIccTagDateTime::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagDateTime::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + CIccInfo Info; + + rv = icMaxStatus(rv, Info.CheckData(sReport, m_DateTime)); + + return rv; +} + + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::CIccTagColorantOrder + * + * Purpose: Constructor + * + * Args: + * nSize = number of channels + * + ***************************************************************************** + */ +CIccTagColorantOrder::CIccTagColorantOrder(int nsize/*=1*/) +{ + m_nCount = nsize; + if (m_nCount <1) + m_nCount = 1; + m_pData = (icUInt8Number*)calloc(nsize, sizeof(icUInt8Number)); +} + + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::CIccTagColorantOrder + * + * Purpose: Copy Constructor + * + * Args: + * ITCO = The CIccTagColorantOrder object to be copied + ***************************************************************************** + */ +CIccTagColorantOrder::CIccTagColorantOrder(const CIccTagColorantOrder &ITCO) +{ + m_nCount = ITCO.m_nCount; + + m_pData = (icUInt8Number*)calloc(m_nCount, sizeof(icUInt8Number)); + memcpy(m_pData, ITCO.m_pData, sizeof(icUInt8Number)*m_nCount); +} + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::operator= + * + * Purpose: Copy Operator + * + * Args: + * ColorantOrderTag = The CIccTagColorantOrder object to be copied + ***************************************************************************** + */ +CIccTagColorantOrder &CIccTagColorantOrder::operator=(const CIccTagColorantOrder &ColorantOrderTag) +{ + if (&ColorantOrderTag == this) + return *this; + + m_nCount = ColorantOrderTag.m_nCount; + + if (m_pData) + free(m_pData); + m_pData = (icUInt8Number*)calloc(m_nCount, sizeof(icUInt8Number)); + memcpy(m_pData, ColorantOrderTag.m_pData, sizeof(icUInt8Number)*m_nCount); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::~CIccTagColorantOrder + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagColorantOrder::~CIccTagColorantOrder() +{ + if (m_pData) + free(m_pData); +} + + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagColorantOrder::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nCount; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read32(&nCount)) + return false; + + icUInt32Number nNum = (size - 3*sizeof(icUInt32Number))/sizeof(icUInt8Number); + + if (nNum < nCount) + return false; + + SetSize((icUInt16Number)nCount); + + if (pIO->Read8(&m_pData[0],nNum) != (icInt32Number)nNum) + return false; + + return true; +} + + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagColorantOrder::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write32(&m_nCount)) + return false; + + if (pIO->Write8(&m_pData[0], m_nCount) != (icInt32Number)m_nCount) + return false; + + return true; +} + + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagColorantOrder::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sprintf(buf, "Colorant Count : %u\r\n", m_nCount); + sDescription += buf; + sDescription += "Order of Colorants:\r\n"; + + for (int i=0; i<(int)m_nCount; i++) { + sprintf(buf, "%u\r\n", m_pData[i]); + sDescription += buf; + } +} + + +/** + **************************************************************************** + * Name: CIccTagColorantOrder::SetSize + * + * Purpose: Sets the size of the data array. + * + * Args: + * nSize - number of channels, + * bZeroNew - flag to zero newly formed values + ***************************************************************************** + */ +void CIccTagColorantOrder::SetSize(icUInt16Number nSize, bool bZeroNew/*=true*/) +{ + if (m_nCount == nSize) + return; + + m_pData = (icUInt8Number*)realloc(m_pData, nSize*sizeof(icUInt8Number)); + if (bZeroNew && nSize > m_nCount) { + memset(&m_pData[m_nCount], 0, (nSize - m_nCount)*sizeof(icUInt8Number)); + } + + m_nCount = nSize; +} + + +/** +****************************************************************************** +* Name: CIccTagColorantOrder::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagColorantOrder::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + return rv; + } + + if (sig==icSigColorantTableTag) { + if (m_nCount != icGetSpaceSamples(pProfile->m_Header.colorSpace)) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Incorrect number of colorants.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + else if (sig==icSigColorantTableOutTag) { + if (m_nCount != icGetSpaceSamples(pProfile->m_Header.pcs)) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Incorrect number of colorants.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + else { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Unknown number of required colorants.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + + return rv; +} + + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::CIccTagColorantTable + * + * Purpose: Constructor + * + * Args: + * nSize = number of entries + * + ***************************************************************************** + */ +CIccTagColorantTable::CIccTagColorantTable(int nSize/*=1*/) +{ + m_nCount = nSize; + if (m_nCount<1) + m_nCount = 1; + + m_pData = (icColorantTableEntry*)calloc(nSize, sizeof(icColorantTableEntry)); +} + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::CIccTagColorantTable + * + * Purpose: Copy Constructor + * + * Args: + * ITCT = The CIccTagUnknown object to be copied + ***************************************************************************** + */ +CIccTagColorantTable::CIccTagColorantTable(const CIccTagColorantTable &ITCT) +{ + m_PCS = ITCT.m_PCS; + m_nCount = ITCT.m_nCount; + + m_pData = (icColorantTableEntry*)calloc(m_nCount, sizeof(icColorantTableEntry)); + memcpy(m_pData, ITCT.m_pData, m_nCount * sizeof(icColorantTableEntry)); +} + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::operator= + * + * Purpose: Copy Operator + * + * Args: + * ColorantTableTag = The CIccTagColorantTable object to be copied + ***************************************************************************** + */ +CIccTagColorantTable &CIccTagColorantTable::operator=(const CIccTagColorantTable &ColorantTableTag) +{ + if (&ColorantTableTag == this) + return *this; + + m_PCS = ColorantTableTag.m_PCS; + m_nCount = ColorantTableTag.m_nCount; + + if (m_pData) + free(m_pData); + m_pData = (icColorantTableEntry*)calloc(m_nCount, sizeof(icColorantTableEntry)); + memcpy(m_pData, ColorantTableTag.m_pData, m_nCount * sizeof(icColorantTableEntry)); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::~CIccTagColorantTable + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagColorantTable::~CIccTagColorantTable() +{ + if (m_pData) + free(m_pData); +} + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagColorantTable::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nCount; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number) + + sizeof(icColorantTableEntry) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read32(&nCount)) + return false; + + icUInt32Number nNum = (size - 3*sizeof(icUInt32Number))/sizeof(icColorantTableEntry); + icUInt32Number nNum8 = sizeof(m_pData->name); + icUInt32Number nNum16 = sizeof(m_pData->data)/sizeof(icUInt16Number); + + if (nNum < nCount) + return false; + + SetSize((icUInt16Number)nCount); + + for (icUInt32Number i=0; iRead8(&m_pData[i].name[0], nNum8) != (icInt32Number)nNum8) + return false; + + if (pIO->Read16(&m_pData[i].data[0], nNum16) != (icInt32Number)nNum16) + return false; + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagColorantTable::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write32(&m_nCount)) + return false; + + icUInt32Number nNum8 = sizeof(m_pData->name); + icUInt32Number nNum16 = sizeof(m_pData->data)/sizeof(icUInt16Number); + + for (icUInt32Number i=0; iWrite8(&m_pData[i].name[0],nNum8) != (icInt32Number)nNum8) + return false; + + if (pIO->Write16(&m_pData[i].data[0],nNum16) != (icInt32Number)nNum16) + return false; + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagColorantTable::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagColorantTable::Describe(std::string &sDescription) +{ + icChar buf[128]; + + icUInt32Number i, nLen, nMaxLen=0; + icFloatNumber Lab[3]; + + sprintf(buf, "BEGIN_COLORANTS %u\r\n", m_nCount); + sDescription += buf; + + for (i=0; inMaxLen) + nMaxLen =nLen; + } + sDescription += "# NAME "; + + if (m_PCS == icSigXYZData) { + sprintf(buf, "XYZ_X XYZ_Y XYZ_Z\r\n"); + sDescription += buf; + } + else { + sprintf(buf, "Lab_L Lab_a Lab_b\r\n"); + sDescription += buf; + } + for (i=0; i m_nCount) { + memset(&m_pData[m_nCount], 0, (nSize-m_nCount)*sizeof(icColorantTableEntry)); + } + m_nCount = nSize; +} + + +/** +****************************************************************************** +* Name: CIccTagColorantTable::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagColorantTable::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + return rv; + } + + + if (sig==icSigColorantTableOutTag) { + if (pProfile->m_Header.deviceClass!=icSigLinkClass) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Use of this tag is allowed only in DeviceLink Profiles.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + if (m_nCount != icGetSpaceSamples(pProfile->m_Header.pcs)) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Incorrect number of colorants.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + else { + if (m_nCount != icGetSpaceSamples(pProfile->m_Header.colorSpace)) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Incorrect number of colorants.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::CIccTagViewingConditions + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagViewingConditions::CIccTagViewingConditions() +{ + m_XYZIllum.X = 0; + m_XYZIllum.Y = 0; + m_XYZIllum.Z = 0; + + m_XYZSurround.X = 0; + m_XYZSurround.Y = 0; + m_XYZSurround.Z = 0; + + m_illumType = icIlluminantUnknown; +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::CIccTagViewingConditions + * + * Purpose: Copy Constructor + * + * Args: + * ITVC = The CIccTagViewingConditions object to be copied + ***************************************************************************** + */ +CIccTagViewingConditions::CIccTagViewingConditions(const CIccTagViewingConditions &ITVC) +{ + m_illumType = ITVC.m_illumType; + + memcpy(&m_XYZIllum, &ITVC.m_XYZIllum, sizeof(icXYZNumber)); + memcpy(&m_XYZSurround, &ITVC.m_XYZSurround, sizeof(icXYZNumber)); +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::operator= + * + * Purpose: Copy Operator + * + * Args: + * ViewCondTag = The CIccTagViewingConditions object to be copied + ***************************************************************************** + */ +CIccTagViewingConditions &CIccTagViewingConditions::operator=(const CIccTagViewingConditions &ViewCondTag) +{ + if (&ViewCondTag == this) + return *this; + + m_illumType = ViewCondTag.m_illumType; + + memcpy(&m_XYZIllum, &ViewCondTag.m_XYZIllum, sizeof(icXYZNumber)); + memcpy(&m_XYZSurround, &ViewCondTag.m_XYZSurround, sizeof(icXYZNumber)); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::~CIccTagViewingConditions + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagViewingConditions::~CIccTagViewingConditions() +{ +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagViewingConditions::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + 2*sizeof(icUInt32Number) + + 2*sizeof(icXYZNumber) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (pIO->Read32(&m_XYZIllum.X, 3) != 3) + return false; + + if (pIO->Read32(&m_XYZSurround.X, 3) != 3) + return false; + + if (!pIO->Read32(&m_illumType)) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagViewingConditions::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (pIO->Write32(&m_XYZIllum.X, 3) !=3) + return false; + + if (pIO->Write32(&m_XYZSurround.X, 3) !=3) + return false; + + if (!pIO->Write32(&m_illumType)) + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagViewingConditions::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagViewingConditions::Describe(std::string &sDescription) +{ + icChar buf[128]; + CIccInfo Fmt; + + sprintf(buf, "Illuminant Tristimulus values: X = %.4lf, Y = %.4lf, Z = %.4lf\r\n", + icFtoD(m_XYZIllum.X), + icFtoD(m_XYZIllum.Y), + icFtoD(m_XYZIllum.Z)); + sDescription += buf; + + sprintf(buf, "Surround Tristimulus values: X = %.4lf, Y = %.4lf, Z = %.4lf\r\n", + icFtoD(m_XYZSurround.X), + icFtoD(m_XYZSurround.Y), + icFtoD(m_XYZSurround.Z)); + sDescription += buf; + + sDescription += "Illuminant Type: "; + + sDescription += Fmt.GetIlluminantName(m_illumType); + sDescription += "\r\n"; + +} + + +/** +****************************************************************************** +* Name: CIccTagViewingConditions::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagViewingConditions::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + rv = icMaxStatus(rv, Info.CheckData(sReport, m_XYZIllum)); + rv = icMaxStatus(rv, Info.CheckData(sReport, m_XYZSurround)); + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::CIccProfileDescText + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccProfileDescText::CIccProfileDescText() +{ + m_pTag = NULL; + m_bNeedsPading = false; +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::CIccProfileDescText + * + * Purpose: Copy Constructor + * + * Args: + * IPDC = The CIccTagUnknown object to be copied + ***************************************************************************** + */ +CIccProfileDescText::CIccProfileDescText(const CIccProfileDescText &IPDC) +{ + if (IPDC.m_pTag) { + m_pTag = IPDC.m_pTag->NewCopy(); + m_bNeedsPading = IPDC.m_bNeedsPading; + } + else { + m_pTag = NULL; + m_bNeedsPading = false; + } +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::operator= + * + * Purpose: Copy Operator + * + * Args: + * ProfDescText = The CIccProfileDescText object to be copied + ***************************************************************************** + */ +CIccProfileDescText &CIccProfileDescText::operator=(const CIccProfileDescText &ProfDescText) +{ + if (&ProfDescText == this) + return *this; + + if (m_pTag) + delete m_pTag; + + if (ProfDescText.m_pTag) { + m_pTag = ProfDescText.m_pTag->NewCopy(); + m_bNeedsPading = ProfDescText.m_bNeedsPading; + } + else { + m_pTag = NULL; + m_bNeedsPading = false; + } + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::~CIccProfileDescText + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccProfileDescText::~CIccProfileDescText() +{ + if (m_pTag) + delete m_pTag; +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::SetType + * + * Purpose: Sets the type of the profile description text. Could be either + * a MultiLocalizedUnicodeType or a TextDescriptionType. + * + * Args: + * nType = the tag type signature + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccProfileDescText::SetType(icTagTypeSignature nType) +{ + if (m_pTag) { + if (m_pTag->GetType() == nType) + return true; + + delete m_pTag; + } + + if (nType == icSigMultiLocalizedUnicodeType || + nType == icSigTextDescriptionType) + m_pTag = CIccTag::Create(nType); + else + m_pTag = NULL; + + return(m_pTag != NULL); +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::SetType + * + * Purpose: Gets the type of the profile description text. Could be either + * a MultiLocalizedUnicodeType or a TextDescriptionType. + * + ***************************************************************************** + */ +icTagTypeSignature CIccProfileDescText::GetType() const +{ + if (m_pTag) + return m_pTag->GetType(); + + return icSigUnknownType; +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccProfileDescText::Describe(std::string &sDescription) +{ + if (m_pTag) + m_pTag->Describe(sDescription); +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccProfileDescText::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nPos; + + //Check for description tag type signature + nPos = pIO->Tell(); + + if ((nPos&0x03) != 0) + m_bNeedsPading = true; + + if (!pIO->Read32(&sig)) + return false; + pIO->Seek(nPos, icSeekSet); + + if (sig==icSigTextDescriptionType) + m_bNeedsPading = false; + + if (!SetType(sig)) { + //We couldn't find it, but we may be looking in the wrong place + //Re-Syncronize on a 4 byte boundary + pIO->Sync32(); + + nPos = pIO->Tell(); + if (!pIO->Read32(&sig)) + return false; + pIO->Seek(nPos, icSeekSet); + + if (!SetType(sig)) { + return false; + } + } + + if (m_pTag) { + return m_pTag->Read(size, pIO); + } + + return false; +} + + +/** + **************************************************************************** + * Name: CIccProfileDescText::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccProfileDescText::Write(CIccIO *pIO) +{ + if (!m_pTag) + return false; + + if (m_pTag->Write(pIO)) { + if (m_pTag->GetType() != icSigTextDescriptionType) + return pIO->Align32(); + else + return true; + } + + return false; +} + + + +/** + **************************************************************************** + * Name: CIccProfileDescStruct::CIccProfileDescStruct + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccProfileDescStruct::CIccProfileDescStruct() +{ +} + + +/** + **************************************************************************** + * Name: CIccProfileDescStruct::CIccProfileDescStruct + * + * Purpose: Copy Constructor + * + * Args: + * IPDS = The CIccProfileDescStruct object to be copied + ***************************************************************************** + */ +CIccProfileDescStruct::CIccProfileDescStruct(const CIccProfileDescStruct &IPDS) +{ + m_deviceMfg = IPDS.m_deviceMfg; + m_deviceModel = IPDS.m_deviceModel; + m_attributes = IPDS.m_attributes; + m_technology = IPDS.m_technology; + m_deviceMfgDesc = IPDS.m_deviceMfgDesc; + m_deviceModelDesc = IPDS.m_deviceModelDesc; +} + + + +/** + **************************************************************************** + * Name: CIccProfileDescStruct::operator= + * + * Purpose: Copy Operator + * + * Args: + * ProfDescStruct = The CIccProfileDescStruct object to be copied + ***************************************************************************** + */ +CIccProfileDescStruct &CIccProfileDescStruct::operator=(const CIccProfileDescStruct &ProfDescStruct) +{ + if (&ProfDescStruct == this) + return *this; + + m_deviceMfg = ProfDescStruct.m_deviceMfg; + m_deviceModel = ProfDescStruct.m_deviceModel; + m_attributes = ProfDescStruct.m_attributes; + m_technology = ProfDescStruct.m_technology; + m_deviceMfgDesc = ProfDescStruct.m_deviceMfgDesc; + m_deviceModelDesc = ProfDescStruct.m_deviceModelDesc; + + return *this; +} + + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::CIccTagProfileSeqDesc + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagProfileSeqDesc::CIccTagProfileSeqDesc() +{ + m_Descriptions = new(CIccProfileSeqDesc); +} + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::CIccTagProfileSeqDesc + * + * Purpose: Copy Constructor + * + * Args: + * ITPSD = The CIccTagProfileSeqDesc object to be copied + ***************************************************************************** + */ +CIccTagProfileSeqDesc::CIccTagProfileSeqDesc(const CIccTagProfileSeqDesc &ITPSD) +{ + m_Descriptions = new(CIccProfileSeqDesc); + *m_Descriptions = *ITPSD.m_Descriptions; +} + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::operator= + * + * Purpose: Copy Operator + * + * Args: + * ProfSeqDescTag = The CIccTagProfileSeqDesc object to be copied + ***************************************************************************** + */ +CIccTagProfileSeqDesc &CIccTagProfileSeqDesc::operator=(const CIccTagProfileSeqDesc &ProfSeqDescTag) +{ + if (&ProfSeqDescTag == this) + return *this; + + *m_Descriptions = *ProfSeqDescTag.m_Descriptions; + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::~CIccTagProfileSeqDesc + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagProfileSeqDesc::~CIccTagProfileSeqDesc() +{ + delete m_Descriptions; +} + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagProfileSeqDesc::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nCount, nEnd; + + nEnd = pIO->Tell() + size; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number)*2 > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read32(&nCount)) + return false; + + if (!nCount) + return true; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number)*2 + + sizeof(CIccProfileDescStruct) > size) + return false; + + icUInt32Number i, nPos; + CIccProfileDescStruct ProfileDescStruct; + + for (i=0; iRead32(&ProfileDescStruct.m_deviceMfg) || + !pIO->Read32(&ProfileDescStruct.m_deviceModel) || + !pIO->Read64(&ProfileDescStruct.m_attributes) || + !pIO->Read32(&ProfileDescStruct.m_technology)) + return false; + + nPos = pIO->Tell(); + + if (!ProfileDescStruct.m_deviceMfgDesc.Read(nEnd - nPos, pIO)) + return false; + + nPos = pIO->Tell(); + if (!ProfileDescStruct.m_deviceModelDesc.Read(nEnd - nPos, pIO)) + return false; + + m_Descriptions->push_back(ProfileDescStruct); + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagProfileSeqDesc::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt32Number nCount=(icUInt32Number)m_Descriptions->size(); + + if (!pIO) { + return false; + } + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write32(&nCount)) + return false; + + CIccProfileSeqDesc::iterator i; + + for (i=m_Descriptions->begin(); i!=m_Descriptions->end(); i++) { + + if (!pIO->Write32(&i->m_deviceMfg) || + !pIO->Write32(&i->m_deviceModel) || + !pIO->Write64(&i->m_attributes) || + !pIO->Write32(&i->m_technology)) + return false; + + if (!i->m_deviceMfgDesc.Write(pIO) || + !i->m_deviceModelDesc.Write(pIO)) + return false; + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagProfileSeqDesc::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagProfileSeqDesc::Describe(std::string &sDescription) +{ + CIccProfileSeqDesc::iterator i; + icChar buf[128], buf2[28]; + icUInt32Number count=0; + + sprintf(buf, "Number of Profile Description Structures: %u\r\n", (icUInt32Number)m_Descriptions->size()); + sDescription += buf; + + for (i=m_Descriptions->begin(); i!=m_Descriptions->end(); i++, count++) { + sDescription += "\r\n"; + + sprintf(buf, "Profile Description Structure Number [%u] follows:\r\n", count+1); + sDescription += buf; + + sprintf(buf, "Device Manufacturer Signature: %s\r\n", icGetSig(buf2, i->m_deviceMfg, false)); + sDescription += buf; + + sprintf(buf, "Device Model Signature: %s\r\n", icGetSig(buf2, i->m_deviceModel, false)); + sDescription += buf; + + sprintf(buf, "Device Attributes: %08x%08x\r\n", (icUInt32Number)(i->m_attributes >> 32), (icUInt32Number)(i->m_attributes)); + sDescription += buf; + + sprintf(buf, "Device Technology Signature: %s\r\n", icGetSig(buf2, i->m_technology, false)); + sDescription += buf; + + sprintf(buf, "Description of device manufacturer: \r\n"); + sDescription += buf; + i->m_deviceMfgDesc.Describe(sDescription); + + sprintf(buf, "Description of device model: \r\n"); + sDescription += buf; + i->m_deviceModelDesc.Describe(sDescription); + } +} + + +/** +****************************************************************************** +* Name: CIccTagProfileSeqDesc::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagProfileSeqDesc::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + char buf[128]; + std::string sSigName = Info.GetSigName(sig); + + CIccProfileSeqDesc::iterator i; + for (i=m_Descriptions->begin(); i!=m_Descriptions->end(); i++) { + switch(i->m_technology) { + case 0x00000000: //Technology not defined + case icSigFilmScanner: + case icSigDigitalCamera: + case icSigReflectiveScanner: + case icSigInkJetPrinter: + case icSigThermalWaxPrinter: + case icSigElectrophotographicPrinter: + case icSigElectrostaticPrinter: + case icSigDyeSublimationPrinter: + case icSigPhotographicPaperPrinter: + case icSigFilmWriter: + case icSigVideoMonitor: + case icSigVideoCamera: + case icSigProjectionTelevision: + case icSigCRTDisplay: + case icSigPMDisplay: + case icSigAMDisplay: + case icSigPhotoCD: + case icSigPhotoImageSetter: + case icSigGravure: + case icSigOffsetLithography: + case icSigSilkscreen: + case icSigFlexography: + break; + + default: + { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sprintf(buf, " - %s: Unknown Technology.\r\n", Info.GetSigName(i->m_technology)); + sReport += buf; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + } + + if (i->m_deviceMfgDesc.m_bNeedsPading) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + + sReport += " Contains non-aligned deviceMfgDesc text tag information\r\n"; + + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + if (i->m_deviceModelDesc.m_bNeedsPading) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + + sReport += " Contains non-aligned deviceModelDesc text tag information\r\n"; + + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + rv = icMaxStatus(rv, i->m_deviceMfgDesc.GetTag()->Validate(sig, sReport, pProfile)); + rv = icMaxStatus(rv, i->m_deviceModelDesc.GetTag()->Validate(sig, sReport, pProfile)); + } + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccResponseCurveStruct::CIccResponseCurveStruct + * + * Purpose: Constructor + * + * Args: + * nChannels = number of channels + * + ***************************************************************************** + */ +CIccResponseCurveStruct::CIccResponseCurveStruct(icUInt16Number nChannels/*=0*/) +{ + m_nChannels = nChannels; + m_maxColorantXYZ = (icXYZNumber*)calloc(nChannels, sizeof(icXYZNumber)); + m_Response16ListArray = new CIccResponse16List[nChannels]; +} + + +/** + **************************************************************************** + * Name: CIccResponseCurveStruct::CIccResponseCurveStruct + * + * Purpose: Constructor + * + * Args: + * sig = measurement unit signature indicating the type of measurement data, + * nChannels = number of channels + ***************************************************************************** + */ +CIccResponseCurveStruct::CIccResponseCurveStruct(icMeasurementUnitSig sig,icUInt16Number nChannels/*=0*/) +{ + m_nChannels = nChannels; + m_measurementUnitSig = sig; + m_maxColorantXYZ = (icXYZNumber*)calloc(nChannels, sizeof(icXYZNumber)); + m_Response16ListArray = new CIccResponse16List[nChannels]; +} + +/** + **************************************************************************** + * Name: CIccResponseCurveStruct::CIccResponseCurveStruct + * + * Purpose: Copy Constructor + * + * Args: + * IRCS = The CIccTagUnknown object to be copied + ***************************************************************************** + */ +CIccResponseCurveStruct::CIccResponseCurveStruct(const CIccResponseCurveStruct &IRCS) +{ + m_nChannels = IRCS.m_nChannels; + m_measurementUnitSig = IRCS.m_measurementUnitSig; + + m_maxColorantXYZ = (icXYZNumber*)calloc(m_nChannels, sizeof(icXYZNumber)); + memcpy(m_maxColorantXYZ, IRCS.m_maxColorantXYZ, m_nChannels*sizeof(icXYZNumber)); + + m_Response16ListArray = new CIccResponse16List[m_nChannels]; + for (icUInt32Number i=0; i size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&m_measurementUnitSig)) + return false; + + icUInt32Number* nMeasurements = new icUInt32Number[m_nChannels]; + + if (pIO->Read32(&nMeasurements[0],m_nChannels) != m_nChannels) + return false; + + icUInt32Number nNum32 = m_nChannels*sizeof(icXYZNumber)/sizeof(icS15Fixed16Number); + if (pIO->Read32(&m_maxColorantXYZ[0], nNum32) != (icInt32Number)nNum32) + return false; + + icResponse16Number nResponse16; + CIccResponse16List nResponseList; + + for (int i = 0; iRead16(&nResponse16.deviceCode) || + !pIO->Read16(&nResponse16.reserved) || + !pIO->Read32(&nResponse16.measurementValue)) + return false; + nResponseList.push_back(nResponse16); + } + m_Response16ListArray[i] = nResponseList; + } + + delete [] nMeasurements; + return true; +} + + +/** + **************************************************************************** + * Name: CIccResponseCurveStruct::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccResponseCurveStruct::Write(CIccIO *pIO) +{ + if (!m_nChannels) + return false; + + icMeasurementUnitSig sig = GetMeasurementType(); + + if (!pIO) { + return false; + } + + if (!pIO->Write32(&sig)) + return false; + + if (m_nChannels) { + + icUInt32Number* nMeasurements = new icUInt32Number[m_nChannels]; + for (int i=0; iWrite32(&nMeasurements[0],m_nChannels) != m_nChannels) + return false; + delete [] nMeasurements; + + icUInt32Number nNum32 = m_nChannels*sizeof(icXYZNumber)/sizeof(icS15Fixed16Number); + if (pIO->Write32(&m_maxColorantXYZ[0], nNum32) != (icInt32Number)nNum32) + return false; + } + else + return false; + + CIccResponse16List nResponseList; + CIccResponse16List::iterator j; + + for (int i = 0; iWrite16(&j->deviceCode) || + !pIO->Write16(&j->reserved) || + !pIO->Write32(&j->measurementValue)) + return false; + } + nResponseList.clear(); + } + + return true; +} + + +/** + **************************************************************************** + * Name: CIccResponseCurveStruct::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccResponseCurveStruct::Describe(std::string &sDescription) +{ + icChar buf[128]; + CIccInfo Fmt; + CIccResponse16List nResponseList; + CIccResponse16List::iterator j; + + sDescription += "Measurement Unit: "; + sDescription += Fmt.GetMeasurementUnit((icSignature)GetMeasurementType()); sDescription += "\r\n"; + + + for (int i=0; ideviceCode, icFtoD(j->measurementValue)); + sDescription += buf; + } + } +} + + +/** +****************************************************************************** +* Name: CIccResponseCurveStruct::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccResponseCurveStruct::Validate(std::string &sReport) const +{ + icValidateStatus rv = icValidateOK; + + CIccInfo Info; + std::string sSigName = Info.GetSigName(m_measurementUnitSig); + switch(m_measurementUnitSig) { + case icSigStatusA: + case icSigStatusE: + case icSigStatusI: + case icSigStatusT: + case icSigStatusM: + case icSigDN: + case icSigDNP: + case icSigDNN: + case icSigDNNP: + break; + + default: + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Unknown measurement unit signature.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + if (!m_nChannels) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Incorrect number of channels.\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + return rv; + } + for (int i=0; iinited = false; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::CIccTagResponseCurveSet16 + * + * Purpose: Copy Constructor + * + * Args: + * ITRCS = The CIccTagResponseCurveSet16 object to be copied + ***************************************************************************** + */ +CIccTagResponseCurveSet16::CIccTagResponseCurveSet16(const CIccTagResponseCurveSet16 &ITRCS) +{ + m_nChannels = ITRCS.m_nChannels; + m_ResponseCurves = new(CIccResponseCurveSet); + *m_ResponseCurves = *ITRCS.m_ResponseCurves; + m_Curve = new(CIccResponseCurveSetIter); + *m_Curve = *ITRCS.m_Curve; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::operator= + * + * Purpose: Copy Operator + * + * Args: + * RespCurveSet16Tag = The CIccTagResponseCurveSet16 object to be copied + ***************************************************************************** + */ +CIccTagResponseCurveSet16 &CIccTagResponseCurveSet16::operator=(const CIccTagResponseCurveSet16 &RespCurveSet16Tag) +{ + if (&RespCurveSet16Tag == this) + return *this; + + if (!m_ResponseCurves->empty()) + m_ResponseCurves->clear(); + + m_nChannels = RespCurveSet16Tag.m_nChannels; + *m_ResponseCurves = *RespCurveSet16Tag.m_ResponseCurves; + *m_Curve = *RespCurveSet16Tag.m_Curve; + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::~CIccTagResponseCurveSet16 + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagResponseCurveSet16::~CIccTagResponseCurveSet16() +{ + if (!m_ResponseCurves->empty()) + m_ResponseCurves->clear(); + + delete m_ResponseCurves; + delete m_Curve; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagResponseCurveSet16::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number)*4 + + sizeof(CIccResponseCurveStruct) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved)) + return false; + + icUInt16Number nCountMeasmntTypes; + + if (!pIO->Read16(&m_nChannels) || + !pIO->Read16(&nCountMeasmntTypes)) + return false; + + + icUInt32Number* nOffset = new icUInt32Number[nCountMeasmntTypes]; + + if (pIO->Read32(&nOffset[0], nCountMeasmntTypes) != nCountMeasmntTypes) + return false; + + delete [] nOffset; + + CIccResponseCurveStruct entry; + + for (icUInt16Number i=0; ipush_back(entry); + } + m_Curve->inited = false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagResponseCurveSet16::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt16Number nCountMeasmntTypes = (icUInt16Number)m_ResponseCurves->size(); + + if (!pIO) { + return false; + } + + icUInt32Number startPos = pIO->GetLength(); + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved)) + return false; + + + if (!pIO->Write16(&m_nChannels) || + !pIO->Write16(&nCountMeasmntTypes)) + return false; + + icUInt32Number offsetPos = pIO->GetLength(); + icUInt32Number* nOffset = new icUInt32Number[nCountMeasmntTypes]; + + + int j; + for (j=0; jWrite32(&nOffset[j])) + return false; + } + + CIccResponseCurveSet::iterator i; + + for (i=m_ResponseCurves->begin(), j=0; i!=m_ResponseCurves->end(); i++, j++) { + nOffset[j] = pIO->GetLength() - startPos; + if (!i->Write(pIO)) + return false; + } + + icUInt32Number curPOs = pIO->GetLength(); + + pIO->Seek(offsetPos,icSeekSet); + + for (j=0; jWrite32(&nOffset[j])) + return false; + } + + pIO->Seek(curPOs,icSeekSet); + delete [] nOffset; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::Describe + * + * Purpose: Dump data associated with the tag to a string + * + * Args: + * sDescription - string to concatenate tag dump to + ***************************************************************************** + */ +void CIccTagResponseCurveSet16::Describe(std::string &sDescription) +{ + CIccResponseCurveSet::iterator i; + icChar buf[128]; + + sprintf(buf, "Number of Channels: %u\r\n", m_nChannels); + sDescription += buf; + + sprintf(buf, "Number of Measurement Types used: %u\r\n", (icUInt32Number)m_ResponseCurves->size()); + sDescription += buf; + + int count = 0; + for (i=m_ResponseCurves->begin(); i!=m_ResponseCurves->end(); i++, count++) { + sDescription += "\r\n"; + + sprintf(buf, "Response Curve for measurement type [%u] follows:\r\n", count+1); + sDescription += buf; + + i->Describe(sDescription); + } +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::SetNumChannels + * + * Purpose: Sets the number of channels. This will delete any prior Response + * curves from the set. + * + * Args: + * nChannels = number of channels + ***************************************************************************** + */ +void CIccTagResponseCurveSet16::SetNumChannels(icUInt16Number nChannels) +{ + m_nChannels = nChannels; + + if (!m_ResponseCurves->empty()) + m_ResponseCurves->clear(); +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::NewResponseCurves + * + * Purpose: Creates and adds a new set of response curves to the list. + * SetNumChannels() must be called before calling this function. + * + * Args: + * sig = measurement unit signature + ***************************************************************************** + */ +CIccResponseCurveStruct *CIccTagResponseCurveSet16::NewResponseCurves(icMeasurementUnitSig sig) +{ + if (!m_nChannels) + return NULL; + + CIccResponseCurveStruct *pResponseCurveStruct; + pResponseCurveStruct = GetResponseCurves(sig); + + if (pResponseCurveStruct) + return pResponseCurveStruct; + + CIccResponseCurveStruct entry; + entry = CIccResponseCurveStruct(sig, m_nChannels); + m_ResponseCurves->push_back(entry); + m_Curve->inited = false; + + return GetResponseCurves(sig); +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::GetResponseCurves + * + * Purpose: Returns pointer to the requested set of response curves + * + * Args: + * sig = measurement unit signature of the response curve set desired + ***************************************************************************** + */ +CIccResponseCurveStruct *CIccTagResponseCurveSet16::GetResponseCurves(icMeasurementUnitSig sig) +{ + if (!m_nChannels) + return NULL; + + CIccResponseCurveSet::iterator i; + + for (i=m_ResponseCurves->begin(); i!=m_ResponseCurves->end(); i++) { + if (i->GetMeasurementType() == sig) + return (i->GetThis()); + } + + return NULL; +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::GetFirstCurves + * + * Purpose: Returns pointer to the first set of response curves in the list. + * + ***************************************************************************** + */ +CIccResponseCurveStruct *CIccTagResponseCurveSet16::GetFirstCurves() +{ + if (!m_Curve) + return NULL; + + m_Curve->item = m_ResponseCurves->begin(); + if (m_Curve->item == m_ResponseCurves->end()) { + m_Curve->inited = false; + return NULL; + } + m_Curve->inited = true; + return m_Curve->item->GetThis(); +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::GetNextCurves + * + * Purpose: Serves as an iterator for the list containing response curves. + * GetFirstCurves() must be called before calling this function. + * + ***************************************************************************** + */ +CIccResponseCurveStruct *CIccTagResponseCurveSet16::GetNextCurves() +{ + if (!m_Curve || !m_Curve->inited) + return NULL; + + m_Curve->item++; + if (m_Curve->item==m_ResponseCurves->end()) { + m_Curve->inited = false; + return NULL; + } + return m_Curve->item->GetThis(); +} + + +/** + **************************************************************************** + * Name: CIccTagResponseCurveSet16::GetNumResponseCurveTypes + * + * Purpose: Get the number of response curve types. + * + ***************************************************************************** + */ +icUInt16Number CIccTagResponseCurveSet16::GetNumResponseCurveTypes() const +{ + return(icUInt16Number) m_ResponseCurves->size(); +} + + +/** +****************************************************************************** +* Name: CIccTagResponseCurveSet16::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagResponseCurveSet16::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + return rv; + } + + if (m_nChannels!=icGetSpaceSamples(pProfile->m_Header.colorSpace)) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Incorrect number of channels.\r\n"; + } + + if (!GetNumResponseCurveTypes()) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Empty Tag!.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + else { + CIccResponseCurveSet::iterator i; + for (i=m_ResponseCurves->begin(); i!=m_ResponseCurves->end(); i++) { + rv = icMaxStatus(rv, i->Validate(sReport)); + } + } + + return rv; +} + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccTagBasic.h b/library/src/main/cpp/icc/IccTagBasic.h new file mode 100644 index 00000000..ebc62172 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagBasic.h @@ -0,0 +1,1187 @@ +/** @file + File: IccTagBasic.h + + Contains: Header for implementation of the CIccTag class + and inherited classes + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCTAGBASIC_H) +#define _ICCTAGBASIC_H + +#include +#include +#include "IccDefs.h" +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +class CIccIO; + +class ICCPROFLIB_API CIccProfile; + +class IIccExtensionTag +{ +public: + virtual const char *GetExtClassName() const=0; + virtual const char *GetExtDerivedClassName() const=0; +}; + +/** + *********************************************************************** + * Class: CIccTag + * + * Purpose: + * CIccTag is the base class that all Icc Tags are derived + * from. It defines basic tag functionality, and provides + * a static function that acts as an object construction + * factory. + *********************************************************************** + */ +class ICCPROFLIB_API CIccTag +{ +public: + CIccTag(); + + /** + * Function: NewCopy(sDescription) + * Each derived tag will implement it's own NewCopy() function. + * + * Parameter(s): + * none + * + * Returns a new CIccTag object that is a copy of this object. + */ + virtual CIccTag* NewCopy() const {return new CIccTag;} + + virtual ~CIccTag(); + + /** + * Function: GetType() + * + * Purpose: Get Tag Type. + * Each derived tag will implement it's own GetType() function. + */ + virtual icTagTypeSignature GetType() const { return icMaxEnumType; } + virtual bool IsArrayType() { return false; } + virtual bool IsMBBType() { return false; } + + virtual const icChar *GetClassName() const { return "CIccTag"; } + + static CIccTag* Create(icTagTypeSignature sig); + + virtual IIccExtensionTag* GetExtension() {return NULL;} + + /** + * Function: IsSupported(size, pIO) - Check if tag fully + * supported for apply purposes. By Default inherited + * classes are supported. Unknown tag types are not + * supported. + * + * Returns true if tag type is supported. + */ + virtual bool IsSupported() { return true; } + + /** + * Function: Read(size, pIO) - Read tag from file. + * Each derived tag will implement it's own Read() function. + * + * Parameter(s): + * size - number of bytes in tag including the type signature. + * pIO - IO object used to read in tag. The IO object should + * already be initialized to point to the begining of + * the tag. + * + * Returns true if Read is successful. + */ + virtual bool Read(icUInt32Number size, CIccIO *pIO) { return false; } + + /** + * Function: Write(pIO) + * Each derived tag will implement it's own Write() function. + * + * Parameter(s): + * pIO - IO object used to write a tag. The IO object should + * already be initialized to point to the begining of + * the tag. + * + * Returns true if Write is successful. + */ + virtual bool Write(CIccIO *pIO) { return false; } + + /** + * Function: Describe(sDescription) + * Each derived tag will implement it's own Describe() function. + * + * Parameter(s): + * sDescription - A string to put the tag's description into. + */ + virtual void Describe(std::string &sDescription) { sDescription.empty(); } + + /** + ****************************************************************************** + * Function: Validate + * Each derived tag will implement it's own IsValid() function + * + * Parameter(s): + * sig - signature of tag being validated, + * sDescription - A string to put tag validation report. + */ + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + //All tags start with a reserved value. Allocate a place to put it. + icUInt32Number m_nReserved; +}; + + +/** +**************************************************************************** +* Class: IccTagUnknown +* +* Purpose: The general purpose I don't know tag. +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagUnknown : public CIccTag +{ +public: + CIccTagUnknown(); + CIccTagUnknown(const CIccTagUnknown &ITU); + CIccTagUnknown &operator=(const CIccTagUnknown &UnknownTag); + virtual CIccTag* NewCopy() const {return new CIccTagUnknown(*this);} + virtual ~CIccTagUnknown(); + + virtual bool IsSupported() { return false; } + + virtual icTagTypeSignature GetType() const { return m_nType; } + virtual const icChar *GetClassName() const { return "CIccTagUnknown"; } + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual void Describe(std::string &sDescription); + + +protected: + icTagTypeSignature m_nType; + icUInt8Number *m_pData; + icUInt32Number m_nSize; +}; + + +/** +**************************************************************************** +* Class: CIccTagText() +* +* Purpose: The textType ICC tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagText : public CIccTag +{ +public: + CIccTagText(); + CIccTagText(const CIccTagText &ITT); + CIccTagText &operator=(const CIccTagText &TextTag); + virtual CIccTag* NewCopy() const {return new CIccTagText(*this);} + virtual ~CIccTagText(); + + virtual icTagTypeSignature GetType() const { return icSigTextType; } + virtual const icChar *GetClassName() const { return "CIccTagText"; } + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual void Describe(std::string &sDescription); + + const icChar *GetText() const { return m_szText; } + void SetText(const icChar *szText); + const icChar *operator=(const icChar *szText); + + icChar *GetBuffer(icUInt32Number nSize); + void Release(); + icUInt32Number Capacity() const { return m_nBufSize; } + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icChar *m_szText; + icUInt32Number m_nBufSize; +}; + +/** +**************************************************************************** +* Class: CIccTagTextDescription() +* +* Purpose: The textType ICC tag +**************************************************************************** +*/ +class ICCPROFLIB_API CIccTagTextDescription : public CIccTag +{ +public: + CIccTagTextDescription(); + CIccTagTextDescription(const CIccTagTextDescription &ITTD); + CIccTagTextDescription &operator=(const CIccTagTextDescription &TextDescTag); + virtual CIccTag* NewCopy() const {return new CIccTagTextDescription(*this);} + virtual ~CIccTagTextDescription(); + + virtual icTagTypeSignature GetType() const { return icSigTextDescriptionType; } + virtual const icChar *GetClassName() const { return "CIccTagTextDescription"; } + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual void Describe(std::string &sDescription); + + const icChar *GetText() const { return m_szText; } + void SetText(const icChar *szText); + const icChar *operator=(const icChar *szText); + + icChar *GetBuffer(icUInt32Number nSize); + void Release(); + icUInt32Number Capacity() const { return m_nASCIISize; } + + icUInt16Number *GetUnicodeBuffer(icUInt32Number nSize); + void ReleaseUnicode(); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + +protected: + icChar *m_szText; + icUInt32Number m_nASCIISize; + + icUInt16Number *m_uzUnicodeText; + icUInt32Number m_nUnicodeSize; + icUInt32Number m_nUnicodeLanguageCode; + + icUInt8Number m_szScriptText[67]; + icUInt8Number m_nScriptSize; + icUInt16Number m_nScriptCode; + + bool m_bInvalidScript; +}; + + +/** +**************************************************************************** +* Class: CIccTagSignature +* +* Purpose: The signatureType tag +**************************************************************************** +*/ +class ICCPROFLIB_API CIccTagSignature : public CIccTag +{ +public: + CIccTagSignature(); + CIccTagSignature(const CIccTagSignature &ITS); + CIccTagSignature &operator=(const CIccTagSignature &SignatureTag); + virtual CIccTag* NewCopy() const {return new CIccTagSignature(*this);} + virtual ~CIccTagSignature(); + + virtual icTagTypeSignature GetType() const { return icSigSignatureType; } + virtual const icChar *GetClassName() const { return "CIccTagSignature"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + icUInt32Number GetValue() const { return m_nSig; } + void SetValue(icUInt32Number sig) { m_nSig = sig; } + icUInt32Number operator=(icUInt32Number sig) { SetValue(sig); return m_nSig; } + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt32Number m_nSig; +}; + +typedef struct +{ + icChar rootName[32]; + icFloatNumber pcsCoords[3]; + icFloatNumber deviceCoords[icAny]; +} SIccNamedColorEntry; + +typedef struct { + icFloatNumber lab[3]; +} SIccNamedLabEntry; + +/** +**************************************************************************** +* Class: CIccTagNamedColor2 +* +* Purpose: the NamedColor2 tag - an array of Named Colors +**************************************************************************** +*/ +class ICCPROFLIB_API CIccTagNamedColor2 : public CIccTag +{ +public: + CIccTagNamedColor2(int nSize=1, int nDeviceCoords=0); + CIccTagNamedColor2(const CIccTagNamedColor2 &ITNC); + CIccTagNamedColor2 &operator=(const CIccTagNamedColor2 &NamedColor2Tag); + virtual CIccTag* NewCopy() const {return new CIccTagNamedColor2(*this);} + virtual ~CIccTagNamedColor2(); + + virtual icTagTypeSignature GetType() const { return icSigNamedColor2Type; } + virtual const icChar *GetClassName() const { return "CIccTagNamedColor2"; } + + virtual bool UseLegacyPCS() const { return true; } //Treat Lab Encoding differently? + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + const icChar *GetPrefix() const { return m_szPrefix; } + void SetPrefix(const icChar *szPrefix); + + const icChar *GetSufix() const { return m_szSufix; } + void SetSufix(const icChar *szSufix); + + icUInt32Number GetVendorFlags() const { return m_nVendorFlags; } + void SetVendorFlags(icUInt32Number nVendorFlags) {m_nVendorFlags = nVendorFlags;} + + //The following Find functions return the zero based index of the color + //or -1 to indicate that the color was not found. + icInt32Number FindColor(const icChar *szColor) const; + icInt32Number FindRootColor(const icChar *szRootColor) const; + icInt32Number FindDeviceColor(icFloatNumber *pDevColor) const; + icInt32Number FindPCSColor(icFloatNumber *pPCS, icFloatNumber dMinDE=1000.0); + + bool InitFindCachedPCSColor(); + //FindPCSColor returns the zero based index of the color or -1 to indicate that the color was not found. + //InitFindPCSColor must be called before FindPCSColor + icInt32Number FindCachedPCSColor(icFloatNumber *pPCS, icFloatNumber dMinDE=1000.0) const; + + ///Call ResetPCSCache() if entry values change between calls to FindPCSColor() + void ResetPCSCache(); + + bool GetColorName(std::string &sColorName, icInt32Number index) const; + SIccNamedColorEntry &operator[](icUInt32Number index) const {return *(SIccNamedColorEntry*)((icUInt8Number*)m_NamedColor + index * m_nColorEntrySize);} + SIccNamedColorEntry *GetEntry(icUInt32Number index) const {return (SIccNamedColorEntry*)((icUInt8Number*)m_NamedColor + index * m_nColorEntrySize);} + + icUInt32Number GetSize() const { return m_nSize; } + icUInt32Number GetDeviceCoords() const {return m_nDeviceCoords;} + void SetSize(icUInt32Number nSize, icInt32Number nDeviceCoords=-1); + + virtual void SetColorSpaces(icColorSpaceSignature csPCS, icColorSpaceSignature csDevice); + icColorSpaceSignature GetPCS() const {return m_csPCS;} + icColorSpaceSignature GetDeviceSpace() const {return m_csDevice;} + + icFloatNumber NegClip(icFloatNumber v) const; + icFloatNumber UnitClip(icFloatNumber v) const; + + void Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src) const; + void Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src) const; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icChar m_szPrefix[32]; + icChar m_szSufix[32]; + + SIccNamedColorEntry *m_NamedColor; + SIccNamedLabEntry *m_NamedLab; ///For quick response of repeated FindPCSColor + icUInt32Number m_nColorEntrySize; + + icUInt32Number m_nVendorFlags; + icUInt32Number m_nDeviceCoords; + icUInt32Number m_nSize; + + icColorSpaceSignature m_csPCS; + icColorSpaceSignature m_csDevice; +}; + +/** +**************************************************************************** +* Class: CIccTagXYZ +* +* Purpose: the XYZType tag - an array of XYZ values +**************************************************************************** +*/ +class ICCPROFLIB_API CIccTagXYZ : public CIccTag +{ +public: + CIccTagXYZ(int nSize=1); + CIccTagXYZ(const CIccTagXYZ &ITXYZ); + CIccTagXYZ &operator=(const CIccTagXYZ &XYZTag); + virtual CIccTag* NewCopy() const {return new CIccTagXYZ(*this);} + virtual ~CIccTagXYZ(); + + virtual bool IsArrayType() { return m_nSize > 1; } + + virtual icTagTypeSignature GetType() const { return icSigXYZType; } + virtual const icChar *GetClassName() const { return "CIccTagXYZ"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + icXYZNumber &operator[](icUInt32Number index) const {return m_XYZ[index];} + icXYZNumber *GetXYZ(icUInt32Number index) {return &m_XYZ[index];} + icUInt32Number GetSize() const { return m_nSize; } + void SetSize(icUInt32Number nSize, bool bZeroNew=true); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icXYZNumber *m_XYZ; + icUInt32Number m_nSize; +}; + +/** +**************************************************************************** +* Class: CIccTagChromaticity +* +* Purpose: the chromaticity tag - xy chromaticity values for each channel +**************************************************************************** +*/ +class ICCPROFLIB_API CIccTagChromaticity : public CIccTag +{ +public: + CIccTagChromaticity(int nSize=3); + CIccTagChromaticity(const CIccTagChromaticity &ITCh); + CIccTagChromaticity &operator=(const CIccTagChromaticity &ChromTag); + virtual CIccTag* NewCopy() const {return new CIccTagChromaticity(*this);} + virtual ~CIccTagChromaticity(); + + virtual bool IsArrayType() { return m_nChannels > 1; } + + virtual icTagTypeSignature GetType() const { return icSigChromaticityType; } + virtual const icChar *GetClassName() const { return "CIccTagChromaticity"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + icChromaticityNumber &operator[](icUInt32Number index) {return m_xy[index];} + icChromaticityNumber *Getxy(icUInt32Number index) {return &m_xy[index];} + icUInt32Number GetSize() const { return m_nChannels; } + void SetSize(icUInt16Number nSize, bool bZeroNew=true); + + icUInt16Number m_nColorantType; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt16Number m_nChannels; + icChromaticityNumber *m_xy; +}; + +/** +**************************************************************************** +* Class: CIccTagFixedNum +* +* Purpose: A template class for arrays of Fixed point numbers +* +* Derived Tags: CIccTagS15Fixed16 and CIccTagU16Fixed16 +***************************************************************************** +*/ +template +class ICCPROFLIB_API CIccTagFixedNum : public CIccTag +{ +public: + CIccTagFixedNum(int nSize=1); + CIccTagFixedNum(const CIccTagFixedNum &ITFN); + CIccTagFixedNum &operator=(const CIccTagFixedNum &FixedNumTag); + virtual CIccTag* NewCopy() const { return new CIccTagFixedNum(*this); } + virtual ~CIccTagFixedNum(); + + virtual bool IsArrayType() { return m_nSize > 1; } + + virtual icTagTypeSignature GetType() const { return Tsig; } + virtual const icChar *GetClassName() const; + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + T &operator[](icUInt32Number index) {return m_Num[index];} + + /// Returns the size of the data array + icUInt32Number GetSize() const { return m_nSize; } + void SetSize(icUInt32Number nSize, bool bZeroNew=true); + +protected: + T *m_Num; + icUInt32Number m_nSize; +}; + +/** +**************************************************************************** +* Class: CIccTagS15Fixed16 +* +* Purpose: s15Fixed16type tag derived from CIccTagFixedNum +***************************************************************************** +*/ +typedef CIccTagFixedNum CIccTagS15Fixed16; + +/** +**************************************************************************** +* Classe: CIccTagU16Fixed16 +* +* Purpose: u16Fixed16type tag derived from CIccTagFixedNum +***************************************************************************** +*/ +typedef CIccTagFixedNum CIccTagU16Fixed16; + +/** +**************************************************************************** +* Class: CIccTagNum +* +* Purpose: A template class for arrays of integers +* +* Derived Tags: CIccTagUInt8, CIccTagUInt16, CIccTagUInt32 and CIccTagUInt64 +***************************************************************************** +*/ +template +class ICCPROFLIB_API CIccTagNum : public CIccTag +{ +public: + CIccTagNum(int nSize=1); + CIccTagNum(const CIccTagNum &ITNum); + CIccTagNum &operator=(const CIccTagNum &NumTag); + virtual CIccTag* NewCopy() const { return new CIccTagNum(*this); } + virtual ~CIccTagNum(); + + virtual bool IsArrayType() { return m_nSize > 1; } + + virtual icTagTypeSignature GetType() const { return Tsig; } + virtual const icChar *GetClassName() const; + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + T &operator[](icUInt32Number index) {return m_Num[index];} + + /// Returns the size of the data array + icUInt32Number GetSize() const { return m_nSize; } + void SetSize(icUInt32Number nSize, bool bZeroNew=true); + +protected: + T *m_Num; + icUInt32Number m_nSize; +}; + + +/** +**************************************************************************** +* Class: CIccTagUInt8 +* +* Purpose: icUInt8Number type tag derived from CIccTagNum +***************************************************************************** +*/ +typedef CIccTagNum CIccTagUInt8; + +/** +**************************************************************************** +* Class: CIccTagUInt16 +* +* Purpose: icUInt16Number type tag derived from CIccTagNum +***************************************************************************** +*/ +typedef CIccTagNum CIccTagUInt16; + +/** +**************************************************************************** +* Class: CIccTagUInt32 +* +* Purpose: icUInt32Number type tag derived from CIccTagNum +***************************************************************************** +*/ +typedef CIccTagNum CIccTagUInt32; + +/** +**************************************************************************** +* Class: CIccTagUInt64 +* +* Purpose: icUInt64Number type tag derived from CIccTagNum +***************************************************************************** +*/ +typedef CIccTagNum CIccTagUInt64; + + + +/** +**************************************************************************** +* Class: CIccTagMeasurement +* +* Purpose: The measurmentType tag +**************************************************************************** +*/ +class ICCPROFLIB_API CIccTagMeasurement : public CIccTag +{ +public: + CIccTagMeasurement(); + CIccTagMeasurement(const CIccTagMeasurement &ITM); + CIccTagMeasurement &operator=(const CIccTagMeasurement &MeasTag); + virtual CIccTag* NewCopy() const {return new CIccTagMeasurement(*this);} + virtual ~CIccTagMeasurement(); + + virtual icTagTypeSignature GetType() const { return icSigMeasurementType; } + virtual const icChar *GetClassName() const { return "CIccTagMeasurement"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + + icMeasurement m_Data; +}; + +/** +**************************************************************************** +* Data Class: CIccLocalizedUnicode +* +* Purpose: Implementation of a unicode string with language and region +* identifiers. +***************************************************************************** +*/ +class ICCPROFLIB_API CIccLocalizedUnicode +{ +public: //member functions + CIccLocalizedUnicode(); + CIccLocalizedUnicode(const CIccLocalizedUnicode& ILU); + CIccLocalizedUnicode &operator=(const CIccLocalizedUnicode &UnicodeText); + virtual ~CIccLocalizedUnicode(); + + icUInt32Number GetLength() const { return m_nLength; } + icUInt16Number *GetBuf() const { return m_pBuf; } + + icUInt32Number GetAnsiSize(); + const icChar *GetAnsi(icChar *szBuf, icUInt32Number nBufSize); + + void SetSize(icUInt32Number); + + void SetText(const icChar *szText, + icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + void SetText(const icUInt16Number *sszUnicode16Text, + icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + void SetText(const icUInt32Number *sszUnicode32Text, + icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + + const icChar *operator=(const icChar *szText) { SetText(szText); return szText; } + const icUInt16Number *operator=(const icUInt16Number *sszText) { SetText(sszText); return sszText; } + const icUInt32Number *operator=(const icUInt32Number *sszText) { SetText(sszText); return sszText; } + + //Data + icLanguageCode m_nLanguageCode; + icCountryCode m_nCountryCode; + +protected: + icUInt32Number m_nLength; + + icUInt16Number *m_pBuf; + +}; + +/** +**************************************************************************** +* List Class: CIccMultiLocalizedUnicode +* +* Purpose: List of CIccLocalizedUnicode objects +***************************************************************************** +*/ +typedef std::list CIccMultiLocalizedUnicode; + + +/** +**************************************************************************** +* Class: CIccTagMultiLocalizedUnicode +* +* Purpose: The MultiLocalizedUnicode tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagMultiLocalizedUnicode : public CIccTag +{ +public: + CIccTagMultiLocalizedUnicode(); + CIccTagMultiLocalizedUnicode(const CIccTagMultiLocalizedUnicode& ITMLU); + CIccTagMultiLocalizedUnicode &operator=(const CIccTagMultiLocalizedUnicode &MultiLocalizedTag); + virtual CIccTag* NewCopy() const {return new CIccTagMultiLocalizedUnicode(*this);} + virtual ~CIccTagMultiLocalizedUnicode(); + + virtual icTagTypeSignature GetType() const { return icSigMultiLocalizedUnicodeType; } + virtual const icChar *GetClassName() const { return "CIcciSigMultiLocalizedUnicode"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + CIccLocalizedUnicode *Find(icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + + void SetText(const icChar *szText, + icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + void SetText(const icUInt16Number *sszUnicode16Text, + icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + void SetText(const icUInt32Number *sszUnicode32Text, + icLanguageCode nLanguageCode = icLanguageCodeEnglish, + icCountryCode nRegionCode = icCountryCodeUSA); + + + CIccMultiLocalizedUnicode *m_Strings; +}; + + +// +// MD: Moved Curve & LUT Tags to IccTagLut.h (4-30-05) +// + +/** +**************************************************************************** +* Class: CIccTagData +* +* Purpose: The data type tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagData : public CIccTag +{ +public: + CIccTagData(int nSize=1); + CIccTagData(const CIccTagData &ITD); + CIccTagData &operator=(const CIccTagData &DataTag); + virtual CIccTag* NewCopy() const {return new CIccTagData(*this);} + virtual ~CIccTagData(); + + virtual icTagTypeSignature GetType() const { return icSigDataType; } + virtual const icChar *GetClassName() const { return "CIccTagData"; } + + virtual bool IsArrayType() { return m_nSize > 1; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + icUInt32Number GetSize() const { return m_nSize; } + void SetSize(icUInt32Number nSize, bool bZeroNew=true); + icUInt8Number &operator[] (icUInt32Number index) { return m_pData[index]; } + icUInt8Number *GetData(icUInt32Number index) { return &m_pData[index];} + + void SetTypeAscii(bool bIsAscii=true) { m_nDataFlag = bIsAscii ? icAsciiData : icBinaryData; } + bool IsTypeAscii() { return m_nDataFlag == icAsciiData; } + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt32Number m_nDataFlag; + icUInt8Number *m_pData; + icUInt32Number m_nSize; +}; + +/** +**************************************************************************** +* Class: CIccTagDateTime +* +* Purpose: The date time tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagDateTime : public CIccTag +{ +public: + CIccTagDateTime(); + CIccTagDateTime(const CIccTagDateTime &ITDT); + CIccTagDateTime &operator=(const CIccTagDateTime &DateTimeTag); + virtual CIccTag* NewCopy() const {return new CIccTagDateTime(*this);} + virtual ~CIccTagDateTime(); + + virtual icTagTypeSignature GetType() const { return icSigDateTimeType; } + virtual const icChar *GetClassName() const { return "CIccTagDateTime"; } + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual void Describe(std::string &sDescription); + + void SetDateTime(icDateTimeNumber nDateTime) { m_DateTime = nDateTime;} + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icDateTimeNumber m_DateTime; +}; + +/** +**************************************************************************** +* Class: CIccTagColorantOrder +* +* Purpose: Colorant Order Tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagColorantOrder : public CIccTag +{ +public: + CIccTagColorantOrder(int nsize=1); + CIccTagColorantOrder(const CIccTagColorantOrder &ITCO); + CIccTagColorantOrder &operator=(const CIccTagColorantOrder &ColorantOrderTag); + virtual CIccTag* NewCopy() const {return new CIccTagColorantOrder(*this);} + virtual ~CIccTagColorantOrder(); + + virtual icTagTypeSignature GetType() const { return icSigColorantOrderType; } + virtual const icChar *GetClassName() const { return "CIccTagColorantOrder"; } + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual void Describe(std::string &sDescription); + icUInt8Number& operator[](int index) { return m_pData[index]; } + icUInt8Number *GetData(int index) { return &m_pData[index]; } + void SetSize(icUInt16Number nsize, bool bZeronew=true); + icUInt32Number GetSize() const {return m_nCount;} + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt32Number m_nCount; + icUInt8Number *m_pData; +}; + +/** +**************************************************************************** +* Class: CIccTagColorantTable +* +* Purpose: Colorant Table Tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagColorantTable : public CIccTag +{ +public: + CIccTagColorantTable(int nsize=1); + CIccTagColorantTable(const CIccTagColorantTable &ITCT); + CIccTagColorantTable &operator=(const CIccTagColorantTable &ColorantTableTag); + virtual CIccTag* NewCopy() const {return new CIccTagColorantTable(*this);} + virtual ~CIccTagColorantTable(); + + virtual icTagTypeSignature GetType() const { return icSigColorantTableType; } + virtual const icChar *GetClassName() const { return "CIccTagColorantTable"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + icColorantTableEntry &operator[](icUInt32Number index) {return m_pData[index];} + icColorantTableEntry *GetEntry(icUInt32Number index) {return &m_pData[index];} + icUInt32Number GetSize() const { return m_nCount; } + void SetSize(icUInt16Number nSize, bool bZeroNew=true); + + void SetPCS(icColorSpaceSignature sig) {m_PCS = sig;} + icColorSpaceSignature GetPCS() const {return m_PCS;}; + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt32Number m_nCount; + icColorantTableEntry *m_pData; + icColorSpaceSignature m_PCS; +}; + +/** +**************************************************************************** +* Class: CIccTagViewingConditions +* +* Purpose: Viewing conditions tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagViewingConditions : public CIccTag +{ +public: + CIccTagViewingConditions(); + CIccTagViewingConditions(const CIccTagViewingConditions &ITVC); + CIccTagViewingConditions &operator=(const CIccTagViewingConditions &ViewCondTag); + virtual CIccTag* NewCopy() const {return new CIccTagViewingConditions(*this);} + virtual ~CIccTagViewingConditions(); + + virtual icTagTypeSignature GetType() const { return icSigViewingConditionsType; } + virtual const icChar *GetClassName() const { return "CIccTagViewingConditions"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + icXYZNumber m_XYZIllum; + icXYZNumber m_XYZSurround; + icIlluminant m_illumType; +}; + +/** +**************************************************************************** +* Data Class: CIccProfileDescText +* +* Purpose: Private text class for CIccProfileDescStruct. +* Text can be either a CIccTagTextDescription or a CIccTagMultiLocalizedUnicode +* so this class provides a single interface to both. +***************************************************************************** +*/ +class ICCPROFLIB_API CIccProfileDescText +{ +public: + CIccProfileDescText(); + CIccProfileDescText(const CIccProfileDescText& IPDC); + CIccProfileDescText &operator=(const CIccProfileDescText &ProfDescText); + virtual ~CIccProfileDescText(); + + bool SetType(icTagTypeSignature nType); + virtual icTagTypeSignature GetType() const; + + CIccTag* GetTag() const { return m_pTag; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + bool m_bNeedsPading; + +protected: + CIccTag *m_pTag; //either a CIccTagTextDescription or a CIccTagMultiLocalizedUnicode +}; + + + +/** +**************************************************************************** +* Data Class: CIccProfileDescStruct +* +* Purpose: Storage class for profile description structure +***************************************************************************** +*/ +class ICCPROFLIB_API CIccProfileDescStruct +{ +public: + CIccProfileDescStruct(); + CIccProfileDescStruct(const CIccProfileDescStruct& IPDS); + CIccProfileDescStruct &operator=(const CIccProfileDescStruct& ProfDescStruct); + + + icSignature m_deviceMfg; /* Device Manufacturer */ + icSignature m_deviceModel; /* Device Model */ + icUInt64Number m_attributes; /* Device attributes */ + icTechnologySignature m_technology; /* Technology signature */ + CIccProfileDescText m_deviceMfgDesc; + CIccProfileDescText m_deviceModelDesc; +}; + +/** +**************************************************************************** +* List Class: CIccProfileSeqDesc +* +* Purpose: List of profile description structures +***************************************************************************** +*/ +typedef std::list CIccProfileSeqDesc; + + +/** +**************************************************************************** +* Class: CIccTagProfileSeqDesc +* +* Purpose: Profile Sequence description tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagProfileSeqDesc : public CIccTag +{ +public: + CIccTagProfileSeqDesc(); + CIccTagProfileSeqDesc(const CIccTagProfileSeqDesc &ITPSD); + CIccTagProfileSeqDesc &operator=(const CIccTagProfileSeqDesc &ProfSeqDescTag); + virtual CIccTag* NewCopy() const {return new CIccTagProfileSeqDesc(*this);} + virtual ~CIccTagProfileSeqDesc(); + + virtual icTagTypeSignature GetType() const { return icSigProfileSequenceDescType; } + virtual const icChar *GetClassName() const { return "CIccTagProfileSeqDesc"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + CIccProfileSeqDesc *m_Descriptions; +}; + + +/** +**************************************************************************** +* List Class: CIccResponse16List +* +* Purpose: List of response16numbers +***************************************************************************** +*/ +typedef std::list CIccResponse16List; + +/** +**************************************************************************** +* Data Class: CIccResponseCurveStruct +* +* Purpose: The base class for response curve structure +***************************************************************************** +*/ +class ICCPROFLIB_API CIccResponseCurveStruct +{ + friend class ICCPROFLIB_API CIccTagResponseCurveSet16; +public: //member functions + CIccResponseCurveStruct(icMeasurementUnitSig sig, icUInt16Number nChannels=0); + CIccResponseCurveStruct(icUInt16Number nChannels=0); + + CIccResponseCurveStruct(const CIccResponseCurveStruct& IRCS); + CIccResponseCurveStruct &operator=(const CIccResponseCurveStruct& RespCurveStruct); + virtual ~CIccResponseCurveStruct(); + + bool Read(icUInt32Number size, CIccIO *pIO); + bool Write(CIccIO *pIO); + void Describe(std::string &sDescription); + + icMeasurementUnitSig GetMeasurementType() const {return m_measurementUnitSig;} + icUInt16Number GetNumChannels() const {return m_nChannels;} + + icXYZNumber *GetXYZ(icUInt32Number index) {return &m_maxColorantXYZ[index];} + CIccResponse16List *GetResponseList(icUInt16Number nChannel) {return &m_Response16ListArray[nChannel];} + CIccResponseCurveStruct* GetThis() {return this;} + icValidateStatus Validate(std::string &sReport) const; + +protected: + icUInt16Number m_nChannels; + icMeasurementUnitSig m_measurementUnitSig; + icXYZNumber *m_maxColorantXYZ; + CIccResponse16List *m_Response16ListArray; +}; + + +/** +**************************************************************************** +* List Class: CIccResponseCurveSet +* +* Purpose: List of response curve structures +***************************************************************************** +*/ + +typedef std::list CIccResponseCurveSet; + +class CIccResponseCurveSetIter +{ +public: + bool inited; + CIccResponseCurveSet::iterator item; +}; + + +/** +**************************************************************************** +* Class: CIccTagResponseCurveSet16 +* +* Purpose: The responseCurveSet16 Tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagResponseCurveSet16 : public CIccTag +{ +public: + CIccTagResponseCurveSet16(); + CIccTagResponseCurveSet16(const CIccTagResponseCurveSet16 &ITRCS); + CIccTagResponseCurveSet16 &operator=(const CIccTagResponseCurveSet16 &RespCurveSet16Tag); + virtual CIccTag* NewCopy() const {return new CIccTagResponseCurveSet16(*this);} + virtual ~CIccTagResponseCurveSet16(); + + virtual icTagTypeSignature GetType() const { return icSigResponseCurveSet16Type; } + virtual const icChar *GetClassName() const { return "CIccTagResponseCurveSet16"; } + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + virtual void Describe(std::string &sDescription); + + void SetNumChannels(icUInt16Number nChannels); + icUInt16Number GetNumChannels() const {return m_nChannels;} + + CIccResponseCurveStruct *NewResponseCurves(icMeasurementUnitSig sig); + CIccResponseCurveStruct *GetResponseCurves(icMeasurementUnitSig sig); + + CIccResponseCurveStruct *GetFirstCurves(); + CIccResponseCurveStruct *GetNextCurves(); + + icUInt16Number GetNumResponseCurveTypes() const; + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + CIccResponseCurveSet *m_ResponseCurves; + icUInt16Number m_nChannels; + CIccResponseCurveSetIter *m_Curve; +}; + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif // !defined(_ICCTAGBASIC_H) diff --git a/library/src/main/cpp/icc/IccTagDict.cpp b/library/src/main/cpp/icc/IccTagDict.cpp new file mode 100644 index 00000000..82c6e1f1 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagDict.cpp @@ -0,0 +1,1467 @@ +/** @file + File: IccTagDictTag.cpp + + Contains: Implementation of prototype dictType Tag + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak Jun-26-2009 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) +#pragma warning( disable: 4786) //disable warning in +#endif + +#include +#include +#include +#include +#include "IccTagDict.h" +#include "IccUtil.h" +#include "IccIO.h" + + +//MSVC 6.0 doesn't support std::string correctly so we disable support in this case +#ifndef ICC_UNSUPPORTED_TAG_DICT + +/*============================================================================= +* CLASS CIccDictEntry +*=============================================================================*/ + +/** +****************************************************************************** +* Name: CIccDictEntry::CIccDictEntry +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccDictEntry::CIccDictEntry() +{ + m_pNameLocalized = NULL; + m_pValueLocalized = NULL; + m_bValueSet = false; +} + +/** +****************************************************************************** +* Name: CIccDictEntry::CIccDictEntry +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccDictEntry::CIccDictEntry(const CIccDictEntry& IDE) +{ + m_sName = IDE.m_sName; + m_bValueSet = IDE.m_bValueSet; + m_sValue = IDE.m_sValue; + + if (IDE.m_pNameLocalized) { + m_pNameLocalized = (CIccTagMultiLocalizedUnicode*)IDE.m_pNameLocalized->NewCopy(); + } + else + m_pNameLocalized = NULL; + + if (IDE.m_pValueLocalized) { + m_pValueLocalized = (CIccTagMultiLocalizedUnicode*)IDE.m_pValueLocalized->NewCopy(); + } + else + m_pValueLocalized = NULL; +} + +/** +****************************************************************************** +* Name: CIccDictEntry::operator= +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccDictEntry &CIccDictEntry::operator=(const CIccDictEntry &IDE) +{ + if (m_pNameLocalized) + delete m_pNameLocalized; + + if (m_pValueLocalized) + delete m_pValueLocalized; + + m_sName = IDE.m_sName; + m_bValueSet = IDE.m_bValueSet; + m_sValue = IDE.m_sValue; + + if (IDE.m_pNameLocalized) { + m_pNameLocalized = (CIccTagMultiLocalizedUnicode*)IDE.m_pNameLocalized->NewCopy(); + } + else + m_pNameLocalized = NULL; + + if (IDE.m_pValueLocalized) { + m_pValueLocalized = (CIccTagMultiLocalizedUnicode*)IDE.m_pValueLocalized->NewCopy(); + } + else + m_pValueLocalized = NULL; + + return *this; +} + +/** +****************************************************************************** +* Name: CIccDictEntry::~CIccDictEntry +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccDictEntry::~CIccDictEntry() +{ + delete m_pNameLocalized; + delete m_pValueLocalized; +} + +/** +****************************************************************************** +* Name: CIccDictEntry::Describe +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +void CIccDictEntry::Describe(std::string &sDescription) +{ + std::string s; + + sDescription += "BEGIN DICT_ENTRY\r\nName="; + m_sName.ToUtf8(s); + sDescription += s; + sDescription += "\r\nValue="; + m_sValue.ToUtf8(s); + sDescription += s; + sDescription += "\r\n"; + + if (m_pNameLocalized) { + sDescription += "BEGIN NAME_LOCALIZATION\r\n"; + m_pNameLocalized->Describe(sDescription); + sDescription += "END NAME_LOCALIZATION\r\n"; + } + if (m_pValueLocalized) { + sDescription += "BEGIN VALUE_LOCALIZATION\r\n"; + m_pValueLocalized->Describe(sDescription); + sDescription += "END VALUE_LOCALIZATION\r\n"; + } + sDescription += "END DICT_ENTRY\r\n"; +} + + +/** +****************************************************************************** +* Name: CIccDictEntry::PosRecSize +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +icUInt32Number CIccDictEntry::PosRecSize() +{ + if (m_pValueLocalized) + return 32; + if (m_pNameLocalized) + return 24; + return 16; +} + + +bool CIccDictEntry::SetValue(const CIccUTF16String &sValue) +{ + bool rv = m_bValueSet && !m_sValue.Empty(); + + m_sValue = sValue; + m_bValueSet = true; + return rv; +} + +/** +****************************************************************************** +* Name: CIccDictEntry::SetNameLocalized +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccDictEntry::SetNameLocalized(CIccTagMultiLocalizedUnicode *pNameLocalized) +{ + bool rv; + + if (m_pNameLocalized) { + delete m_pNameLocalized; + rv = true; + } + else + rv = false; + + m_pNameLocalized = pNameLocalized; + + return rv; +} + + +/** +****************************************************************************** +* Name: CIccDictEntry::SetValueLocalized +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccDictEntry::SetValueLocalized(CIccTagMultiLocalizedUnicode *pValueLocalized) +{ + bool rv; + + if (m_pValueLocalized) { + delete m_pValueLocalized; + rv = true; + } + else + rv = false; + + m_pValueLocalized = pValueLocalized; + + return rv; +} + +/*============================================================================= + * CLASS CIccTagDict + *============================================================================*/ + +/** + ****************************************************************************** + * Name: CIccTagDict::CIccTagDict + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagDict::CIccTagDict() +{ + m_bBadAlignment = false; + + m_Dict = new CIccNameValueDict; +} + +/** + ****************************************************************************** + * Name: CIccTagDict::CIccTagDict + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagDict::CIccTagDict(const CIccTagDict &dict) +{ + m_bBadAlignment = false; + m_Dict = new CIccNameValueDict; + + CIccNameValueDict::iterator i; + CIccDictEntryPtr ptr; + + for (i=dict.m_Dict->begin(); i!=dict.m_Dict->end(); i++) { + ptr.ptr = new CIccDictEntry(*i->ptr); + + m_Dict->push_back(ptr); + } +} + +/** + ****************************************************************************** + * Name: &operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagDict &CIccTagDict::operator=(const CIccTagDict &dict) +{ + if (&dict == this) + return *this; + + Cleanup(); + + CIccNameValueDict::iterator i; + CIccDictEntryPtr ptr; + + for (i=dict.m_Dict->begin(); i!=dict.m_Dict->end(); i++) { + ptr.ptr = new CIccDictEntry(*i->ptr); + + m_Dict->push_back(ptr); + } + + return *this; +} + +/** + ****************************************************************************** + * Name: CIccTagDict::~CIccTagDict + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagDict::~CIccTagDict() +{ + Cleanup(); + delete m_Dict; +} + + +/** +****************************************************************************** +* Name: CIccTagDict::MaxPosRecSize; +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +icUInt32Number CIccTagDict::MaxPosRecSize() +{ + + icUInt32Number rv = 16; + + CIccNameValueDict::iterator i; + CIccDictEntry ptr; + + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + if (i->ptr->PosRecSize() > rv) + rv = i->ptr->PosRecSize(); + } + + return rv; +} + + +/** + ****************************************************************************** + * Name: CIccTagDict::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccTagDict::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sprintf(buf, "BEGIN DICT_TAG\r\n"); + sDescription += buf; + + CIccNameValueDict::iterator i; + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + sDescription += "\r\n"; + + i->ptr->Describe(sDescription); + } + + sprintf(buf, "\r\nEND DICT_TAG\r\n"); + sDescription += buf; +} + +typedef struct +{ + icPositionNumber posName; + icPositionNumber posValue; + icPositionNumber posNameLocalized; + icPositionNumber posValueLocalized; +} icDictRecordPos; + + +/** + ****************************************************************************** + * Name: CIccTagDict::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagDict::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + m_tagSize = size; + + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + Cleanup(); + + m_tagStart = pIO->Tell(); + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number count, reclen, i; + + if (!pIO->Read32(&count)) + return false; + + if (!pIO->Read32(&reclen)) + return false; + + if (reclen!=16 && reclen!=24 && reclen!=32) + return false; + + if (headerSize + count*reclen > size) + return false; + + icDictRecordPos *pos = (icDictRecordPos*)calloc(count, sizeof(icDictRecordPos)); + if (!pos) + return false; + + //Read TagDir + for (i=0; iRead32(&pos[i].posName.offset) || + !pIO->Read32(&pos[i].posName.size) || + !pIO->Read32(&pos[i].posValue.offset) || + !pIO->Read32(&pos[i].posValue.size)) { + free(pos); + return false; + } + + if (reclen>=24) { + if (!pIO->Read32(&pos[i].posNameLocalized.offset) || + !pIO->Read32(&pos[i].posNameLocalized.size)) { + free(pos); + return false; + } + if (reclen>=32) { + if (!pIO->Read32(&pos[i].posValueLocalized.offset) || + !pIO->Read32(&pos[i].posValueLocalized.size)) { + free(pos); + return false; + } + } + } + + if ((pos[i].posName.offset & 0x3) || + (pos[i].posValue.offset & 0x3) || + (pos[i].posNameLocalized.offset & 0x3) || + (pos[i].posValueLocalized.offset & 0x3)) + m_bBadAlignment = true; + } + + icUInt32Number bufsize = 128, num; + icUnicodeChar *buf = (icUnicodeChar*)malloc(bufsize); + CIccDictEntryPtr ptr; + CIccUTF16String str; + + for (i=0; iSetValue(str); + } + else { + if (pos[i].posName.offset + pos[i].posName.size >size || + !pos[i].posName.size) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + //Make sure we have buf large enough for the string + if (bufsize < pos[i].posName.size) { + bufsize = pos[i].posName.size; + buf = (icUnicodeChar*)realloc(buf, bufsize+1*sizeof(icUnicodeChar)); + if (!buf) { + free(pos); + delete ptr.ptr; + return false; + } + } + + if (pIO->Seek(m_tagStart+pos[i].posName.offset, icSeekSet)<0) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + num = pos[i].posName.size / sizeof(icUnicodeChar); + if (pIO->Read16(buf, num)!=(icInt32Number)num) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + buf[num] = 0; + ptr.ptr->m_sName = buf; + } + } + + //GetValue + if (pos[i].posValue.offset) { + if (!pos[i].posValue.size) { + str.Clear(); + ptr.ptr->SetValue(str); + } + else { + if (pos[i].posValue.offset + pos[i].posValue.size >size || + (pos[i].posValue.size&1)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + //Make sure we have buf large enough for the string + if (bufsize < pos[i].posValue.size) { + bufsize = pos[i].posValue.size; + buf = (icUnicodeChar*)realloc(buf, bufsize+1*sizeof(icUnicodeChar)); + if (!buf) { + free(pos); + delete ptr.ptr; + return false; + } + } + + if (pIO->Seek(m_tagStart+pos[i].posValue.offset, icSeekSet)<0) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + num = pos[i].posValue.size / sizeof(icUnicodeChar); + if (pIO->Read16(buf, num)!=(icInt32Number)num) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + buf[num]=0; + ptr.ptr->SetValue(buf); + } + } + + //Get NameLocalized + if (pos[i].posNameLocalized.offset) { + if (pos[i].posNameLocalized.offset + pos[i].posNameLocalized.size > size || + pos[i].posNameLocalized.size < sizeof(icSignature)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + if (pIO->Seek(m_tagStart+pos[i].posNameLocalized.offset, icSeekSet)<0) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + icTagTypeSignature textSig = (icTagTypeSignature)0; + if (!pIO->Read32(&textSig, 1)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + if (textSig != icSigMultiLocalizedUnicodeType) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + if (pIO->Seek(m_tagStart+pos[i].posNameLocalized.offset, icSeekSet)<0) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + CIccTagMultiLocalizedUnicode *pTag = new CIccTagMultiLocalizedUnicode(); + + if (!pTag || !pTag->Read(pos[i].posNameLocalized.size, pIO)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + ptr.ptr->SetNameLocalized(pTag); + } + + //Get ValueLocalized + if (pos[i].posValueLocalized.offset) { + if (pos[i].posValueLocalized.offset + pos[i].posValueLocalized.size > size || + pos[i].posValueLocalized.size < sizeof(icSignature)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + if (pIO->Seek(m_tagStart+pos[i].posValueLocalized.offset, icSeekSet)<0) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + icTagTypeSignature textSig = (icTagTypeSignature)0; + if (!pIO->Read32(&textSig, 1)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + if (textSig != icSigMultiLocalizedUnicodeType) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + if (pIO->Seek(m_tagStart+pos[i].posValueLocalized.offset, icSeekSet)<0) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + CIccTagMultiLocalizedUnicode *pTag = new CIccTagMultiLocalizedUnicode(); + + if (!pTag || !pTag->Read(pos[i].posValueLocalized.size, pIO)) { + free(pos); + free(buf); + delete ptr.ptr; + return false; + } + + ptr.ptr->SetValueLocalized(pTag); + } + + m_Dict->push_back(ptr); + } + + free(pos); + free(buf); + + return true; +} + +/** + ****************************************************************************** + * Name: CIccTagDict::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagDict::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + m_tagStart = pIO->Tell(); + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + CIccNameValueDict::iterator i, j; + icUInt32Number count; + icUInt8Number zbuf[32]; + + memset(zbuf, 0, 32); + + for (count=0, i=m_Dict->begin(); i!= m_Dict->end(); i++) { + if (i->ptr) + count++; + } + + pIO->Write32(&count); + + icUInt32Number recSize = MaxPosRecSize(); + pIO->Write32(&recSize); + + icDictRecordPos *pos = (icDictRecordPos*)calloc(count, sizeof(icDictRecordPos)); + if (!pos) + return false; + + icUInt32Number n, dirpos = pIO->Tell(); + + //Write Unintialized Dict rec offset array + for (i=m_Dict->begin(); i!= m_Dict->end(); i++) { + if (i->ptr) { + pIO->Write8(zbuf, recSize); + } + } + + //Write Dict records + for (n=0, i=m_Dict->begin(); i!= m_Dict->end(); i++) { + if (i->ptr) { + pos[n].posName.offset = pIO->Tell()-m_tagStart; + + pIO->Write16((void*)i->ptr->m_sName.c_str(), i->ptr->m_sName.Size()); + pos[n].posName.size = pIO->Tell()-m_tagStart - pos[n].posName.offset; + pIO->Align32(); + + if (i->ptr->IsValueSet()) { + const CIccUTF16String &str = i->ptr->GetValue(); + pos[n].posValue.offset = pIO->Tell()-m_tagStart; + pIO->Write16((void*)str.c_str(), str.Size()); + + pos[n].posValue.size = pIO->Tell()-m_tagStart - pos[n].posValue.offset; + pIO->Align32(); + } + + if (recSize>16 && i->ptr->GetNameLocalized()) { + pos[n].posNameLocalized.offset = pIO->Tell()-m_tagStart; + i->ptr->GetNameLocalized()->Write(pIO); + pos[n].posNameLocalized.size = pIO->Tell()-m_tagStart - pos[n].posNameLocalized.offset; + pIO->Align32(); + } + + if (recSize>24 && i->ptr->GetValueLocalized()) { + pos[n].posValueLocalized.offset = pIO->Tell()-m_tagStart; + i->ptr->GetValueLocalized()->Write(pIO); + pos[n].posValueLocalized.size = pIO->Tell()-m_tagStart - pos[n].posValueLocalized.offset; + pIO->Align32(); + } + n++; + } + } + icUInt32Number endpos = pIO->Tell(); + + pIO->Seek(dirpos, icSeekSet); + + //Write TagDir with offsets and sizes + for (n=0, i=m_Dict->begin(); i!= m_Dict->end(); i++) { + if (i->ptr) { + pIO->Write32(&pos[n].posName.offset); + pIO->Write32(&pos[n].posName.size); + pIO->Write32(&pos[n].posValue.offset); + pIO->Write32(&pos[n].posValue.size); + if (recSize>16) { + pIO->Write32(&pos[n].posNameLocalized.offset); + pIO->Write32(&pos[n].posNameLocalized.size); + if (recSize>24) { + pIO->Write32(&pos[n].posValueLocalized.offset); + pIO->Write32(&pos[n].posValueLocalized.size); + } + } + } + n++; + } + pIO->Seek(endpos, icSeekSet); + + free(pos); + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccTagDict::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccTagDict::Validate(icTagSignature sig, std::string &sReport, + const CIccProfile* pProfile /*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + // Check for duplicate tags + if (!AreNamesUnique()) { + sReport += icValidateWarning; + sReport += sSigName; + sReport += " - There are duplicate tags.\r\n"; + rv =icMaxStatus(rv, icValidateWarning); + } + + if (!AreNamesNonzero()) { + sReport += icValidateWarning; + sReport += sSigName; + sReport += " - There are duplicate tags.\r\n"; + rv =icMaxStatus(rv, icValidateWarning); + } + + // Check for duplicate tags + if (m_bBadAlignment) { + sReport += icValidateWarning; + sReport += sSigName; + sReport += " - Some Data elements are not aligned correctly\r\n"; + rv =icMaxStatus(rv, icValidateWarning); + } + + return rv; +} + +/** + *************************************************************************** + * Name: CIccTagDict::Cleanup + * + * Purpose: Detach from a pending IO object + *************************************************************************** + */ +void CIccTagDict::Cleanup() +{ + CIccNameValueDict::iterator i; + + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + if (i->ptr) + delete i->ptr; + } + m_Dict->clear(); +} + +/** +****************************************************************************** +* Name: CIccTagDict::AreNamesUnique +* +* Purpose: For each tag it checks to see if any other tags have the same +* signature. +* +* +* Return: +* true if all tags have unique signatures, or false if there are duplicate +* tag signatures. +******************************************************************************* +*/ +bool CIccTagDict::AreNamesUnique() const +{ + CIccNameValueDict::const_iterator i, j; + + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + j=i; + for (j++; j!= m_Dict->end(); j++) { + if (i->ptr->m_sName == j->ptr->m_sName) + return false; + } + } + + return true; +} + +/** +****************************************************************************** +* Name: CIccTagDict::AreNamesNonzero +* +* Purpose: For each tag it checks to see if any other tags have the same +* signature. +* +* +* Return: +* true if all tags have unique signatures, or false if there are duplicate +* tag signatures. +******************************************************************************* +*/ +bool CIccTagDict::AreNamesNonzero() const +{ + CIccNameValueDict::const_iterator i, j; + + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + if (i->ptr->m_sName.Empty()) + return false; + } + +return true; +} + + +/** + **************************************************************************** + * Name: CIccTagDict::Get + * + * Purpose: Get a dictionary entry with a given name + * + * Args: + * sName - name to find in dictionary + * + * Return: + * Pointer to desired dictionary entry, or NULL if not found. + ***************************************************************************** + */ +CIccDictEntry* CIccTagDict::Get(const CIccUTF16String &sName) const +{ + CIccNameValueDict::const_iterator i; + + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + if (i->ptr->m_sName == sName) + return i->ptr; + } + + return NULL; +} + +/** +**************************************************************************** +* Name: CIccTagDict::Get +* +* Purpose: Get a dictionary entry with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* Pointer to desired dictionary entry, or NULL if not found. +***************************************************************************** +*/ +CIccDictEntry* CIccTagDict::Get(const icUnicodeChar *szName) const +{ + CIccUTF16String sName(szName); + + return Get(sName); +} + + +/** +**************************************************************************** +* Name: CIccTagDict::Get +* +* Purpose: Get a dictionary entry with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* Pointer to desired dictionary entry, or NULL if not found. +***************************************************************************** +*/ +CIccDictEntry* CIccTagDict::Get(const char *szName) const +{ + CIccUTF16String sName(szName); + + return Get(sName); +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetValue +* +* Purpose: Get a value associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* Pointer to desired dictionary entry, or NULL if not found. +***************************************************************************** +*/ +CIccUTF16String CIccTagDict::GetValue(const CIccUTF16String &sName, bool *bIsSet) const +{ + CIccDictEntry *de = Get(sName); + + if (de) { + + if (bIsSet) + *bIsSet = de->IsValueSet(); + + return de->GetValue(); + } + + if (bIsSet) + *bIsSet = false; + + CIccUTF16String str; + return str; +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetValue +* +* Purpose: Get a value associated with a given name +* +* Args: +* szName - name to find in dictionary +* +* Return: +* Pointer to desired dictionary entry, or NULL if not found. +***************************************************************************** +*/ +CIccUTF16String CIccTagDict::GetValue(const icUnicodeChar *szName, bool *bIsSet) const +{ + CIccUTF16String sName(szName); + + return GetValue(sName, bIsSet); +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetValue +* +* Purpose: Get a value associated with a given name +* +* Args: +* szName - name to find in dictionary +* +* Return: +* Pointer to desired dictionary entry, or NULL if not found. +***************************************************************************** +*/ +CIccUTF16String CIccTagDict::GetValue(const char *szName, bool *bIsSet) const +{ + CIccUTF16String sName(szName); + + return GetValue(sName, bIsSet); +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetNameLocalized +* +* Purpose: Get a localized name information associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* localized information for name +***************************************************************************** +*/ +CIccTagMultiLocalizedUnicode* CIccTagDict::GetNameLocalized(const CIccUTF16String &sName) const +{ + CIccDictEntry *de = Get(sName); + + if (de) + return de->GetNameLocalized(); + + return NULL; +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetNameLocalized +* +* Purpose: Get a localized name information associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* localized information for name +***************************************************************************** +*/ +CIccTagMultiLocalizedUnicode* CIccTagDict::GetNameLocalized(const icUnicodeChar *szName) const +{ + CIccUTF16String sName(szName); + + return GetNameLocalized(sName); +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetNameLocalized +* +* Purpose: Get a localized name information associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* localized information for name +***************************************************************************** +*/ + +CIccTagMultiLocalizedUnicode* CIccTagDict::GetNameLocalized(const char *szName) const +{ + CIccUTF16String sName(szName); + + return GetNameLocalized(sName); +} + + +/** +**************************************************************************** +* Name: CIccTagDict::GetValueLocalized +* +* Purpose: Get a localized name information for value associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* localized information for name's value +***************************************************************************** +*/ +CIccTagMultiLocalizedUnicode* CIccTagDict::GetValueLocalized(const CIccUTF16String &sName) const +{ + CIccDictEntry *de = Get(sName); + + if (de) + return de->GetValueLocalized(); + + return NULL; +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetValueLocalized +* +* Purpose: Get a localized name information for value associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* localized information for name's value +***************************************************************************** +*/ +CIccTagMultiLocalizedUnicode* CIccTagDict::GetValueLocalized(const icUnicodeChar *szName) const +{ + CIccUTF16String sName(szName); + + return GetValueLocalized(sName); +} + +/** +**************************************************************************** +* Name: CIccTagDict::GetValueLocalized +* +* Purpose: Get a localized name information for value associated with a given name +* +* Args: +* sName - name to find in dictionary +* +* Return: +* localized information for name's value +***************************************************************************** +*/ + +CIccTagMultiLocalizedUnicode* CIccTagDict::GetValueLocalized(const char *szName) const +{ + CIccUTF16String sName(szName); + + return GetValueLocalized(sName); +} + + +/** +****************************************************************************** +* Name: CIccTagDict::Remove +* +* Purpose: Remove a name value pair from the dictionary +* +* Args: +* sName = the name to look for in the dictionary +* +* Return: +* true if sName exists and was removed, or false otherwise +******************************************************************************* +*/ +bool CIccTagDict::Remove(const CIccUTF16String &sName) +{ + CIccNameValueDict::iterator i; + + for (i=m_Dict->begin(); i!=m_Dict->end(); i++) { + if (i->ptr->m_sName == sName) { + delete i->ptr; + + m_Dict->erase(i); + return true; + } + } + + return false; +} + + +/** +****************************************************************************** +* Name: CIccTagDict::Remove +* +* Purpose: Remove a name value pair from the dictionary +* +* Args: +* sName = the name to look for in the dictionary +* +* Return: +* true if sName exists and was remove , or false otherwise +******************************************************************************* +*/ +bool CIccTagDict::Remove(const icUnicodeChar *szName) +{ + CIccUTF16String sName(szName); + + return Remove(sName); + +} + + +/** +****************************************************************************** +* Name: CIccTagDict::Remove +* +* Purpose: Remove a name value pair from the dictionary +* +* Args: +* sName = the name to look for in the dictionary +* +* Return: +* true if sName exists and was remove , or false otherwise +******************************************************************************* +*/ +bool CIccTagDict::Remove(const char *szName) +{ + CIccUTF16String sName(szName); + + return Remove(sName); +} + + +/** +****************************************************************************** +* Name: CIccTagDict::Set +* +* Purpose: Associate a value with a name in the dictionary +* +* Args: +* sName = the name to look for in the dictionary +* sValue = value to associate with sName +* bUnset = flag to indicate that value has not been set (no data for value in tag) +* +* Return: +* true if value associate with sName was changed, or false if no change +******************************************************************************* +*/ +bool CIccTagDict::Set(const CIccUTF16String &sName, const CIccUTF16String &sValue, bool bUnSet) +{ + CIccDictEntry *de = Get(sName); + + if (de) { + if (de->GetValue()==sValue && de->IsValueSet() && !bUnSet) + return false; + } + else { + de = new CIccDictEntry; + de->m_sName = sName; + + CIccDictEntryPtr ptr; + ptr.ptr = de; + m_Dict->push_back(ptr); + } + + if (sValue.Empty() && bUnSet) + de->UnsetValue(); + else + de->SetValue(sValue); + + return true; +} + +bool CIccTagDict::Set(const icUnicodeChar *szName, const icUnicodeChar *szValue) +{ + CIccUTF16String sName(szName); + + CIccUTF16String sValue; + + if (szValue) { + sValue = szValue; + + return Set(sName, sValue, false); + } + + return Set(sName, sValue, true); +} + +bool CIccTagDict::Set(const char *szName, const char *szValue) +{ + CIccUTF16String sName(szName); + CIccUTF16String sValue; + + if (szValue) { + sValue = szValue; + + return Set(sName, sValue, false); + } + + return Set(sName, sValue, true); +} + +bool CIccTagDict::SetNameLocalized(const CIccUTF16String &sName, CIccTagMultiLocalizedUnicode *pTag) +{ + CIccDictEntry *de = Get(sName); + + if (!de) { + de = new CIccDictEntry; + de->m_sName = sName; + + CIccDictEntryPtr ptr; + ptr.ptr = de; + m_Dict->push_back(ptr); + } + + return de->SetNameLocalized(pTag); +} + +bool CIccTagDict::SetNameLocalized(const icUnicodeChar *szName, CIccTagMultiLocalizedUnicode *pTag) +{ + CIccUTF16String sName(szName); + + return SetNameLocalized(sName, pTag); +} + +bool CIccTagDict::SetNameLocalized(const char *szName, CIccTagMultiLocalizedUnicode *pTag) +{ + CIccUTF16String sName(szName); + + return SetNameLocalized(sName, pTag); +} + +bool CIccTagDict::SetValueLocalized(const CIccUTF16String &sName, CIccTagMultiLocalizedUnicode *pTag) +{ + CIccDictEntry *de = Get(sName); + + if (!de) { + de = new CIccDictEntry; + de->m_sName = sName; + + CIccDictEntryPtr ptr; + ptr.ptr = de; + m_Dict->push_back(ptr); + } + + return de->SetValueLocalized(pTag); +} + +bool CIccTagDict::SetValueLocalized(const icUnicodeChar *szName, CIccTagMultiLocalizedUnicode *pTag) +{ + CIccUTF16String sName(szName); + + return SetValueLocalized(sName, pTag); +} + +bool CIccTagDict::SetValueLocalized(const char *szName, CIccTagMultiLocalizedUnicode *pTag) +{ + CIccUTF16String sName(szName); + + return SetValueLocalized(sName, pTag); +} + +#endif //ICC_UNSUPPORTED_TAG_DICT diff --git a/library/src/main/cpp/icc/IccTagDict.h b/library/src/main/cpp/icc/IccTagDict.h new file mode 100644 index 00000000..0eb47190 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagDict.h @@ -0,0 +1,229 @@ +/** @file +File: IccTagDictTag.h + +Contains: Header for implementation of CIccTagDict +and supporting classes + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Jun 26, 2009 +// Initial CIccDictTag prototype development +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCTAGSUBTAG_H +#define _ICCTAGSUBTAG_H + +#include "IccProfile.h" +#include "IccTag.h" +#include "IccTagFactory.h" +#include "IccUtil.h" +#include +#include +#include + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + + +/** +**************************************************************************** +* Data Class: CIccDictEntry +* +* Purpose: Implementation of a dictionary entry with optional localization of +* name and value +***************************************************************************** +*/ +class ICCPROFLIB_API CIccDictEntry +{ +public: //member functions + CIccDictEntry(); + CIccDictEntry(const CIccDictEntry& IDE); + CIccDictEntry &operator=(const CIccDictEntry &IDE); + virtual ~CIccDictEntry(); + + void Describe(std::string &sDescription); + + icUInt32Number PosRecSize(); + + //Data + CIccUTF16String m_sName; + + const CIccUTF16String &GetValue() { return m_sValue; } + bool IsValueSet() { return m_bValueSet; } + + //GetNameLocalized and GetValueLocalized both give direct access to objects owned by the CIccDirEntry object + CIccTagMultiLocalizedUnicode* GetNameLocalized() { return m_pNameLocalized; } + CIccTagMultiLocalizedUnicode* GetValueLocalized() { return m_pValueLocalized; } + + void UnsetValue() { m_sValue.Clear(); m_bValueSet = false; } + bool SetValue(const CIccUTF16String &sValue); + + //SetNameLocalized and SetValueLocalized both transfer ownership of the argument to the CIccDirEntry object + //deleting access to previous object + bool SetNameLocalized(CIccTagMultiLocalizedUnicode *pNameLocalized); + bool SetValueLocalized(CIccTagMultiLocalizedUnicode *pValueLocalized); + +protected: + CIccUTF16String m_sValue; + bool m_bValueSet; + + CIccTagMultiLocalizedUnicode *m_pNameLocalized; + CIccTagMultiLocalizedUnicode *m_pValueLocalized; +}; + +class CIccDictEntryPtr +{ +public: + CIccDictEntry *ptr; +}; + +/** +**************************************************************************** +* List Class: CIccDictEntry +* +* Purpose: Dictionary is stored as a List of CIccDictEntry objects +***************************************************************************** +*/ +typedef std::list CIccNameValueDict; + +/** +**************************************************************************** +* Class: CIccTagDict +* +* Purpose: A name-value dictionary tag with optional localization +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagDict : public CIccTag +{ +public: + CIccTagDict(); + CIccTagDict(const CIccTagDict &dict); + CIccTagDict &operator=(const CIccTagDict &dict); + virtual CIccTag *NewCopy() const { return new CIccTagDict(*this);} + virtual ~CIccTagDict(); + + virtual icTagTypeSignature GetType() const { return icSigDictType; } + virtual const icChar *GetClassName() const { return "CIccTagDict"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + bool AreNamesUnique() const; + bool AreNamesNonzero() const; + + CIccDictEntry *Get(const char *szName) const; + CIccDictEntry *Get(const icUInt16Number *szName) const; + CIccDictEntry *Get(const CIccUTF16String &sName) const; + + CIccUTF16String GetValue(const char *szName, bool *bIsSet=NULL) const; + CIccUTF16String GetValue(const icUnicodeChar *szName, bool *bIsSet=NULL) const; + CIccUTF16String GetValue(const CIccUTF16String &sName, bool *bIsSet=NULL) const; + + CIccTagMultiLocalizedUnicode* GetNameLocalized(const CIccUTF16String &sName) const; + CIccTagMultiLocalizedUnicode* GetNameLocalized(const icUnicodeChar *szName) const; + CIccTagMultiLocalizedUnicode* GetNameLocalized(const char *szName) const; + + CIccTagMultiLocalizedUnicode* GetValueLocalized(const CIccUTF16String &sName) const; + CIccTagMultiLocalizedUnicode* GetValueLocalized(const icUnicodeChar *szName) const; + CIccTagMultiLocalizedUnicode* GetValueLocalized(const char *szName) const; + + bool Remove(const CIccUTF16String &sName); + bool Remove(const icUnicodeChar *szName); + bool Remove(const char *szName); + + bool Set(const char *szName, const char *szValue=NULL); + bool Set(const icUnicodeChar *szName, const icUnicodeChar *szValue=NULL); + bool Set(const CIccUTF16String &sName, const CIccUTF16String &sValue, bool bUnSet=false); + + bool SetNameLocalized(const char *szName, CIccTagMultiLocalizedUnicode *pTag); + bool SetNameLocalized(const icUnicodeChar *szName, CIccTagMultiLocalizedUnicode *pTag); + bool SetNameLocalized(const CIccUTF16String &sName, CIccTagMultiLocalizedUnicode *pTag); + + bool SetValueLocalized(const char *szName, CIccTagMultiLocalizedUnicode *pTag); + bool SetValueLocalized(const icUnicodeChar *szName, CIccTagMultiLocalizedUnicode *pTag); + bool SetValueLocalized(const CIccUTF16String &sName, CIccTagMultiLocalizedUnicode *pTag); + + CIccNameValueDict *m_Dict; + +protected: + bool m_bBadAlignment; + void Cleanup(); + icUInt32Number MaxPosRecSize(); + + icUInt32Number m_tagSize; + icUInt32Number m_tagStart; +}; + + +//CIccFloatTag support +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif //_ICCTAGDICTTAG_H + diff --git a/library/src/main/cpp/icc/IccTagFactory.cpp b/library/src/main/cpp/icc/IccTagFactory.cpp new file mode 100644 index 00000000..62b3819e --- /dev/null +++ b/library/src/main/cpp/icc/IccTagFactory.cpp @@ -0,0 +1,579 @@ +/** @file + File: IccTagFactory.cpp + + Contains: Implementation of the CIccTag class and creation factories + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Oct 30, 2005 +// Added CICCTag Creation using factory support +// +////////////////////////////////////////////////////////////////////// + +#include "IccTag.h" +#include "IccTagFactory.h" +#include "IccUtil.h" +#include "IccProfile.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +CIccTag* CIccSpecTagFactory::CreateTag(icTagTypeSignature tagSig) +{ + switch(tagSig) { + case icSigSignatureType: + return new CIccTagSignature; + + case icSigTextType: + return new CIccTagText; + + case icSigXYZArrayType: + return new CIccTagXYZ; + + case icSigUInt8ArrayType: + return new CIccTagUInt8; + + case icSigUInt16ArrayType: + return new CIccTagUInt16; + + case icSigUInt32ArrayType: + return new CIccTagUInt32; + + case icSigUInt64ArrayType: + return new CIccTagUInt64; + + case icSigS15Fixed16ArrayType: + return new CIccTagS15Fixed16; + + case icSigU16Fixed16ArrayType: + return new CIccTagU16Fixed16; + + case icSigCurveType: + return new CIccTagCurve; + + case icSigMeasurementType: + return new CIccTagMeasurement; + + case icSigMultiLocalizedUnicodeType: + return new CIccTagMultiLocalizedUnicode; + + case icSigMultiProcessElementType: + return new CIccTagMultiProcessElement(); + + case icSigParametricCurveType: + return new CIccTagParametricCurve; + + case icSigLutAtoBType: + return new CIccTagLutAtoB; + + case icSigLutBtoAType: + return new CIccTagLutBtoA; + + case icSigLut16Type: + return new CIccTagLut16; + + case icSigLut8Type: + return new CIccTagLut8; + + case icSigTextDescriptionType: + return new CIccTagTextDescription; + + case icSigNamedColor2Type: + return new CIccTagNamedColor2; + + case icSigChromaticityType: + return new CIccTagChromaticity; + + case icSigDataType: + return new CIccTagData; + + case icSigDateTimeType: + return new CIccTagDateTime; + +#ifndef ICC_UNSUPPORTED_TAG_DICT + case icSigDictType: + return new CIccTagDict; +#endif + + case icSigColorantOrderType: + return new CIccTagColorantOrder; + + case icSigColorantTableType: + return new CIccTagColorantTable; + + case icSigViewingConditionsType: + return new CIccTagViewingConditions; + + case icSigProfileSequenceDescType: + return new CIccTagProfileSeqDesc; + + case icSigResponseCurveSet16Type: + return new CIccTagResponseCurveSet16; + + case icSigProfileSequceIdType: + return new CIccTagProfileSequenceId; + + case icSigScreeningType: + case icSigUcrBgType: + case icSigCrdInfoType: + + default: + return new CIccTagUnknown; + } +} + +const icChar* CIccSpecTagFactory::GetTagSigName(icTagSignature tagSig) +{ + switch (tagSig) { + case icSigAToB0Tag: + return "AToB0Tag"; + + case icSigAToB1Tag: + return "AToB1Tag"; + + case icSigAToB2Tag: + return "AToB2Tag"; + + case icSigBlueColorantTag: + return "blueColorantTag"; + + case icSigBlueTRCTag: + return "blueTRCTag"; + + case icSigBToA0Tag: + return "BToA0Tag"; + + case icSigBToA1Tag: + return "BToA1Tag"; + + case icSigBToA2Tag: + return "BToA2Tag"; + + case icSigBToD0Tag: + return "BToD0Tag"; + + case icSigBToD1Tag: + return "BToD1Tag"; + + case icSigBToD2Tag: + return "BToD2Tag"; + + case icSigBToD3Tag: + return "BToD3Tag"; + + case icSigCalibrationDateTimeTag: + return "calibrationDateTimeTag"; + + case icSigCharTargetTag: + return "charTargetTag"; + + case icSigChromaticityTag: + return "chromaticityTag"; + + case icSigCopyrightTag: + return "copyrightTag"; + + case icSigCrdInfoTag: + return "crdInfoTag"; + + case icSigDataTag: + return "dataTag"; + + case icSigDateTimeTag: + return "dateTimeTag"; + + case icSigDeviceMfgDescTag: + return "deviceMfgDescTag"; + + case icSigDeviceModelDescTag: + return "deviceModelDescTag"; + + case icSigMetaDataTag: + return "metaDataTag"; + + case icSigDToB0Tag: + return "DToB0Tag"; + + case icSigDToB1Tag: + return "DToB1Tag"; + + case icSigDToB2Tag: + return "DToB2Tag"; + + case icSigDToB3Tag: + return "DToB3Tag"; + + case icSigGamutTag: + return "gamutTag"; + + case icSigGrayTRCTag: + return "grayTRCTag"; + + case icSigGreenColorantTag: + return "greenColorantTag"; + + case icSigGreenTRCTag: + return "greenTRCTag"; + + case icSigLuminanceTag: + return "luminanceTag"; + + case icSigMeasurementTag: + return "measurementTag"; + + case icSigMediaBlackPointTag: + return "mediaBlackPointTag"; + + case icSigMediaWhitePointTag: + return "mediaWhitePointTag"; + + case icSigNamedColor2Tag: + return "namedColor2Tag"; + + case icSigPreview0Tag: + return "preview0Tag"; + + case icSigPreview1Tag: + return "preview1Tag"; + + case icSigPreview2Tag: + return "preview2Tag"; + + case icSigPrintConditionTag: + return "printConditionTag"; + + case icSigProfileDescriptionTag: + return "profileDescriptionTag"; + + case icSigProfileSequenceDescTag: + return "profileSequenceDescTag"; + + case icSigProfileSequceIdTag: + return "profileSequenceIdentifierTag"; + + case icSigPs2CRD0Tag: + return "ps2CRD0Tag"; + + case icSigPs2CRD1Tag: + return "ps2CRD1Tag"; + + case icSigPs2CRD2Tag: + return "ps2CRD2Tag"; + + case icSigPs2CRD3Tag: + return "ps2CRD3Tag"; + + case icSigPs2CSATag: + return "ps2CSATag"; + + case icSigPs2RenderingIntentTag: + return "ps2RenderingIntentTag"; + + case icSigRedColorantTag: + return "redColorantTag"; + + case icSigRedTRCTag: + return "redTRCTag"; + + case icSigScreeningDescTag: + return "screeningDescTag"; + + case icSigScreeningTag: + return "screeningTag"; + + case icSigTechnologyTag: + return "technologyTag"; + + case icSigUcrBgTag: + return "ucrBgTag"; + + case icSigViewingCondDescTag: + return "viewingCondDescTag"; + + case icSigViewingConditionsTag: + return "viewingConditionsTag"; + + case icSigColorantOrderTag: + return "colorantOrderTag"; + + case icSigColorantTableTag: + return "colorantTableTag"; + + case icSigChromaticAdaptationTag: + return "chromaticAdaptationTag"; + + case icSigColorantTableOutTag: + return "colorantTableOutTag"; + + case icSigOutputResponseTag: + return "outputResponseTag"; + + case icSigPerceptualRenderingIntentGamutTag: + return "perceptualRenderingIntentGamutTag"; + + case icSigSaturationRenderingIntentGamutTag: + return "saturationRenderingIntentGamutTag"; + + default: + return NULL; + } + return NULL; +} + +const icChar* CIccSpecTagFactory::GetTagTypeSigName(icTagTypeSignature tagSig) +{ + switch (tagSig) { + case icSigChromaticityType: + return "chromaticityType"; + + case icSigColorantOrderType: + return "colorantOrderType"; + + case icSigColorantTableType: + return "colorantTableType"; + + case icSigCrdInfoType: + return "crdInfoType"; + + case icSigCurveType: + return "curveType"; + + case icSigDataType: + return "dataType"; + + case icSigDateTimeType: + return "dateTimeType"; + + case icSigDeviceSettingsType: + return "deviceSettingsType"; + + case icSigDictType: + return "dictType"; + + case icSigLut16Type: + return "lut16Type"; + + case icSigLut8Type: + return "lut8Type"; + + case icSigLutAtoBType: + return "lutAtoBType"; + + case icSigLutBtoAType: + return "lutBtoAType"; + + case icSigMeasurementType: + return "measurementType"; + + case icSigMultiLocalizedUnicodeType: + return "multiLocalizedUnicodeType"; + + case icSigMultiProcessElementType: + return "multiProcessElementType"; + + case icSigNamedColor2Type: + return "namedColor2Type"; + + case icSigParametricCurveType: + return "parametricCurveType"; + + case icSigResponseCurveSet16Type: + return "responseCurveSet16Type"; + + case icSigProfileSequenceDescType: + return "profileSequenceDescType"; + + case icSigS15Fixed16ArrayType: + return "s15Fixed16 ArrayType"; + + case icSigScreeningType: + return "screeningType"; + + case icSigSignatureType: + return "signatureType"; + + case icSigTextType: + return "textType"; + + case icSigTextDescriptionType: + return "textDescriptionType"; + + case icSigU16Fixed16ArrayType: + return "u16Fixed16 Type"; + + case icSigUcrBgType: + return "ucrBgType"; + + case icSigUInt16ArrayType: + return "uInt16 Type"; + + case icSigUInt32ArrayType: + return "uInt32 Type"; + + case icSigUInt64ArrayType: + return "uInt64 Type"; + + case icSigUInt8ArrayType: + return "uInt8 Type"; + + case icSigViewingConditionsType: + return "viewingConditionsType"; + + case icSigXYZArrayType: + return "XYZ Type"; + + case icSigProfileSequceIdType: + return "profileSequenceIdentifierType"; + + default: + return NULL; + } + + return NULL; +} + +std::auto_ptr CIccTagCreator::theTagCreator; + +CIccTagCreator::~CIccTagCreator() +{ + IIccTagFactory *pFactory = DoPopFactory(true); + + while (pFactory) { + delete pFactory; + pFactory = DoPopFactory(true); + } +} + +CIccTagCreator* CIccTagCreator::GetInstance() +{ + if (!theTagCreator.get()) { + theTagCreator = CIccTagCreatorPtr(new CIccTagCreator); + + theTagCreator->DoPushFactory(new CIccSpecTagFactory); + } + + return theTagCreator.get(); +} + +CIccTag* CIccTagCreator::DoCreateTag(icTagTypeSignature tagTypeSig) +{ + CIccTagFactoryList::iterator i; + CIccTag *rv = NULL; + + for (i=factoryStack.begin(); i!=factoryStack.end(); i++) { + rv = (*i)->CreateTag(tagTypeSig); + if (rv) + break; + } + return rv; +} + +const icChar* CIccTagCreator::DoGetTagSigName(icTagSignature tagSig) +{ + CIccTagFactoryList::iterator i; + const icChar* rv; + + for (i=factoryStack.begin(); i!=factoryStack.end(); i++) { + rv = (*i)->GetTagSigName(tagSig); + if (rv) + return rv; + } + + return NULL; +} + +const icChar* CIccTagCreator::DoGetTagTypeSigName(icTagTypeSignature tagTypeSig) +{ + CIccTagFactoryList::iterator i; + const icChar* rv; + + for (i=factoryStack.begin(); i!=factoryStack.end(); i++) { + rv = (*i)->GetTagTypeSigName(tagTypeSig); + if (rv) + return rv; + } + + return NULL; +} + +void CIccTagCreator::DoPushFactory(IIccTagFactory *pFactory) +{ + factoryStack.push_front(pFactory); +} + +IIccTagFactory* CIccTagCreator::DoPopFactory(bool bAll /*=false*/) +{ +// int nNum = (bAll ? 0 : 1); + + if (factoryStack.size()>0) { + CIccTagFactoryList::iterator i=factoryStack.begin(); + IIccTagFactory* rv = (*i); + factoryStack.pop_front(); + return rv; + } + return NULL; +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccTagFactory.h b/library/src/main/cpp/icc/IccTagFactory.h new file mode 100644 index 00000000..e9e4c2fb --- /dev/null +++ b/library/src/main/cpp/icc/IccTagFactory.h @@ -0,0 +1,322 @@ +/** @file + File: IccTagFactory.h + + Contains: Header for implementation of CIccTagFactory class and + creation factories + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2005-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Oct 30, 2005 +// A CIccTagCreator singleton class has been added to provide general +// support for dynamically creating tag classes using a tag signature. +// Prototype and private tag type support can be added to the system +// by pushing additional IIccTagFactory based objects to the +// singleton CIccTagCreator object. +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCTAGFACTORY_H +#define _ICCTAGFACTORY_H + +#include "IccDefs.h" +#include +#include +#include + +//CIccTag factory support +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +class CIccTag; + +/** + *********************************************************************** + * Class: IIccTagFactory + * + * Purpose: + * IIccTagFactory is a factory pattern interface for CIccTag creation. + * This class is pure virtual. + *********************************************************************** + */ +class IIccTagFactory +{ +public: + virtual ~IIccTagFactory() {} + + /** + * Function: CreateTag(tagTypeSig) + * Create a tag of type tagTypeSig. + * + * Parameter(s): + * tagTypeSig = signature of the ICC tag type for the tag to be created + * + * Returns a new CIccTag object of the given signature type. If the tag + * factory doesn't support creation of tags of type tagTypeSig then it + * should return NULL. + */ + virtual CIccTag* CreateTag(icTagTypeSignature tagTypeSig)=0; + + /** + * Function: GetTagSigName(tagSig) + * Get display name of tagSig. + * + * Parameter(s): + * tagSig = signature of the ICC tag to get a name for + * + * Returns pointer to string containing name of tag if tag is recognized + * by the factory, NULL if the factory doesn't create tagSig tags. + */ + virtual const icChar* GetTagSigName(icTagSignature tagSig)=0; + + /** + * Function: GetTagTypeSigName(tagTypeSig) + * Get display name of tagTypeSig. + * + * Parameter(s): + * tagTypeSig = signature of the ICC tag type to get a name for + * + * Returns pointer to string containing name of tag type if tag is recognized + * by the factory, NULL if the factory doesn't create tagTypeSig tags. + */ + virtual const icChar* GetTagTypeSigName(icTagTypeSignature tagTypeSig)=0; +}; + + +//A CIccTagFactoryList is used by CIccTagCreator to keep track of tag +//creation factories +typedef std::list CIccTagFactoryList; + + +/** + *********************************************************************** + * Class: CIccSpecTagFactory + * + * Purpose: + * CIccSpecTagFactory provides creation of CIccTag's defined by the ICC profile + * specification. The CIccTagCreator always creates a CIccSpecTagFactory. + *********************************************************************** + */ +class CIccSpecTagFactory : public IIccTagFactory +{ +public: + /** + * Function: CreateTag(tagTypeSig) + * Create a tag of type tagTypeSig. + * + * Parameter(s): + * tagTypeSig = signature of the ICC tag type for the tag to be created + * + * Returns a new CIccTag object of the given signature type. + * Unrecognized tagTypeSig's will be created as a CIccTagUnknown object. + */ + virtual CIccTag* CreateTag(icTagTypeSignature tagSig); + + /** + * Function: GetTagSigName(tagSig) + * Get display name of tagSig. + * + * Parameter(s): + * tagName = string to put tag name into, + * tagSig = signature of the ICC tag type to get a name for + * + * Returns pointer to string containing name of tag if tag is recognized + * by the factory, NULL if the factory doesn't create tagSig tags. + */ + virtual const icChar* GetTagSigName(icTagSignature tagSig); + + /** + * Function: GetTagTypeSigName(tagTypeSig) + * Get display name of tagTypeSig. + * + * Parameter(s): + * tagName = string to put tag name into, + * tagTypeSig = signature of the ICC tag type to get a name for + * + * Returns pointer to string containing name of tag type if tag is recognized + * by the factory, NULL if the factory doesn't create tagTypeSig tags. + */ + virtual const icChar* GetTagTypeSigName(icTagTypeSignature tagTypeSig); +}; + +class CIccTagCreator; + +typedef std::auto_ptr CIccTagCreatorPtr; + +/** + *********************************************************************** + * Class: CIccTagCreator + * + * Purpose: + * CIccTagCreator uses a singleton pattern to provide dynamically + * upgradeable CIccTag derived object creation based on tag signature. + *********************************************************************** + */ +class CIccTagCreator +{ +public: + ~CIccTagCreator(); + + /** + * Function: CreateTag(tagTypeSig) + * Create a tag of type tagTypeSig. + * + * Parameter(s): + * tagTypeSig = signature of the ICC tag type for the tag to be created + * + * Returns a new CIccTag object of the given signature type. + * Each factory in the factoryStack is used until a factory supports the + * signature type. + */ + static CIccTag* CreateTag(icTagTypeSignature tagTypeSig) + { return CIccTagCreator::GetInstance()->DoCreateTag(tagTypeSig); } + + /** + * Function: GetTagSigName(tagSig) + * Get display name of tagSig. + * + * Parameter(s): + * tagSig = signature of the ICC tag to get a name for + * + * Returns ptr to string containing name of tag type if it is recognized + * by any factory, NULL if all factories do not create tagTypeSig tags. + */ + static const icChar* GetTagSigName(icTagSignature tagTypeSig) + { return CIccTagCreator::GetInstance()->DoGetTagSigName(tagTypeSig); } + + + /** + * Function: GetTagTypeSigName(tagTypeSig) + * Get display name of tagTypeSig. + * + * Parameter(s): + * tagTypeSig = signature of the ICC tag type to get a name for + * + * Returns ptr to string containing name of tag type if it is recognized by + * any factory, NULL if all factories do not create tagTypeSig tags. + */ + static const icChar* GetTagTypeSigName(icTagTypeSignature tagTypeSig) + { return CIccTagCreator::GetInstance()->DoGetTagTypeSigName(tagTypeSig); } + + /** + * Function: PushFactory(pFactory) + * Add an IIccTagFactory to the stack of tag factories tracked by the system. + * + * Parameter(s): + * pFactory = pointer to an IIccTagFactory object to add to the system. + * The pFactory must be created with new, and will be owned CIccTagCreator + * until popped off the stack using PopFactory(). Any factories not + * popped off will be taken care of properly on application shutdown. + * + */ + static void PushFactory(IIccTagFactory *pFactory) + { CIccTagCreator::GetInstance()->CIccTagCreator::DoPushFactory(pFactory); } + + /** + * Function: PopFactory() + * Remove the top IIccTagFactory from the stack of tag factories tracked by the system. + * + * Parameter(s): + * None + * + * Returns the top IIccTagFactory from the stack of tag factories tracked by the system. + * The returned tag factory is no longer owned by the system and needs to be deleted + * to avoid memory leaks. + * + * Note: The initial CIccSpecTagFactory cannot be popped off the stack. + */ + static IIccTagFactory* PopFactory() + { return CIccTagCreator::GetInstance()->DoPopFactory(); } + +private: + /**Only GetInstance() can create the signleton*/ + CIccTagCreator() { } + + /** + * Function: GetInstance() + * Private static function to access singleton CiccTagCreator Object. + * + * Parameter(s): + * None + * + * Returns the singleton CIccTagCreator object. It will allocate + * a new one and push a single CIccSpecTag Factory object onto the factory + * stack if the singleton has not been intialized. + */ + static CIccTagCreator* GetInstance(); + + CIccTag* DoCreateTag(icTagTypeSignature tagTypeSig); + const icChar *DoGetTagSigName(icTagSignature tagSig); + const icChar *DoGetTagTypeSigName(icTagTypeSignature tagTypeSig); + void DoPushFactory(IIccTagFactory *pFactory); + IIccTagFactory* DoPopFactory(bool bAll=false); + + static CIccTagCreatorPtr theTagCreator; + + CIccTagFactoryList factoryStack; +}; + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif //_ICCTAGFACTORY_H diff --git a/library/src/main/cpp/icc/IccTagLut.cpp b/library/src/main/cpp/icc/IccTagLut.cpp new file mode 100644 index 00000000..1aa7b313 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagLut.cpp @@ -0,0 +1,4842 @@ +/** @file + File: IccTagLut.cpp + + Contains: Implementation of the Lut Tag classes + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +// -Moved LUT tags to separate file 4-30-2005 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) + #pragma warning( disable: 4786) //disable warning in + #include +#endif +#include +#include +#include +#include +#include "IccTag.h" +#include "IccUtil.h" +#include "IccProfile.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** +**************************************************************************** +* Name: CIccCurve::Find +* +* Purpose: Read in the tag contents into a data block +* +* Args: +* v = index to be searched, +* v0 = index less than/equal to v, +* p0 = the value at index v0, +* v1 = index greater than/equal to v, +* p1 = value at index v1 +* +* Return: The value at the requested index +* +***************************************************************************** +*/ +icFloatNumber CIccCurve::Find(icFloatNumber v, + icFloatNumber p0, icFloatNumber v0, + icFloatNumber p1, icFloatNumber v1) +{ + if (v<=v0) + return p0; + if (v>=v1) + return p1; + + if (p1-p0 <= 0.00001) { + icFloatNumber d0 = fabs(v-v0); + icFloatNumber d1 = fabs(v1-v); + + if (d00) + m_Curve = (icFloatNumber*)calloc(nSize, sizeof(icFloatNumber)); + else + m_Curve = NULL; +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::CIccTagCurve +* +* Purpose: Copy Constructor +* +* Args: +* ITCurve = The CIccTagCurve object to be copied +***************************************************************************** +*/ +CIccTagCurve::CIccTagCurve(const CIccTagCurve &ITCurve) +{ + m_nSize = ITCurve.m_nSize; + m_nMaxIndex = ITCurve.m_nMaxIndex; + + m_Curve = (icFloatNumber*)calloc(m_nSize, sizeof(icFloatNumber)); + memcpy(m_Curve, ITCurve.m_Curve, m_nSize*sizeof(icFloatNumber)); +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::operator= +* +* Purpose: Copy Operator +* +* Args: +* CurveTag = The CIccTagCurve object to be copied +***************************************************************************** +*/ +CIccTagCurve &CIccTagCurve::operator=(const CIccTagCurve &CurveTag) +{ + if (&CurveTag == this) + return *this; + + m_nSize = CurveTag.m_nSize; + m_nMaxIndex = CurveTag.m_nMaxIndex; + + if (m_Curve) + free(m_Curve); + m_Curve = (icFloatNumber*)calloc(m_nSize, sizeof(icFloatNumber)); + memcpy(m_Curve, CurveTag.m_Curve, m_nSize*sizeof(icFloatNumber)); + + return *this; +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::~CIccTagCurve +* +* Purpose: Destructor +* +***************************************************************************** +*/ +CIccTagCurve::~CIccTagCurve() +{ + if (m_Curve) + free(m_Curve); +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::Read +* +* Purpose: Read in the tag contents into a data block +* +* Args: +* size - # of bytes in tag, +* pIO - IO object to read tag from +* +* Return: +* true = successful, false = failure +***************************************************************************** +*/ +bool CIccTagCurve::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number) > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number nSize; + + if (!pIO->Read32(&nSize)) + return false; + + SetSize(nSize, icInitNone); + + if (m_nSize) { + if (pIO->Read16Float(m_Curve, m_nSize)!=(icInt32Number)m_nSize) + return false; + } + + return true; +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::Write +* +* Purpose: Write the tag to a file +* +* Args: +* pIO - The IO object to write tag to. +* +* Return: +* true = succesful, false = failure +***************************************************************************** +*/ +bool CIccTagCurve::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write32(&m_nSize)) + return false; + + if (m_nSize) + if (pIO->Write16Float(m_Curve, m_nSize)!=(icInt32Number)m_nSize) + return false; + + pIO->Align32(); + + return true; +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::Describe +* +* Purpose: Dump data associated with the tag to a string +* +* Args: +* sDescription - string to concatenate tag dump to +***************************************************************************** +*/ +void CIccTagCurve::Describe(std::string &sDescription) +{ + icChar buf[128], *ptr; + + if (!m_nSize) { + sprintf(buf, "BEGIN_CURVE In_Out\r\n"); + sDescription += buf; + sDescription += "Y = X\r\n"; + } + else if (m_nSize==1) { + icFloatNumber dGamma = (icFloatNumber)(m_Curve[0] * 256.0); + sprintf(buf, "BEGIN_CURVE In_Out\r\n"); + sDescription += buf; + sprintf(buf, "Y = X ^ %.4lf\r\n", dGamma); + sDescription += buf; + } + else { + int i; + + sprintf(buf, "BEGIN_LUT In_Out 1 1\r\n"); + sDescription += buf; + sDescription += "IN OUT\r\n"; + + for (i=0; i<(int)m_nSize; i++) { + ptr = buf; + + icColorValue(buf, (icFloatNumber)i/(m_nSize-1), icSigMCH1Data, 1); + ptr += strlen(buf); + + strcpy(ptr, " "); + ptr ++; + + icColorValue(ptr, m_Curve[i], icSigMCH1Data, 1); + + ptr += strlen(ptr); + + strcpy(ptr, "\r\n"); + + sDescription += buf; + } + } + sDescription += "\r\n"; +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::DumpLut +* +* Purpose: Dump data associated with the tag to a string. Basically has +* the same function as Describe() +* +* Args: +* sDescription = string to concatenate tag dump to, +* szName = name of the curve to be printed, +* csSig = color space signature of the LUT data, +* nIndex = the channel number of color space +***************************************************************************** +*/ +void CIccTagCurve::DumpLut(std::string &sDescription, const icChar *szName, + icColorSpaceSignature csSig, int nIndex) +{ + icChar buf[128], *ptr; + + if (!m_nSize) { + sprintf(buf, "BEGIN_CURVE %s\r\n", szName); + sDescription += buf; + sDescription += "Y = X\r\n"; + } + else if (m_nSize==1) { + icFloatNumber dGamma = (icFloatNumber)(m_Curve[0] * 256.0); + sprintf(buf, "BEGIN_CURVE %s\r\n", szName); + sDescription += buf; + sprintf(buf, "Y = X ^ %.4lf\r\n", dGamma); + sDescription += buf; + } + else { + int i; + + sprintf(buf, "BEGIN_LUT %s 1 1\r\n", szName); + sDescription += buf; + sDescription += "IN OUT\r\n"; + + sDescription.reserve(sDescription.size() + m_nSize * 20); + + for (i=0; i<(int)m_nSize; i++) { + ptr = buf; + + icColorValue(buf, (icFloatNumber)i/(m_nSize-1), csSig, nIndex); + ptr += strlen(buf); + + strcpy(ptr, " "); + ptr ++; + + icColorValue(ptr, m_Curve[i], csSig, nIndex); + + ptr += strlen(ptr); + + strcpy(ptr, "\r\n"); + + sDescription += buf; + } + } + sDescription += "\r\n"; +} + + +/** +**************************************************************************** +* Name: CIccTagCurve::SetSize +* +* Purpose: Sets the size of the curve array. +* +* Args: +* nSize - number of entries in the curve, +* nSizeOpt - flag to zero newly formed values +***************************************************************************** +*/ +void CIccTagCurve::SetSize(icUInt32Number nSize, icTagCurveSizeInit nSizeOpt/*=icInitZero*/) +{ + if (nSize==m_nSize) + return; + + if (!nSize && m_Curve) { + free(m_Curve); + m_Curve = NULL; + } + else { + if (!m_Curve) + m_Curve = (icFloatNumber*)malloc(nSize*sizeof(icFloatNumber)); + else + m_Curve = (icFloatNumber*)realloc(m_Curve, nSize*sizeof(icFloatNumber)); + + switch (nSizeOpt) { + case icInitNone: + default: + break; + + case icInitZero: + if (m_nSize < nSize) { + memset(&m_Curve[m_nSize], 0, (nSize-m_nSize)*sizeof(icFloatNumber)); + } + break; + + case icInitIdentity: + if (nSize>1) { + icUInt32Number i; + icFloatNumber last = (icFloatNumber)(nSize-1); + + for (i=0; i(1.0-VERYSMALLNUM) && num<(1.0+VERYSMALLNUM)); +} + +/** +**************************************************************************** +* Name: CIccTagCurve::IsIdentity +* +* Purpose: Checks if this is an identity curve. +* +* Return: true if the curve is an identity +* +***************************************************************************** +*/ +bool CIccTagCurve::IsIdentity() +{ + if (!m_nSize) { + return true; + } + + if (m_nSize==1) { + return IsUnity(icFloatNumber(m_Curve[0]*65535.0/256.0)); + } + + icUInt32Number i; + for (i=0; iVERYSMALLNUM) { + return false; + } + } + + return true; +} + +/** +**************************************************************************** +* Name: CIccTagCurve::Apply +* +* Purpose: Applies the curve to the value passed. +* +* Args: +* v = value to be passed through the curve. +* +* Return: The value modified by the curve. +* +***************************************************************************** +*/ +icFloatNumber CIccTagCurve::Apply(icFloatNumber v) +{ + if(v<0.0) v = 0.0; + else if(v>1.0) v = 1.0; + + icUInt32Number nIndex = (icUInt32Number)(v * m_nMaxIndex); + + if (!m_nSize) { + return v; + } + if (m_nSize==1) { + //Convert 0.0 to 1.0 float to 16bit and then convert from u8Fixed8Number + icFloatNumber dGamma = (icFloatNumber)(m_Curve[0] * 65535.0 / 256.0); + return pow(v, dGamma); + } + if (nIndex == m_nMaxIndex) { + return m_Curve[nIndex]; + } + else { + icFloatNumber nDif = v*m_nMaxIndex - nIndex; + icFloatNumber p0 = m_Curve[nIndex]; + + icFloatNumber rv = p0 + (m_Curve[nIndex+1]-p0)*nDif; + if (rv>1.0) + rv=1.0; + + return rv; + } +} + + +/** +****************************************************************************** +* Name: CIccTagCurve::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagCurve::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (sig==icSigBlueTRCTag || sig==icSigRedTRCTag || sig==icSigGreenTRCTag || sig==icSigGrayTRCTag) { + if (m_nSize>1) { + if (m_Curve) { + if (m_Curve[0]>0.0 || m_Curve[m_nSize-1]<1.0) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Curve cannot be accurately inverted.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + } + } + } + + return rv; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::CIccTagParametricCurve +* +* Purpose: Constructor +* +***************************************************************************** +*/ +CIccTagParametricCurve::CIccTagParametricCurve() +{ + m_nFunctionType = 0xffff; + m_nNumParam = 0; + m_dParam = NULL; + m_nReserved2 = 0; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::CIccTagParametricCurve +* +* Purpose: Copy Constructor +* +* Args: +* ITPC = The CIccTagParametricCurve object to be copied +***************************************************************************** +*/ +CIccTagParametricCurve::CIccTagParametricCurve(const CIccTagParametricCurve &ITPC) +{ + m_nFunctionType = ITPC.m_nFunctionType; + m_nNumParam = ITPC.m_nNumParam; + + m_dParam = new icFloatNumber[m_nNumParam]; + memcpy(m_dParam, ITPC.m_dParam, m_nNumParam*sizeof(icFloatNumber)); +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::operator= +* +* Purpose: Copy Operator +* +* Args: +* ParamCurveTag = The CIccTagParametricCurve object to be copied +***************************************************************************** +*/ +CIccTagParametricCurve &CIccTagParametricCurve::operator=(const CIccTagParametricCurve &ParamCurveTag) +{ + if (&ParamCurveTag == this) + return *this; + + m_nFunctionType = ParamCurveTag.m_nFunctionType; + m_nNumParam = ParamCurveTag.m_nNumParam; + + if (m_dParam) + delete [] m_dParam; + m_dParam = new icFloatNumber[m_nNumParam]; + memcpy(m_dParam, ParamCurveTag.m_dParam, m_nNumParam*sizeof(icFloatNumber)); + + return *this; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::~CIccTagParametricCurve +* +* Purpose: Destructor +* +***************************************************************************** +*/ +CIccTagParametricCurve::~CIccTagParametricCurve() +{ + if (m_dParam) + delete [] m_dParam; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::Read +* +* Purpose: Read in the tag contents into a data block +* +* Args: +* size - # of bytes in tag, +* pIO - IO object to read tag from +* +* Return: +* true = successful, false = failure +***************************************************************************** +*/ +bool CIccTagParametricCurve::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt16Number nFunctionType; + + icUInt32Number nHdrSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + 2*sizeof(icUInt16Number); + + if ( nHdrSize > size) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read16(&nFunctionType) || + !pIO->Read16(&m_nReserved2)) + return false; + + SetFunctionType(nFunctionType); + + if (!m_nNumParam) { + m_nNumParam = (icUInt16Number)((size-nHdrSize) / sizeof(icS15Fixed16Number)); + m_dParam = new icFloatNumber[m_nNumParam]; + } + + if (m_nNumParam) { + int i; + if (nHdrSize + m_nNumParam*sizeof(icS15Fixed16Number) > size) + return false; + + for (i=0; iRead32(&num, 1)) + return false; + m_dParam[i]=icFtoD(num); + } + } + + return true; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::Write +* +* Purpose: Write the tag to a file +* +* Args: +* pIO - The IO object to write tag to. +* +* Return: +* true = succesful, false = failure +***************************************************************************** +*/ +bool CIccTagParametricCurve::Write(CIccIO *pIO) +{ + icTagTypeSignature sig; + + if (!pIO) { + return false; + } + + sig = GetType(); + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write16(&m_nFunctionType) || + !pIO->Write16(&m_nReserved2)) + return false; + + if (m_nNumParam) { + int i; + for (i=0; iWrite32(&num, 1)) + return false; + } + } + + if (!pIO->Align32()) + return false; + + return true; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::Describe +* +* Purpose: Dump data associated with the tag to a string +* +* Args: +* sDescription - string to concatenate tag dump to +***************************************************************************** +*/ +void CIccTagParametricCurve::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sprintf(buf, "FunctionType: %04Xh\r\n", m_nFunctionType); + sDescription += buf; + + switch(m_nFunctionType) { +case 0x0000: + sprintf(buf, "Y = X ^ %.4lf\r\n", m_dParam[0]); + sDescription += buf; + return; + +case 0x0001: + sprintf(buf, "Y = 0 when (X < %.4lf / %.4lf)\r\n", + -m_dParam[2], m_dParam[1]); + sDescription += buf; + + sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf when (X >= %.4lf / %.4lf)\r\n", + m_dParam[1], m_dParam[2], m_dParam[0], + m_dParam[2], m_dParam[1]); + sDescription += buf; + return; + +case 0x0002: + sprintf(buf, "Y = %.4lf when (X < %.4lf / %.4lf)\r\n", m_dParam[3], + -m_dParam[2], m_dParam[1]); + sDescription += buf; + + sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf + %.4lf when (X >= %.4lf / %.4lf)\r\n", + m_dParam[1], m_dParam[2], m_dParam[0], + m_dParam[3], + -m_dParam[2], m_dParam[1]); + sDescription += buf; + return; + +case 0x0003: + sprintf(buf, "Y = %lf * X when (X < %.4lf)\r\n", + m_dParam[3], m_dParam[4]); + sDescription += buf; + + sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf when (X >= %.4lf)\r\n", + m_dParam[1], m_dParam[2], m_dParam[0], + m_dParam[4]); + sDescription += buf; + return; + +case 0x0004: + sprintf(buf, "Y = %lf * X + %.4lf when (X < %.4lf)\r\n", + m_dParam[3], m_dParam[6], m_dParam[4]); + sDescription += buf; + + sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf + %.4lf when (X >= %.4lf)\r\n", + m_dParam[1], m_dParam[2], m_dParam[0], + m_dParam[5], m_dParam[4]); + sDescription += buf; + return; + +default: + int i; + sprintf(buf, "Unknown Function with %d parameters:\r\n", m_nNumParam); + sDescription += buf; + + for (i=0; i= -b/a) { + return (icFloatNumber)pow((double)a*X + b, (double)m_dParam[0]); + } + else { + return 0; + } + + case 0x0002: + a=m_dParam[1]; + b=m_dParam[2]; + + if (X >= -b/a) { + return (icFloatNumber)pow((double)a*X + b, (double)m_dParam[0]) + m_dParam[3]; + } + else { + return m_dParam[3]; + } + + case 0x0003: + if (X >= m_dParam[4]) { + return (icFloatNumber)pow((double)m_dParam[1]*X + m_dParam[2], (double)m_dParam[0]); + } + else { + return m_dParam[3]*X; + } + + case 0x0004: + if (X >= m_dParam[4]) { + return (icFloatNumber)pow((double)m_dParam[1]*X + m_dParam[2], (double)m_dParam[0]) + m_dParam[5]; + } + else { + return m_dParam[3]*X + m_dParam[6]; + } + + default: + return X; + } +} + + +/** +****************************************************************************** +* Name: CIccTagParametricCurve::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagParametricCurve::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (m_nReserved2!=0) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Reserved Value must be zero.\r\n"; + + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + switch(m_nFunctionType) { +case 0x0000: + if (m_nNumParam!=1) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Number of parameters inconsistent with function type.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + +case 0x0001: + if (m_nNumParam!=3) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Number of parameters inconsistent with function type.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + +case 0x0002: + if (m_nNumParam!=4) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Number of parameters inconsistent with function type.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + +case 0x0003: + if (m_nNumParam!=5) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Number of parameters inconsistent with function type.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + +case 0x0004: + if (m_nNumParam!=7) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Number of parameters inconsistent with function type.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + break; + +default: + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Unknown function type.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + if (sig==icSigBlueTRCTag || sig==icSigRedTRCTag || sig==icSigGreenTRCTag || sig==icSigGrayTRCTag) { + icFloatNumber lval = DoApply(0.0); + icFloatNumber uval = DoApply(1.0); + if (lval>0.0 || uval<1.0) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Curve cannot be accurately inverted.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + } + + return rv; +} + +/** +**************************************************************************** +* Name: CIccMatrix::CIccMatrix +* +* Purpose: Constructor +* +* Args: +* bUseConstants = true if the matrix contains additional row for constants +***************************************************************************** +*/ +CIccMatrix::CIccMatrix(bool bUseConstants/*=true*/) +{ + m_bUseConstants = bUseConstants; + m_e[0] = m_e[4] = m_e[8] = 1.0; + m_e[1] = m_e[2] = m_e[3] = + m_e[5] = m_e[6] = m_e[7] = 0.0; + + if (!m_bUseConstants) { + m_e[9] = m_e[10] = m_e[11] = 0.0; + } +} + + +/** +**************************************************************************** +* Name: CIccMatrix::CIccMatrix +* +* Purpose: Copy Constructor +* +* Args: +* MatrixClass = The CIccMatrix object to be copied +***************************************************************************** +*/ +CIccMatrix::CIccMatrix(const CIccMatrix &MatrixClass) +{ + m_bUseConstants = MatrixClass.m_bUseConstants; + memcpy(m_e, MatrixClass.m_e, sizeof(m_e)); +} + + +/** +**************************************************************************** +* Name: CIccMatrix::operator= +* +* Purpose: Copy Operator +* +* Args: +* MatrixClass = The CIccMatrix object to be copied +***************************************************************************** +*/ +CIccMatrix &CIccMatrix::operator=(const CIccMatrix &MatrixClass) +{ + if (&MatrixClass == this) + return *this; + + m_bUseConstants = MatrixClass.m_bUseConstants; + memcpy(m_e, MatrixClass.m_e, sizeof(m_e)); + + return *this; +} + + +/** +**************************************************************************** +* Name: CIccTagParametricCurve::DumpLut +* +* Purpose: Dump the matrix data to a string. +* +* Args: +* sDescription = string to concatenate tag dump to, +* szName = name of the curve to be printed +***************************************************************************** +*/ +void CIccMatrix::DumpLut(std::string &sDescription, const icChar *szName) +{ + icChar buf[128]; + + sprintf(buf, "BEGIN_MATRIX %s\r\n", szName); + sDescription += buf; + + if (!m_bUseConstants) { + sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n", + m_e[0], m_e[1], m_e[2]); + sDescription += buf; + sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n", + m_e[3], m_e[4], m_e[5]); + sDescription += buf; + sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n", + m_e[6], m_e[7], m_e[8]); + sDescription += buf; + } + else { + sprintf(buf, "%8.4lf %8.4lf %8.4lf + %8.4lf\r\n", + m_e[0], m_e[1], m_e[2], m_e[9]); + sDescription += buf; + sprintf(buf, "%8.4lf %8.4lf %8.4lf + %8.4lf\r\n", + m_e[3], m_e[4], m_e[5], m_e[10]); + sDescription += buf; + sprintf(buf, "%8.4lf %8.4lf %8.4lf + %8.4lf\r\n", + m_e[6], m_e[7], m_e[8], m_e[11]); + sDescription += buf; + } + sDescription += "\r\n"; +} + +/** +**************************************************************************** +* Name: CIccMatrix::IsIdentity +* +* Purpose: Checks if the matrix is identity +* +* Return: +* true if matrix is identity and uses no constants, else false +* +***************************************************************************** +*/ +bool CIccMatrix::IsIdentity() +{ + if (m_bUseConstants) { + if (fabs(m_e[9])>0.0 || fabs(m_e[10])>0.0 || fabs(m_e[11])>0.0) { + return false; + } + } + + if (!IsUnity(m_e[0]) || !IsUnity(m_e[4]) || !IsUnity(m_e[8])) { + return false; + } + + if (fabs(m_e[1])>0.0 || fabs(m_e[2])>0.0 || fabs(m_e[3])>0.0 || + fabs(m_e[5])>0.0 || fabs(m_e[6])>0.0 || fabs(m_e[7])>0.0) + { + return false; + } + + return true; +} + +/** +**************************************************************************** +* Name: CIccMatrix::Apply +* +* Purpose: Multiplies the pixel by the matrix. +* +* Args: +* Pixel = Pixel to be multiplied by the matrix +* +***************************************************************************** +*/ +void CIccMatrix::Apply(icFloatNumber *Pixel) const +{ + icFloatNumber a=Pixel[0]; + icFloatNumber b=Pixel[1]; + icFloatNumber c=Pixel[2]; + + icFloatNumber x = m_e[0]*a + m_e[1]*b + m_e[2]*c; + icFloatNumber y = m_e[3]*a + m_e[4]*b + m_e[5]*c; + icFloatNumber z = m_e[6]*a + m_e[7]*b + m_e[8]*c; + + if (m_bUseConstants) { + x += m_e[9]; + y += m_e[10]; + z += m_e[11]; + } + + Pixel[0] = x; + Pixel[1] = y; + Pixel[2] = z; +} + + +/** +****************************************************************************** +* Name: CIccMatrix::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccMatrix::Validate(icTagTypeSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = icValidateOK; + + if (sig==icSigLut8Type || sig==icSigLut16Type) { + if (pProfile->m_Header.pcs!=icSigXYZData) { + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + icFloatNumber sum=0.0; + for (int i=0; i<9; i++) { + sum += m_e[i]; + } + if (m_e[0]!=1.0 || m_e[4]!=1.0 || m_e[9]!=1.0 || sum!=3.0) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Matrix must be identity.\r\n"; + rv = icValidateNonCompliant; + } + } + } + + return rv; +} + + +static icFloatNumber ClutUnitClip(icFloatNumber v) +{ + if (v<0) + return 0; + else if (v>1.0) + return 1.0; + + return v; +} + +/** + **************************************************************************** + * Name: CIccCLUT::CIccCLUT + * + * Purpose: Constructor + * + * Args: + * nInputChannels = number of input channels, + * nOutputChannels = number of output channels + * + ***************************************************************************** + */ +CIccCLUT::CIccCLUT(icUInt8Number nInputChannels, icUInt16Number nOutputChannels, icUInt8Number nPrecision/*=2*/) +{ + m_nInput = nInputChannels; + m_nOutput = nOutputChannels; + m_nPrecision = nPrecision; + m_pData = NULL; + m_nOffset = NULL; + m_g = NULL; + m_ig = NULL; + m_s = NULL; + m_df = NULL; + memset(&m_nReserved2, 0 , sizeof(m_nReserved2)); + + UnitClip = ClutUnitClip; +} + + +/** + **************************************************************************** + * Name: CIccCLUT::CIccCLUT + * + * Purpose: Copy Constructor + * + * Args: + * ICLUT = The CIccCLUT object to be copied + ***************************************************************************** + */ +CIccCLUT::CIccCLUT(const CIccCLUT &ICLUT) +{ + m_pData = NULL; + m_nOffset = NULL; + m_g = NULL; + m_ig = NULL; + m_s = NULL; + m_df = NULL; + m_nInput = ICLUT.m_nInput; + m_nOutput = ICLUT.m_nOutput; + m_nPrecision = ICLUT.m_nPrecision; + m_nNumPoints = ICLUT.m_nNumPoints; + + m_csInput = ICLUT.m_csInput; + m_csOutput = ICLUT.m_csOutput; + + memcpy(m_GridPoints, ICLUT.m_GridPoints, sizeof(m_GridPoints)); + memcpy(m_DimSize, ICLUT.m_DimSize, sizeof(m_DimSize)); + memcpy(m_GridAdr, ICLUT.m_GridAdr, sizeof(m_GridAdr)); + memcpy(&m_nReserved2, &ICLUT.m_nReserved2, sizeof(m_nReserved2)); + + int num = NumPoints()*m_nOutput; + m_pData = new icFloatNumber[num]; + memcpy(m_pData, ICLUT.m_pData, num*sizeof(icFloatNumber)); + + UnitClip = ICLUT.UnitClip; +} + + +/** + **************************************************************************** + * Name: CIccCLUT::operator= + * + * Purpose: Copy Operator + * + * Args: + * CLUTTag = The CIccCLUT object to be copied + ***************************************************************************** + */ +CIccCLUT &CIccCLUT::operator=(const CIccCLUT &CLUTTag) +{ + if (&CLUTTag == this) + return *this; + + m_nInput = CLUTTag.m_nInput; + m_nOutput = CLUTTag.m_nOutput; + m_nPrecision = CLUTTag.m_nPrecision; + m_nNumPoints = CLUTTag.m_nNumPoints; + + m_csInput = CLUTTag.m_csInput; + m_csOutput = CLUTTag.m_csOutput; + + memcpy(m_GridPoints, CLUTTag.m_GridPoints, sizeof(m_GridPoints)); + memcpy(m_DimSize, CLUTTag.m_DimSize, sizeof(m_DimSize)); + memcpy(m_GridAdr, CLUTTag.m_GridAdr, sizeof(m_GridAdr)); + memcpy(m_nReserved2, &CLUTTag.m_nReserved2, sizeof(m_nReserved2)); + + int num; + if (m_pData) + delete [] m_pData; + num = NumPoints()*m_nOutput; + m_pData = new icFloatNumber[num]; + memcpy(m_pData, CLUTTag.m_pData, num*sizeof(icFloatNumber)); + + UnitClip = CLUTTag.UnitClip; + + return *this; +} + + + +/** + **************************************************************************** + * Name: CIccCLUT::~CIccCLUT + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccCLUT::~CIccCLUT() +{ + if (m_pData) + delete [] m_pData; + + if (m_nOffset) + delete [] m_nOffset; + + if (m_g) + delete [] m_g; + + if (m_ig) + delete [] m_ig; + + if (m_s) + delete [] m_s; + + if (m_df) + delete [] m_df; +} + +/** + **************************************************************************** + * Name: CIccCLUT::Init + * + * Purpose: Initializes and sets the size of the CLUT + * + * Args: + * nGridPoints = number of grid points in the CLUT + ***************************************************************************** + */ +bool CIccCLUT::Init(icUInt8Number nGridPoints) +{ + memset(&m_GridPoints, 0, sizeof(m_GridPoints)); + memset(m_GridPoints, nGridPoints, m_nInput); + return Init(&m_GridPoints[0]); +} + +/** + **************************************************************************** + * Name: CIccCLUT::Init + * + * Purpose: Initializes and sets the size of the CLUT + * + * Args: + * pGridPoints = number of grid points in the CLUT + ***************************************************************************** + */ +bool CIccCLUT::Init(icUInt8Number *pGridPoints) +{ + memset(m_nReserved2, 0, sizeof(m_nReserved2)); + if (pGridPoints!=&m_GridPoints[0]) { + memcpy(m_GridPoints, pGridPoints, m_nInput); + if (m_nInput<16) + memset(m_GridPoints+m_nInput, 0, 16-m_nInput); + } + + if (m_pData) { + delete [] m_pData; + } + + int i=m_nInput-1; + + m_DimSize[i] = m_nOutput; + m_nNumPoints = m_GridPoints[i]; + for (i--; i>=0; i--) { + m_DimSize[i] = m_DimSize[i+1] * m_GridPoints[i+1]; + m_nNumPoints *= m_GridPoints[i]; + } + + icUInt32Number nSize = NumPoints() * m_nOutput; + + if (!nSize) + return false; + + m_pData = new icFloatNumber[nSize]; + + return (m_pData != NULL); +} + + +/** + **************************************************************************** + * Name: CIccCLUT::ReadData + * + * Purpose: Reads the CLUT data points into the data buffer + * + * Args: + * size = # of bytes in the tag, + * pIO = IO object to read data from, + * nPrecision = data precision (8bit encoded as 1 or 16bit encoded as 2) + * + * Return: + * true = data read succesfully, + * false = read data failed + ***************************************************************************** + */ +bool CIccCLUT::ReadData(icUInt32Number size, CIccIO *pIO, icUInt8Number nPrecision) +{ + icUInt32Number nNum=NumPoints() * m_nOutput; + + if (nNum * nPrecision > size) + return false; + + if (nPrecision==1) { + if (pIO->Read8Float(m_pData, nNum)!=(icInt32Number)nNum) + return false; + } + else if (nPrecision==2) { + if (pIO->Read16Float(m_pData, nNum)!=(icInt32Number)nNum) + return false; + } + else + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccCLUT::WriteData + * + * Purpose: Writes the CLUT data points from the data buffer + * + * Args: + * pIO = IO object to write data to, + * nPrecision = data precision (8bit encoded as 1 or 16bit encoded as 2) + * + * Return: + * true = data written succesfully, + * false = write operation failed + ***************************************************************************** + */ +bool CIccCLUT::WriteData(CIccIO *pIO, icUInt8Number nPrecision) +{ + icUInt32Number nNum=NumPoints() * m_nOutput; + + if (nPrecision==1) { + if (pIO->Write8Float(m_pData, nNum)!=(icInt32Number)nNum) + return false; + } + else if (nPrecision==2) { + if (pIO->Write16Float(m_pData, nNum)!=(icInt32Number)nNum) + return false; + } + else + return false; + + return true; +} + + +/** + **************************************************************************** + * Name: CIccCLUT::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccCLUT::Read(icUInt32Number size, CIccIO *pIO) +{ + if (size < 20) + return false; + + if (pIO->Read8(m_GridPoints, 16)!=16 || + !pIO->Read8(&m_nPrecision) || + pIO->Read8(&m_nReserved2[0], 3)!=3) + return false; + + Init(m_GridPoints); + + return ReadData(size-20, pIO, m_nPrecision); +} + + +/** + **************************************************************************** + * Name: CIccCLUT::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccCLUT::Write(CIccIO *pIO) +{ + if (pIO->Write8(m_GridPoints, 16)!=16 || + !pIO->Write8(&m_nPrecision) || + pIO->Write8(&m_nReserved2[0], 3)!=3) + return false; + + return WriteData(pIO, m_nPrecision); +} + +/** + **************************************************************************** + * Name: CIccCLUT::Iterate + * + * Purpose: Iterate through the CLUT to dump the data + * + * Args: + * sDescription = string to concatenate data dump to, + * nIndex = the channel number, + * nPos = the current position in the CLUT + * + ***************************************************************************** + */ +void CIccCLUT::Iterate(std::string &sDescription, icUInt8Number nIndex, icUInt32Number nPos, bool bUseLegacy) +{ + if (nIndex < m_nInput) { + int i; + for (i=0; iPixelOp(m_fGridAdr, &m_pData[index]); + + } + } + } + } + else if (m_nInput==4) { + int i,j,k,l; + icUInt32Number index=0; + for (i=0; iPixelOp(m_fGridAdr, &m_pData[index]); + + } + } + } + } + } + else + SubIterate(pExec, 0, 0); +} + + +/** + **************************************************************************** + * Name: CIccCLUT::SubIterate + * + * Purpose: Iterate through the CLUT to get the data + * + * Args: + * pExec = pointer to the IIccCLUTExec object that implements the + * IIccCLUTExec::Apply() function, + * nIndex = the channel number, + * nPos = the current position in the CLUT + * + ***************************************************************************** + */ +void CIccCLUT::SubIterate(IIccCLUTExec* pExec, icUInt8Number nIndex, icUInt32Number nPos) +{ + if (nIndex < m_nInput) { + int i; + for (i=0; iPixelOp(m_fGridAdr, &m_pData[nPos]); +} + +/** + **************************************************************************** + * Name: CIccCLUT::DumpLut + * + * Purpose: Dump data associated with the tag to a string. + * + * Args: + * sDescription = string to concatenate tag dump to, + * szName = name of the LUT to be printed, + * csInput = color space signature of the input data, + * csOutput = color space signature of the output data + ***************************************************************************** + */ +void CIccCLUT::DumpLut(std::string &sDescription, const icChar *szName, + icColorSpaceSignature csInput, icColorSpaceSignature csOutput, + bool bUseLegacy) +{ + icChar szOutText[2048], szColor[40]; + int i, len; + + sprintf(szOutText, "BEGIN_LUT %s %d %d\r\n", szName, m_nInput, m_nOutput); + sDescription += szOutText; + + for (i=0; iv) { + destPixel[i] = (p[n000] + t*(p[n110]-p[n010]) + + u*(p[n010]-p[n000]) + + v*(p[n111]-p[n110])); + } + else if (uNewCopy(); + } + else { + m_CurvesA = NULL; + } + + if (IMBB.m_CurvesM) { + nCurves = IsInputMatrix() ? m_nInput : m_nOutput; + + m_CurvesM = new LPIccCurve[nCurves]; + for (i=0; iNewCopy(); + } + else { + m_CurvesM = NULL; + } + + if (IMBB.m_CurvesB) { + nCurves = IsInputB() ? m_nInput : m_nOutput; + + m_CurvesB = new LPIccCurve[nCurves]; + for (i=0; iNewCopy(); + } + else { + m_CurvesB = NULL; + } + + if (IMBB.m_Matrix) { + m_Matrix = new CIccMatrix(*IMBB.m_Matrix); + } + else { + m_Matrix = NULL; + } +} + + +/** + **************************************************************************** + * Name: CIccMBB::operator= + * + * Purpose: Copy Operator + * + * Args: + * IMBB = The CIccMBB object to be copied + ***************************************************************************** + */ +CIccMBB &CIccMBB::operator=(const CIccMBB &IMBB) +{ + if (&IMBB == this) + return *this; + + Cleanup(); + + icUInt8Number nCurves; + int i; + + m_bInputMatrix = IMBB.m_bInputMatrix; + m_bUseMCurvesAsBCurves = IMBB.m_bUseMCurvesAsBCurves; + m_nInput = IMBB.m_nInput; + m_nOutput = IMBB.m_nOutput; + m_csInput = IMBB.m_csInput; + m_csOutput = IMBB.m_csOutput; + + if (IMBB.m_CLUT) { + m_CLUT = new CIccCLUT(*IMBB.m_CLUT); + } + else + m_CLUT = NULL; + + if (IMBB.m_CurvesA) { + nCurves = !IsInputB() ? m_nInput : m_nOutput; + + m_CurvesA = new LPIccCurve[nCurves]; + for (i=0; iNewCopy(); + } + else { + m_CurvesA = NULL; + } + + if (IMBB.m_CurvesM) { + nCurves = IsInputMatrix() ? m_nInput : m_nOutput; + + m_CurvesM = new LPIccCurve[nCurves]; + for (i=0; iNewCopy(); + } + else { + m_CurvesM = NULL; + } + + if (IMBB.m_CurvesB) { + nCurves = IsInputB() ? m_nInput : m_nOutput; + + m_CurvesB = new LPIccCurve[nCurves]; + for (i=0; iNewCopy(); + } + else { + m_CurvesB = NULL; + } + + if (IMBB.m_Matrix) { + m_Matrix = new CIccMatrix(*IMBB.m_Matrix); + } + else { + m_Matrix = NULL; + } + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccMBB::~CIccMBB + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccMBB::~CIccMBB() +{ + Cleanup(); +} + +/** + **************************************************************************** + * Name: CIccMBB::Cleanup + * + * Purpose: Frees the memory allocated to the object + * + ***************************************************************************** + */ +void CIccMBB::Cleanup() +{ + int i; + + if (IsInputMatrix()) { + if (m_CurvesB) { + for (i=0; iDumpLut(sDescription, buf, m_csInput, i); + } + } + + if (m_Matrix) + m_Matrix->DumpLut(sDescription, "Matrix"); + + if (m_CurvesM) { + for (i=0; iDumpLut(sDescription, buf, m_csInput, i); + } + } + + if (m_CLUT) + m_CLUT->DumpLut(sDescription, "CLUT", m_csInput, m_csOutput, GetType()==icSigLut16Type); + + if (m_CurvesA) { + for (i=0; iDumpLut(sDescription, buf, m_csOutput, i); + } + } + } + else { + if (m_CurvesA) { + for (i=0; iDumpLut(sDescription, buf, m_csInput, i); + } + } + + if (m_CLUT) + m_CLUT->DumpLut(sDescription, "CLUT", m_csInput, m_csOutput); + + if (m_CurvesM && this->GetType()!=icSigLut8Type) { + for (i=0; iDumpLut(sDescription, buf, m_csOutput, i); + } + } + + if (m_Matrix) + m_Matrix->DumpLut(sDescription, "Matrix"); + + if (m_CurvesB) { + for (i=0; iDumpLut(sDescription, buf, m_csOutput, i); + } + } + } +} + + +/** +****************************************************************************** +* Name: CIccMBB::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccMBB::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + return rv; + } + icUInt32Number nInput, nOutput; + + //Check # of channels + switch(sig) { + case icSigAToB0Tag: + case icSigAToB1Tag: + case icSigAToB2Tag: + { + nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + if (m_nInput!=nInput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of input channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + nOutput = icGetSpaceSamples(pProfile->m_Header.pcs); + if (m_nOutput!=nOutput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of output channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + break; + } + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + { + nInput = icGetSpaceSamples(pProfile->m_Header.pcs); + if (m_nInput!=nInput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of input channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + if (m_nOutput!=nOutput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of output channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + break; + } + case icSigGamutTag: + { + nInput = icGetSpaceSamples(pProfile->m_Header.pcs); + if (m_nInput!=nInput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of input channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + nOutput = 1; + if (m_nOutput!=nOutput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of output channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + break; + } + default: + { + nInput = m_nInput; + nOutput = m_nOutput; + } + } + + //CLUT check + if (nInput!=nOutput) { + if (!m_CLUT) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - CLUT must be present.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + if (m_CLUT) { + rv = icMaxStatus(rv, m_CLUT->Validate(GetType(), sReport, pProfile)); + } + + return rv; +} + +/** + **************************************************************************** + * Name: CIccMBB::NewCurvesA + * + * Purpose: Allocates memory for a new set of A-curves + * + * Return: Pointer to the LPIccCurve object + ***************************************************************************** + */ +LPIccCurve* CIccMBB::NewCurvesA() +{ + if (m_CurvesA) + return m_CurvesA; + + icUInt8Number nCurves = !IsInputB() ? m_nInput : m_nOutput; + + m_CurvesA = new LPIccCurve[nCurves]; + memset(m_CurvesA, 0, nCurves * sizeof(LPIccCurve)); + + return m_CurvesA; +} + + +/** + **************************************************************************** + * Name: CIccMBB::NewCurvesM + * + * Purpose: Allocates memory for a new set of M-curves + * + * Return: Pointer to the LPIccCurve object + ***************************************************************************** + */ +LPIccCurve* CIccMBB::NewCurvesM() +{ + if (m_CurvesM) + return m_CurvesM; + + icUInt8Number nCurves = IsInputMatrix() ? m_nInput : m_nOutput; + + m_CurvesM = new LPIccCurve[nCurves]; + memset(m_CurvesM, 0, nCurves * sizeof(LPIccCurve)); + + return m_CurvesM; +} + +/** + **************************************************************************** + * Name: CIccMBB::NewCurvesB + * + * Purpose: Allocates memory for a new set of B-curves + * + * Return: Pointer to the LPIccCurve object + ***************************************************************************** + */ +LPIccCurve* CIccMBB::NewCurvesB() +{ + if (m_CurvesB) + return m_CurvesB; + + icUInt8Number nCurves = IsInputB() ? m_nInput : m_nOutput; + + m_CurvesB = new LPIccCurve[nCurves]; + memset(m_CurvesB, 0, nCurves * sizeof(LPIccCurve)); + + return m_CurvesB; +} + +/** + **************************************************************************** + * Name: CIccMBB::NewMatrix + * + * Purpose: Allocates memory for a new matrix + * + * Return: Pointer to the CIccMatrix object + ***************************************************************************** + */ +CIccMatrix* CIccMBB::NewMatrix() +{ + if (m_Matrix) + return m_Matrix; + + m_Matrix = new CIccMatrix; + + return m_Matrix; +} + +/** + **************************************************************************** + * Name: CIccMBB::NewCLUT + * + * Purpose: Allocates memory for a new CLUT and initializes it + * + * Args: + * pGridPoints = number of grid points in the CLUT + * + * Return: Pointer to the CIccCLUT object + ***************************************************************************** + */ +CIccCLUT* CIccMBB::NewCLUT(icUInt8Number *pGridPoints, icUInt8Number nPrecision/*=2*/) +{ + if (m_CLUT) + return m_CLUT; + + m_CLUT = new CIccCLUT(m_nInput, m_nOutput, nPrecision); + + m_CLUT->Init(pGridPoints); + + return m_CLUT; +} + +/** +**************************************************************************** +* Name: CIccMBB::SetCLUT +* +* Purpose: Assignes CLUT connection to an initialized new CLUT +* +* Args: +* clut = pointer to a previously allocated CLUT (Onwership is transfered to +* CIccMBB object). +* +* Return: Pointer to the CIccCLUT object or NULL if clut is incompatible with +* CIccMBB object. If the clut is incompatible it is deleted. +***************************************************************************** +*/ +CIccCLUT *CIccMBB::SetCLUT(CIccCLUT *clut) +{ + if (clut->GetInputDim() != m_nInput || clut->GetOutputChannels() != m_nOutput) { + delete clut; + return NULL; + } + + if (m_CLUT) { + delete m_CLUT; + } + + m_CLUT = clut; + return clut; +} + +/** + **************************************************************************** + * Name: CIccMBB::NewCLUT + * + * Purpose: Allocates memory for a new CLUT and initializes it + * + * Args: + * nGridPoints = number of grid points in the CLUT + * + * Return: Pointer to the CIccCLUT object + ***************************************************************************** + */ +CIccCLUT* CIccMBB::NewCLUT(icUInt8Number nGridPoints, icUInt8Number nPrecision/*=2*/) +{ + if (m_CLUT) + return m_CLUT; + + m_CLUT = new CIccCLUT(m_nInput, m_nOutput, nPrecision); + + m_CLUT->Init(nGridPoints); + + return m_CLUT; +} + + +/** + **************************************************************************** + * Name: CIccTagLutAtoB::CIccTagLutAtoB + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagLutAtoB::CIccTagLutAtoB() +{ + m_bInputMatrix = false; + m_nReservedWord = 0; +} + + +/** + **************************************************************************** + * Name: CIccTagLutAtoB::CIccTagLutAtoB + * + * Purpose: Copy Constructor + * + * Args: + * ITLA2B = The CIccTagLutAtoB object to be copied + ***************************************************************************** + */ +CIccTagLutAtoB::CIccTagLutAtoB(const CIccTagLutAtoB &ITLA2B) : CIccMBB(ITLA2B) +{ + m_nReservedWord = 0; +} + + +/** + **************************************************************************** + * Name: CIccTagLutAtoB::operator= + * + * Purpose: Copy Operator + * + * Args: + * ITLA2B = The CIccTagLutAtoB object to be copied + ***************************************************************************** + */ +CIccTagLutAtoB &CIccTagLutAtoB::operator=(const CIccTagLutAtoB &ITLA2B) +{ + if (&ITLA2B == this) + return *this; + + CIccMBB::operator=(ITLA2B); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagLutAtoB::~CIccTagLutAtoB + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagLutAtoB::~CIccTagLutAtoB() +{ +} + + +/** + **************************************************************************** + * Name: CIccTagLutAtoB::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagLutAtoB::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number Offset[5], nStart, nEnd, nPos; + icUInt8Number nCurves, i; + + if (size<8*sizeof(icUInt32Number) || !pIO) { + return false; + } + + nStart = pIO->Tell(); + nEnd = nStart + size; + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read8(&m_nInput) || + !pIO->Read8(&m_nOutput) || + !pIO->Read16(&m_nReservedWord) || + pIO->Read32(Offset, 5)!=5) + return false; + + if (sig!=GetType()) + return false; + + //B Curves + if (Offset[0]) { + nCurves = IsInputB() ? m_nInput : m_nOutput; + LPIccCurve *pCurves = NewCurvesB(); + + if (pIO->Seek(nStart + Offset[0], icSeekSet)<0) + return false; + + for (i=0; iTell(); + + if (!pIO->Read32(&sig)) + return false; + + if (pIO->Seek(nPos, icSeekSet)<0) + return false; + + if (sig!=icSigCurveType && + sig!=icSigParametricCurveType) + return false; + + pCurves[i] = (CIccCurve*)CIccTag::Create(sig); + + if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO)) + return false; + + if (!pIO->Sync32(Offset[1])) + return false; + } + } + + //Matrix + if (Offset[1]) { + icS15Fixed16Number tmp; + + if (Offset[1] + 12*sizeof(icS15Fixed16Number) >size) + return false; + + m_Matrix = new CIccMatrix(); + + if (pIO->Seek(nStart + Offset[1], icSeekSet)<0) + return false; + + for (i=0; i<12; i++) { + if (pIO->Read32(&tmp, 1)!=1) + return false; + m_Matrix->m_e[i] = icFtoD(tmp); + } + } + + + //M Curves + if (Offset[2]) { + nCurves = IsInputMatrix() ? m_nInput : m_nOutput; + LPIccCurve *pCurves = NewCurvesM(); + + if (pIO->Seek(nStart + Offset[2], icSeekSet)<0) + return false; + + for (i=0; iTell(); + + if (!pIO->Read32(&sig)) + return false; + + if (pIO->Seek(nPos, icSeekSet)<0) + return false; + + if (sig!=icSigCurveType && + sig!=icSigParametricCurveType) + return false; + + pCurves[i] = (CIccCurve*)CIccTag::Create(sig); + + if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO)) + return false; + + if (!pIO->Sync32(Offset[2])) + return false; + } + } + + //CLUT + if (Offset[3]) { + if (pIO->Seek(nStart + Offset[3], icSeekSet)<0) + return false; + + m_CLUT = new CIccCLUT(m_nInput, m_nOutput); + + if (!m_CLUT->Read(nEnd - pIO->Tell(), pIO)) + return false; + } + + //A Curves + if (Offset[4]) { + nCurves = !IsInputB() ? m_nInput : m_nOutput; + LPIccCurve *pCurves = NewCurvesA(); + + if (pIO->Seek(nStart + Offset[4], icSeekSet)<0) + return false; + + for (i=0; iTell(); + + if (!pIO->Read32(&sig)) + return false; + + if (pIO->Seek(nPos, icSeekSet)<0) + return false; + + if (sig!=icSigCurveType && + sig!=icSigParametricCurveType) + return false; + + pCurves[i] = (CIccCurve*)CIccTag::Create(sig); + + if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO)) + return false; + + if (!pIO->Sync32(Offset[4])) + return false; + } + } + return true; +} + + + +/** + **************************************************************************** + * Name: CIccTagLutAtoB::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagLutAtoB::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt32Number Offset[5], nStart, nEnd, nOffsetPos; + icUInt8Number nCurves, i; + + nStart = pIO->Tell(); + memset(&Offset[0], 0, sizeof(Offset)); + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write8(&m_nInput) || + !pIO->Write8(&m_nOutput) || + !pIO->Write16(&m_nReservedWord)) + return false; + + nOffsetPos = pIO->Tell(); + if (pIO->Write32(Offset, 5)!=5) + return false; + + //B Curves + if (m_CurvesB) { + Offset[0] = pIO->Tell() - nStart; + nCurves = IsInputB() ? m_nInput : m_nOutput; + + for (i=0; iWrite(pIO)) + return false; + + if (!pIO->Align32()) + return false; + } + } + + //Matrix + if (m_Matrix) { + icS15Fixed16Number tmp; + + Offset[1] = pIO->Tell() - nStart; + + for (i=0; i<12; i++) { + tmp = icDtoF(m_Matrix->m_e[i]); + if (pIO->Write32(&tmp, 1)!=1) + return false; + } + } + + + //M Curves + if (m_CurvesM) { + Offset[2] = pIO->Tell() - nStart; + nCurves = IsInputMatrix() ? m_nInput : m_nOutput; + + for (i=0; iWrite(pIO)) + return false; + + if (!pIO->Align32()) + return false; + } + } + + //CLUT + if (m_CLUT) { + Offset[3] = pIO->Tell() - nStart; + + if (!m_CLUT->Write(pIO)) + return false; + + if (!pIO->Align32()) + return false; + } + + //A Curves + if (m_CurvesA) { + Offset[4] = pIO->Tell() - nStart; + nCurves = !IsInputB() ? m_nInput : m_nOutput; + + for (i=0; iWrite(pIO)) + return false; + + if (!pIO->Align32()) + return false; + } + } + + nEnd = pIO->Tell(); + + if (!pIO->Seek(nOffsetPos, icSeekSet)) + return false; + + if (pIO->Write32(&Offset[0], 5)!=5) + return false; + + return pIO->Seek(nEnd, icSeekSet)>=0; +} + + +/** +****************************************************************************** +* Name: CIccTagLutAtoB::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagLutAtoB::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + return rv; + } + + switch(sig) { + case icSigAToB0Tag: + case icSigAToB1Tag: + case icSigAToB2Tag: + { + icUInt32Number nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + + icUInt32Number nOutput = icGetSpaceSamples(pProfile->m_Header.pcs); + + icUInt8Number i; + if (m_CurvesB) { + for (i=0; iValidate(sig, sReport, pProfile)); + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of B-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + + if (m_CurvesM) { + for (i=0; iValidate(sig, sReport, pProfile)); + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of M-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + + if (m_CurvesA) { + if (!m_CLUT) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - CLUT must be present if using A-curves.\r\n"; + + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + for (i=0; iValidate(sig, sReport, pProfile)); + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of A-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + } + + break; + } + default: + { + } + } + + + return rv; +} + +/** + **************************************************************************** + * Name: CIccTagLutBtoA::CIccTagLutBtoA + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagLutBtoA::CIccTagLutBtoA() +{ + m_bInputMatrix = true; +} + + +/** + **************************************************************************** + * Name: CIccTagLutBtoA::CIccTagLutBtoA + * + * Purpose: Copy Constructor + * + * Args: + * ITLB2A = The CIccTagLutBtoA object to be copied + ***************************************************************************** + */ +CIccTagLutBtoA::CIccTagLutBtoA(const CIccTagLutBtoA &ITLB2A) : CIccTagLutAtoB(ITLB2A) +{ +} + + +/** + **************************************************************************** + * Name: CIccTagLutBtoA::operator= + * + * Purpose: Copy Operator + * + * Args: + * ITLB2A = The CIccTagLutBtoA object to be copied + ***************************************************************************** + */ +CIccTagLutBtoA &CIccTagLutBtoA::operator=(const CIccTagLutBtoA &ITLB2A) +{ + if (&ITLB2A == this) + return *this; + + CIccMBB::operator=(ITLB2A); + + return *this; +} + + +/** +****************************************************************************** +* Name: CIccTagLutBtoA::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagLutBtoA::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + return rv; + } + + switch(sig) { + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + case icSigGamutTag: + { + icUInt32Number nInput = icGetSpaceSamples(pProfile->m_Header.pcs); + + icUInt32Number nOutput; + if (sig==icSigGamutTag) { + nOutput = 1; + } + else { + nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + } + + if (m_nOutput!=nOutput) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of output channels.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + + icUInt8Number i; + if (m_CurvesB) { + for (i=0; iValidate(sig, sReport, pProfile)); + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of B-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + + if (m_CurvesM) { + for (i=0; iValidate(sig, sReport, pProfile)); + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of M-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + + if (m_CurvesA) { + if (!m_CLUT) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - CLUT must be present if using A-curves.\r\n"; + + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + for (i=0; iValidate(sig, sReport, pProfile)); + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of A-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + } + + break; + } + default: + { + } + } + + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::CIccTagLut8 + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagLut8::CIccTagLut8() +{ + memset(m_XYZMatrix, 0, sizeof(m_XYZMatrix)); + m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0); + m_nReservedByte = 0; +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::CIccTagLut8 + * + * Purpose: Copy Constructor + * + * Args: + * ITL = The CIccTagLut8 object to be copied + ***************************************************************************** + */ +CIccTagLut8::CIccTagLut8(const CIccTagLut8& ITL) : CIccMBB(ITL) +{ + memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix)); + m_nReservedByte = 0; +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::operator= + * + * Purpose: Copy Operator + * + * Args: + * ITL = The CIccTagLut8 object to be copied + ***************************************************************************** + */ +CIccTagLut8 &CIccTagLut8::operator=(const CIccTagLut8 &ITL) +{ + if (&ITL==this) + return *this; + + CIccMBB::operator=(ITL); + memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix)); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::~CIccTagLut8 + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagLut8::~CIccTagLut8() +{ +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagLut8::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nStart, nEnd; + icUInt8Number i, nGrid; + LPIccCurve *pCurves; + CIccTagCurve *pCurve; + + if (size<13*sizeof(icUInt32Number) || !pIO) { + return false; + } + + nStart = pIO->Tell(); + nEnd = nStart + size; + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read8(&m_nInput) || + !pIO->Read8(&m_nOutput) || + !pIO->Read8(&nGrid) || + !pIO->Read8(&m_nReservedByte) || + pIO->Read32(m_XYZMatrix, 9) != 9) + return false; + + if (sig!=GetType()) + return false; + + //B Curves + pCurves = NewCurvesB(); + + for (i=0; i nEnd - pIO->Tell()) + return false; + + pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType); + + pCurve->SetSize(256); + + if (pIO->Read8Float(&(*pCurve)[0], 256) != 256) + return false; + } + + //CLUT + m_CLUT = new CIccCLUT(m_nInput, m_nOutput); + + m_CLUT->Init(nGrid); + + if (!m_CLUT->ReadData(nEnd - pIO->Tell(), pIO, 1)) + return false; + + //A Curves + pCurves = NewCurvesA(); + + for (i=0; i nEnd - pIO->Tell()) + return false; + + pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType); + + pCurve->SetSize(256); + + if (pIO->Read8Float(&(*pCurve)[0], 256) != 256) + return false; + } + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::SetColorSpaces + * + * Purpose: Sets the input and output color spaces + * + * Args: + * csInput = input color space signature, + * csOutput = output color space signature + * + ***************************************************************************** + */ +void CIccTagLut8::SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput) +{ + if (csInput==icSigXYZData) { + int i; + + if (!m_CurvesM && IsInputMatrix()) { //Transfer ownership of curves + m_CurvesM = m_CurvesB; + m_CurvesB = NULL; + + LPIccCurve *pCurves = NewCurvesB(); + CIccTagCurve *pCurve; + for (i=0; iSetSize(0); + } + + m_bUseMCurvesAsBCurves = true; + } + + if (!m_Matrix) { + CIccMatrix *pMatrix = NewMatrix(); + for (i=0; i<9; i++) { + pMatrix->m_e[i] = icFtoD(m_XYZMatrix[i]); + } + + pMatrix->m_bUseConstants=false; + } + } + else { + m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0); + m_XYZMatrix[1] = m_XYZMatrix[2] = m_XYZMatrix[3] = + m_XYZMatrix[5] = m_XYZMatrix[6] = m_XYZMatrix[7] = 0; + } + + CIccMBB::SetColorSpaces(csInput, csOutput); +} + + +/** + **************************************************************************** + * Name: CIccTagLut8::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagLut8::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt8Number i, nGrid; + icS15Fixed16Number XYZMatrix[9]; + icUInt16Number nInputEntries, nOutputEntries; + LPIccCurve *pCurves; + CIccTagCurve *pCurve; + icFloat32Number v; + + if (m_Matrix) { + for (i=0; i<9; i++) + XYZMatrix[i] = icDtoF(m_Matrix->m_e[i]); + } + else { + memset(XYZMatrix, 0, 9*sizeof(icS15Fixed16Number)); + XYZMatrix[0] = XYZMatrix[4] = XYZMatrix[8] = icDtoF(1.0); + } + + if (m_bUseMCurvesAsBCurves) { + pCurves = m_CurvesM; + } + else { + pCurves = m_CurvesB; + } + + if (!pCurves || !m_CurvesA || !m_CLUT) + return false; + + nGrid = m_CLUT->GridPoints(); + + nInputEntries = (icUInt16Number)(((CIccTagCurve*)pCurves[0])->GetSize()); + nOutputEntries = (icUInt16Number)(((CIccTagCurve*)m_CurvesA[0])->GetSize()); + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write8(&m_nInput) || + !pIO->Write8(&m_nOutput) || + !pIO->Write8(&nGrid) || + !pIO->Write8(&m_nReservedByte) || + pIO->Write32(XYZMatrix, 9) != 9) + return false; + + //B Curves + for (i=0; iGetType()!=icSigCurveType) + return false; + + pCurve = (CIccTagCurve*)pCurves[i]; + if (!pCurve) + return false; + + if (pCurve->GetSize()!=256) { + icUInt32Number j; + + for (j=0; j<256; j++) { + v = pCurve->Apply((icFloat32Number)j / 255.0F); + if (!pIO->Write8Float(&v, 1)) + return false; + } + } + else { + if (pIO->Write8Float(&(*pCurve)[0], 256)!=256) + return false; + } + } + + //CLUT + if (!m_CLUT->WriteData(pIO, 1)) + return false; + + //A Curves + pCurves = m_CurvesA; + + for (i=0; iGetType()!=icSigCurveType) + return false; + + pCurve = (CIccTagCurve*)pCurves[i]; + + if (!pCurve) + return false; + + if (pCurve->GetSize()!=256) { + icUInt32Number j; + + for (j=0; j<256; j++) { + v = pCurve->Apply((icFloat32Number)j / 255.0F); + if (!pIO->Write8Float(&v, 1)) + return false; + } + } + else { + if (pIO->Write8Float(&(*pCurve)[0], 256)!=256) + return false; + } + } + return true; +} + + +/** +****************************************************************************** +* Name: CIccTagLut8::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagLut8::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + return rv; + } + + switch(sig) { + case icSigAToB0Tag: + case icSigAToB1Tag: + case icSigAToB2Tag: + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + case icSigGamutTag: + { + icUInt32Number nInput, nOutput; + if (sig==icSigAToB0Tag || sig==icSigAToB1Tag || sig==icSigAToB2Tag || sig==icSigGamutTag) { + nInput = icGetSpaceSamples(pProfile->m_Header.pcs); + nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + } + else { + nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + nOutput = icGetSpaceSamples(pProfile->m_Header.pcs); + } + + if (sig==icSigGamutTag) { + nOutput = 1; + } + + icUInt8Number i; + if (m_CurvesB) { + for (i=0; iValidate(sig, sReport, pProfile)); + if (m_CurvesB[i]->GetType()==icSigCurveType) { + CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesB[i]; + if (pTagCurve->GetSize()==1) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - lut8Tags do not support single entry gamma curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of B-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + + if (m_Matrix) { + rv = icMaxStatus(rv, m_Matrix->Validate(GetType(), sReport, pProfile)); + } + else { + int sum=0; + for (int i=0; i<9; i++) { + sum += m_XYZMatrix[i]; + } + if (m_XYZMatrix[0]!=1.0 || m_XYZMatrix[4]!=1.0 || m_XYZMatrix[8]!=1.0 || sum!=3.0) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Matrix must be identity.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + } + + if (m_CurvesA) { + + for (i=0; iValidate(sig, sReport, pProfile)); + if (m_CurvesA[i]->GetType()==icSigCurveType) { + CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesA[i]; + if (pTagCurve->GetSize()==1) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - lut8Tags do not support single entry gamma curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of A-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + } + + break; + } + default: + { + } + } + + + return rv; +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::CIccTagLut16 + * + * Purpose: Constructor + * + ***************************************************************************** + */ +CIccTagLut16::CIccTagLut16() +{ + memset(m_XYZMatrix, 0, sizeof(m_XYZMatrix)); + m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0); + m_nReservedByte = 0; +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::CIccTagLut16 + * + * Purpose: Copy Constructor + * + * Args: + * ITL = The CIccTagUnknown object to be copied + ***************************************************************************** + */ +CIccTagLut16::CIccTagLut16(const CIccTagLut16& ITL) : CIccMBB(ITL) +{ + memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix)); + m_nReservedByte = 0; +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::operator= + * + * Purpose: Copy Operator + * + * Args: + * ITL = The CIccTagLut16 object to be copied + ***************************************************************************** + */ +CIccTagLut16 &CIccTagLut16::operator=(const CIccTagLut16 &ITL) +{ + if (&ITL==this) + return *this; + + CIccMBB::operator=(ITL); + memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix)); + + return *this; +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::~CIccTagLut16 + * + * Purpose: Destructor + * + ***************************************************************************** + */ +CIccTagLut16::~CIccTagLut16() +{ +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::Read + * + * Purpose: Read in the tag contents into a data block + * + * Args: + * size - # of bytes in tag, + * pIO - IO object to read tag from + * + * Return: + * true = successful, false = failure + ***************************************************************************** + */ +bool CIccTagLut16::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + icUInt32Number nStart, nEnd; + icUInt8Number i, nGrid; + icUInt16Number nInputEntries, nOutputEntries; + LPIccCurve *pCurves; + CIccTagCurve *pCurve; + + if (size<13*sizeof(icUInt32Number) || !pIO) { + return false; + } + + nStart = pIO->Tell(); + nEnd = nStart + size; + + if (!pIO->Read32(&sig) || + !pIO->Read32(&m_nReserved) || + !pIO->Read8(&m_nInput) || + !pIO->Read8(&m_nOutput) || + !pIO->Read8(&nGrid) || + !pIO->Read8(&m_nReservedByte) || + pIO->Read32(m_XYZMatrix, 9) != 9 || + !pIO->Read16(&nInputEntries) || + !pIO->Read16(&nOutputEntries)) + return false; + + if (sig!=GetType()) + return false; + + + //B Curves + pCurves = NewCurvesB(); + + for (i=0; i nEnd - pIO->Tell()) + return false; + + pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType); + + pCurve->SetSize(nInputEntries); + + if (pIO->Read16Float(&(*pCurve)[0], nInputEntries) != nInputEntries) + return false; + } + + //CLUT + m_CLUT = new CIccCLUT(m_nInput, m_nOutput); + + m_CLUT->Init(nGrid); + + if (!m_CLUT->ReadData(nEnd - pIO->Tell(), pIO, 2)) + return false; + + //A Curves + pCurves = NewCurvesA(); + + for (i=0; i nEnd - pIO->Tell()) + return false; + + pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType); + + pCurve->SetSize(nOutputEntries); + + if (pIO->Read16Float(&(*pCurve)[0], nOutputEntries) != nOutputEntries) + return false; + } + return true; +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::SetColorSpaces + * + * Purpose: Sets the input and output color spaces + * + * Args: + * csInput = input color space signature, + * csOutput = output color space signature + * + ***************************************************************************** + */ +void CIccTagLut16::SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput) +{ + if (csInput==icSigXYZData) { + int i; + + if (!m_CurvesM && IsInputMatrix()) { //Transfer ownership of curves + m_CurvesM = m_CurvesB; + m_CurvesB = NULL; + + LPIccCurve *pCurves = NewCurvesB(); + CIccTagCurve *pCurve; + for (i=0; iSetSize(0); + } + + m_bUseMCurvesAsBCurves = true; + } + + if (!m_Matrix) { + CIccMatrix *pMatrix = NewMatrix(); + for (i=0; i<9; i++) { + pMatrix->m_e[i] = icFtoD(m_XYZMatrix[i]); + } + + pMatrix->m_bUseConstants=false; + } + } + else { + m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0); + m_XYZMatrix[1] = m_XYZMatrix[2] = m_XYZMatrix[3] = + m_XYZMatrix[5] = m_XYZMatrix[6] = m_XYZMatrix[7] = 0; + } + + CIccMBB::SetColorSpaces(csInput, csOutput); +} + + +/** + **************************************************************************** + * Name: CIccTagLut16::Write + * + * Purpose: Write the tag to a file + * + * Args: + * pIO - The IO object to write tag to. + * + * Return: + * true = succesful, false = failure + ***************************************************************************** + */ +bool CIccTagLut16::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + icUInt8Number i, nGrid; + icS15Fixed16Number XYZMatrix[9]; + icUInt16Number nInputEntries, nOutputEntries; + LPIccCurve *pCurves; + CIccTagCurve *pCurve; + + if (m_Matrix) { + for (i=0; i<9; i++) { + XYZMatrix[i] = icDtoF(m_Matrix->m_e[i]); + } + } + else { + memset(XYZMatrix, 0, 9*sizeof(icS15Fixed16Number)); + XYZMatrix[0] = XYZMatrix[4] = XYZMatrix[8] = icDtoF(1.0); + } + + if (m_bUseMCurvesAsBCurves) { + pCurves = m_CurvesM; + } + else { + pCurves = m_CurvesB; + } + + if (!pCurves || !m_CurvesA || !m_CLUT) + return false; + + nGrid = m_CLUT->GridPoints(); + + nInputEntries = (icUInt16Number)(((CIccTagCurve*)pCurves[0])->GetSize()); + nOutputEntries = (icUInt16Number)(((CIccTagCurve*)m_CurvesA[0])->GetSize()); + + if (!pIO->Write32(&sig) || + !pIO->Write32(&m_nReserved) || + !pIO->Write8(&m_nInput) || + !pIO->Write8(&m_nOutput) || + !pIO->Write8(&nGrid) || + !pIO->Write8(&m_nReservedByte) || + pIO->Write32(XYZMatrix, 9) != 9 || + !pIO->Write16(&nInputEntries) || + !pIO->Write16(&nOutputEntries)) + return false; + + //B Curves + for (i=0; iGetType()!=icSigCurveType) + return false; + + pCurve = (CIccTagCurve*)pCurves[i]; + if (!pCurve) + return false; + + if (pIO->Write16Float(&(*pCurve)[0], nInputEntries) != nInputEntries) + return false; + } + + //CLUT + if (!m_CLUT->WriteData(pIO, 2)) + return false; + + //A Curves + pCurves = m_CurvesA; + + for (i=0; iGetType()!=icSigCurveType) + return false; + + pCurve = (CIccTagCurve*)pCurves[i]; + + if (pIO->Write16Float(&(*pCurve)[0], nOutputEntries) != nOutputEntries) + return false; + } + return true; +} + + +/** +****************************************************************************** +* Name: CIccTagLut16::Validate +* +* Purpose: Check tag data validity. +* +* Args: +* sig = signature of tag being validated, +* sReport = String to add report information to +* +* Return: +* icValidateStatusOK if valid, or other error status. +****************************************************************************** +*/ +icValidateStatus CIccTagLut16::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const +{ + icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!pProfile) { + rv = icMaxStatus(rv, icValidateWarning); + return rv; + } + + switch(sig) { + case icSigAToB0Tag: + case icSigAToB1Tag: + case icSigAToB2Tag: + case icSigBToA0Tag: + case icSigBToA1Tag: + case icSigBToA2Tag: + case icSigGamutTag: + { + icUInt32Number nInput, nOutput; + if (sig==icSigAToB0Tag || sig==icSigAToB1Tag || sig==icSigAToB2Tag || sig==icSigGamutTag) { + nInput = icGetSpaceSamples(pProfile->m_Header.pcs); + nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + } + else { + nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace); + nOutput = icGetSpaceSamples(pProfile->m_Header.pcs); + } + + if (sig==icSigGamutTag) { + nOutput = 1; + } + + icUInt8Number i; + if (m_CurvesB) { + for (i=0; iValidate(sig, sReport, pProfile)); + if (m_CurvesB[i]->GetType()==icSigCurveType) { + CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesB[i]; + if (pTagCurve->GetSize()==1) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - lut16Tags do not support single entry gamma curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of B-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + + if (m_Matrix) { + rv = icMaxStatus(rv, m_Matrix->Validate(GetType(), sReport, pProfile)); + } + else { + int sum=0; + for (int i=0; i<9; i++) { + sum += m_XYZMatrix[i]; + } + if (m_XYZMatrix[0]!=1.0 || m_XYZMatrix[4]!=1.0 || m_XYZMatrix[8]!=1.0 || sum!=3.0) { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " - Matrix must be identity.\r\n"; + rv = icMaxStatus(rv, icValidateWarning); + } + } + + if (m_CurvesA) { + + for (i=0; iValidate(sig, sReport, pProfile)); + if (m_CurvesA[i]->GetType()==icSigCurveType) { + CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesA[i]; + if (pTagCurve->GetSize()==1) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - lut16Tags do not support single entry gamma curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + } + else { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Incorrect number of A-curves.\r\n"; + rv = icMaxStatus(rv, icValidateCriticalError); + } + } + + } + + break; + } + default: + { + } + } + + + return rv; +} + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccTagLut.h b/library/src/main/cpp/icc/IccTagLut.h new file mode 100644 index 00000000..48187e76 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagLut.h @@ -0,0 +1,533 @@ +/** @file + File: IccTagLut.h + + Contains: Header for implementation of the Multi-Dimensional + Lut tag classes classes + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2005-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +// -Moved LUT tags to separate file 4-30-2005 +// +////////////////////////////////////////////////////////////////////// + +#if !defined(_ICCTAGLUT_H) +#define _ICCTAGLUT_H + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +#include "IccTagBasic.h" + +/** +**************************************************************************** +* Class: CIccCurve +* +* Purpose: The base curve class +***************************************************************************** +*/ +class ICCPROFLIB_API CIccCurve : public CIccTag +{ +public: + CIccCurve() {} + virtual CIccTag *NewCopy() const { return new CIccCurve; } + virtual ~CIccCurve() {} + + virtual void DumpLut(std::string &sDescription, const icChar *szName, + icColorSpaceSignature csSig, int nIndex) {} + + virtual void Begin() {} + virtual icFloatNumber Apply(icFloatNumber v) { return v; } + + icFloatNumber Find(icFloatNumber v) { return Find(v, 0, Apply(0), 1.0, Apply(1.0)); } + virtual bool IsIdentity() {return false;} + +protected: + icFloatNumber Find(icFloatNumber v, + icFloatNumber p0, icFloatNumber v0, + icFloatNumber p1, icFloatNumber v1); + +}; +typedef CIccCurve* LPIccCurve; + +typedef enum { + icInitNone, + icInitZero, + icInitIdentity, +} icTagCurveSizeInit; + +/** +**************************************************************************** +* Class: CIccTagCurve +* +* Purpose: The curveType tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagCurve : public CIccCurve +{ +public: + CIccTagCurve(int nSize=0); + CIccTagCurve(const CIccTagCurve &ITCurve); + CIccTagCurve &operator=(const CIccTagCurve &CurveTag); + virtual CIccTag *NewCopy() const { return new CIccTagCurve(*this);} + virtual ~CIccTagCurve(); + + virtual icTagTypeSignature GetType() const { return icSigCurveType; } + virtual const icChar *GetClassName() const { return "CIccTagCurve"; } + + virtual void Describe(std::string &sDescription); + virtual void DumpLut(std::string &sDescription, const icChar *szName, + icColorSpaceSignature csSig, int nIndex); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + icFloatNumber &operator[](icUInt32Number index) {return m_Curve[index];} + icFloatNumber *GetData(icUInt32Number index) {return &m_Curve[index];} + icUInt32Number GetSize() const { return m_nSize; } + void SetSize(icUInt32Number nSize, icTagCurveSizeInit nSizeOpt=icInitZero); + void SetGamma(icFloatNumber gamma); + + virtual void Begin() {m_nMaxIndex = (icUInt16Number)m_nSize - 1;} + virtual icFloatNumber Apply(icFloatNumber v); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + virtual bool IsIdentity(); + +protected: + icFloatNumber *m_Curve; + icUInt32Number m_nSize; + icUInt16Number m_nMaxIndex; +}; + +/** +**************************************************************************** +* Class: CIccTagParametricCurve +* +* Purpose: The parametric curve type tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagParametricCurve : public CIccCurve +{ +public: + CIccTagParametricCurve(); + CIccTagParametricCurve(const CIccTagParametricCurve &ITPC); + CIccTagParametricCurve &operator=(const CIccTagParametricCurve &ParamCurveTag); + virtual CIccTag *NewCopy() const { return new CIccTagParametricCurve(*this);} + virtual ~CIccTagParametricCurve(); + + virtual icTagTypeSignature GetType() const { return icSigParametricCurveType; } + virtual const icChar *GetClassName() const { return "CIccTagParametricCurve"; } + + virtual void Describe(std::string &sDescription); + virtual void DumpLut(std::string &sDescription, const icChar *szName, + icColorSpaceSignature csSig, int nIndex); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + + bool SetFunctionType(icUInt16Number nFunctionType); //# parameters set by + icUInt16Number GetFunctionType() const {return m_nFunctionType; } + + icUInt16Number GetNumParam() const { return m_nNumParam; } + icFloatNumber *GetParams() const { return m_dParam; } + icFloatNumber Param(int index) const { return m_dParam[index]; } + icFloatNumber& operator[](int index) { return m_dParam[index]; } + + virtual icFloatNumber Apply(icFloatNumber v) { return DoApply(v); } + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + virtual bool IsIdentity(); + + icUInt16Number m_nReserved2; +protected: + icFloatNumber DoApply(icFloatNumber v) const; + icUInt16Number m_nFunctionType; + icUInt16Number m_nNumParam; + icFloatNumber *m_dParam; +}; + + +/** +**************************************************************************** +* Class: CIccMatrix +* +* Purpose: The base matrix class +***************************************************************************** +*/ +class ICCPROFLIB_API CIccMatrix +{ +public: + CIccMatrix(bool bUseConstants=true); + CIccMatrix(const CIccMatrix &MatrixClass); + CIccMatrix &operator=(const CIccMatrix &MatrixClass); + virtual ~CIccMatrix() {} + + void DumpLut(std::string &sDescription, const icChar *szName); + + icFloatNumber m_e[12]; //e = element + bool m_bUseConstants; + + virtual void Apply(icFloatNumber *Pixel) const; + icValidateStatus Validate(icTagTypeSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + virtual bool IsIdentity(); +}; + +/** +**************************************************************************** +* Interface Class: IIccCLUTExec +* +* Purpose: Interface class that is useful to populate CLUTs +***************************************************************************** +*/ +class ICCPROFLIB_API IIccCLUTExec +{ +public: + virtual ~IIccCLUTExec() {} + + virtual void PixelOp(icFloatNumber* pGridAdr, icFloatNumber* pData)=0; +}; + +typedef icFloatNumber (*icCLUTCLIPFUNC)(icFloatNumber v); + +/** +**************************************************************************** +* Class: CIccCLUT +* +* Purpose: The base multidimensional color look-up table (CLUT) class +***************************************************************************** +*/ +class ICCPROFLIB_API CIccCLUT +{ +public: + CIccCLUT(icUInt8Number nInputChannels, icUInt16Number nOutputChannels, icUInt8Number nPrecision=2); + CIccCLUT(const CIccCLUT &ICLUT); + CIccCLUT &operator=(const CIccCLUT &CLUTClass); + virtual ~CIccCLUT(); + + bool Init(icUInt8Number nGridPoints); + bool Init(icUInt8Number *pGridPoints); + + bool ReadData(icUInt32Number size, CIccIO *pIO, icUInt8Number nPrecision); + bool WriteData(CIccIO *pIO, icUInt8Number nPrecision); + + bool Read(icUInt32Number size, CIccIO *pIO); + bool Write(CIccIO *pIO); + + void DumpLut(std::string &sDescription, const icChar *szName, + icColorSpaceSignature csInput, icColorSpaceSignature csOutput, + bool bUseLegacy=false); + + icFloatNumber& operator[](int index) { return m_pData[index]; } + icFloatNumber* GetData(int index) { return &m_pData[index]; } + icUInt32Number NumPoints() const { return m_nNumPoints; } + icUInt8Number GridPoints() const { return m_GridPoints[0]; } + icUInt8Number GridPoint(int index) const { return m_GridPoints[index]; } + icUInt32Number MaxGridPoint(int index) const { return m_MaxGridPoint[index]; } + + icUInt32Number GetDimSize(icUInt8Number nIndex) const { return m_DimSize[nIndex]; } + + icUInt8Number GetInputDim() const { return m_nInput; } + icUInt16Number GetOutputChannels() const { return m_nOutput; } + + icUInt32Number GetNumOffset() const { return m_nNodes; } + icUInt32Number GetOffset(int index) const { return m_nOffset ? m_nOffset[index] : 0; } + + + void Begin(); + void Interp3dTetra(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const; + void Interp3d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const; + void Interp4d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const; + void Interp5d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const; + void Interp6d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const; + void InterpND(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const; + + void Iterate(IIccCLUTExec* pExec); + icValidateStatus Validate(icTagTypeSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + void SetClipFunc(icCLUTCLIPFUNC ClipFunc) { UnitClip = ClipFunc; } + + icUInt8Number GetPrecision() { return m_nPrecision; } + +protected: + void Iterate(std::string &sDescription, icUInt8Number nIndex, icUInt32Number nPos, bool bUseLegacy=false); + void SubIterate(IIccCLUTExec* pExec, icUInt8Number nIndex, icUInt32Number nPos); + + icCLUTCLIPFUNC UnitClip; + + icUInt8Number m_nReserved2[3]; + + icUInt8Number m_nInput; + icUInt16Number m_nOutput; //16 bit to support MPE CLUT elements + icUInt8Number m_nPrecision; + + icUInt8Number m_GridPoints[16]; + icUInt32Number m_nNumPoints; + + icUInt32Number m_DimSize[16]; + icFloatNumber *m_pData; + + //Iteration temporary variables + icUInt8Number m_GridAdr[16]; + icFloatNumber m_fGridAdr[16]; + icChar *m_pOutText, *m_pVal; + icColorSpaceSignature m_csInput, m_csOutput; + + //Tetrahedral interpolation variables + icUInt8Number m_MaxGridPoint[16]; + icUInt32Number n000, n001, n010, n011, n100, n101, n110, n111, n1000, n10000, n100000; + + //ND Interpolation + icUInt32Number *m_nOffset; + // Temporary ND Interp Variables + icFloatNumber *m_g, *m_s, *m_df; + icUInt32Number* m_ig; + icUInt32Number m_nNodes, m_nPower[16]; +}; + + +/** +**************************************************************************** +* Class: CIccMBB +* +* Purpose: The Multi-dimensional Black Box (MBB) base class for lut8, lut16, +* lutA2B and lutB2A tag types +***************************************************************************** +*/ +class ICCPROFLIB_API CIccMBB : public CIccTag +{ + friend class ICCPROFLIB_API CIccXform3DLut; + friend class ICCPROFLIB_API CIccXform4DLut; + friend class ICCPROFLIB_API CIccXformNDLut; +public: + CIccMBB(); + CIccMBB(const CIccMBB &IMBB); + CIccMBB &operator=(const CIccMBB &IMBB); + virtual CIccTag* NewCopy() const {return new CIccMBB(*this);} + virtual ~CIccMBB(); + + virtual bool IsMBBType() { return true;} + + virtual icUInt8Number GetPrecision() { return 2; } + virtual bool IsInputMatrix() { return m_bInputMatrix; } //Is matrix on input side of CLUT? + virtual bool UseLegacyPCS() const { return false; } //Treat Lab Encoding differently? + + bool IsInputB() { return IsInputMatrix(); } + bool SwapMBCurves() { return m_bUseMCurvesAsBCurves; } + + void Cleanup(); + void Init(icUInt8Number nInputChannels, icUInt8Number nOutputChannels); + + icUInt8Number InputChannels() const { return m_nInput; } + icUInt8Number OutputChannels() const { return m_nOutput; } + + virtual void Describe(std::string &sDescription); + + virtual void SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + LPIccCurve* NewCurvesA(); + CIccCLUT* NewCLUT(icUInt8Number nGridPoints, icUInt8Number nPrecision=2); + CIccCLUT* NewCLUT(icUInt8Number *pGridPoints, icUInt8Number nPrecision=2); + CIccMatrix* NewMatrix(); + LPIccCurve* NewCurvesM(); + LPIccCurve* NewCurvesB(); + + CIccMatrix *GetMatrix() const {return m_Matrix; } + CIccCLUT *GetCLUT() const {return m_CLUT;} + LPIccCurve *GetCurvesA() const {return m_CurvesA;} + LPIccCurve *GetCurvesB() const {return m_CurvesB;} + LPIccCurve *GetCurvesM() const {return m_CurvesM;} + + CIccCLUT *SetCLUT(CIccCLUT *clut); + +protected: + bool m_bInputMatrix; + bool m_bUseMCurvesAsBCurves; + + icUInt8Number m_nInput; + icUInt8Number m_nOutput; + + icColorSpaceSignature m_csInput; + icColorSpaceSignature m_csOutput; + + LPIccCurve *m_CurvesA; + CIccCLUT *m_CLUT; + CIccMatrix *m_Matrix; + LPIccCurve *m_CurvesM; + LPIccCurve *m_CurvesB; + +}; + +/** +**************************************************************************** +* Class: CIccTagLutAtoB +* +* Purpose: The LutA2B tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagLutAtoB : public CIccMBB +{ +public: + CIccTagLutAtoB(); + CIccTagLutAtoB(const CIccTagLutAtoB &ITLA2B); + CIccTagLutAtoB &operator=(const CIccTagLutAtoB &ITLA2B); + virtual CIccTag* NewCopy() const { return new CIccTagLutAtoB(*this); } + virtual ~CIccTagLutAtoB(); + + virtual icTagTypeSignature GetType() const { return icSigLutAtoBType; } + + bool Read(icUInt32Number size, CIccIO *pIO); + bool Write(CIccIO *pIO); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt16Number m_nReservedWord; +}; + +/** +**************************************************************************** +* Class: CIccTagLutBtoA +* +* Purpose: The LutB2A tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagLutBtoA : public CIccTagLutAtoB +{ +public: + CIccTagLutBtoA(); + CIccTagLutBtoA(const CIccTagLutBtoA &ITLB2A); + CIccTagLutBtoA &operator=(const CIccTagLutBtoA &ITLB2A); + virtual CIccTag* NewCopy() const { return new CIccTagLutBtoA(*this); } + + virtual icTagTypeSignature GetType() const { return icSigLutBtoAType; } + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; +}; + + +/** +**************************************************************************** +* Class: CIccTagLut8 +* +* Purpose: The Lut8 tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagLut8 : public CIccMBB +{ +public: + CIccTagLut8(); + CIccTagLut8(const CIccTagLut8 &ITL); + CIccTagLut8 &operator=(const CIccTagLut8 &ITL); + virtual CIccTag* NewCopy() const {return new CIccTagLut8(*this);} + virtual ~CIccTagLut8(); + + virtual icTagTypeSignature GetType() const { return icSigLut8Type; } + virtual icUInt8Number GetPrecision() { return 1; } + + bool Read(icUInt32Number size, CIccIO *pIO); + bool Write(CIccIO *pIO); + + virtual void SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt8Number m_nReservedByte; + icS15Fixed16Number m_XYZMatrix[9]; +}; + +/** +**************************************************************************** +* Class: CIccTagLut16 +* +* Purpose: The Lut16 tag type +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagLut16 : public CIccMBB +{ +public: + CIccTagLut16(); + CIccTagLut16(const CIccTagLut16 &ITL); + CIccTagLut16 &operator=(const CIccTagLut16 &ITL); + virtual CIccTag* NewCopy() const {return new CIccTagLut16(*this);} + virtual ~CIccTagLut16(); + + virtual icTagTypeSignature GetType() const { return icSigLut16Type; } + virtual bool UseLegacyPCS() const { return true; } //Treat Lab Encoding differently? + + bool Read(icUInt32Number size, CIccIO *pIO); + bool Write(CIccIO *pIO); + + virtual void SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput); + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + +protected: + icUInt8Number m_nReservedByte; + icS15Fixed16Number m_XYZMatrix[9]; +}; + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif // !defined(_ICCTAG_H) diff --git a/library/src/main/cpp/icc/IccTagMPE.cpp b/library/src/main/cpp/icc/IccTagMPE.cpp new file mode 100644 index 00000000..e5bceb32 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagMPE.cpp @@ -0,0 +1,1440 @@ +/** @file + File: IccTagMpe.cpp + + Contains: Implementation of MultiProcessElementType Tag + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 1-30-2006 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) +#pragma warning( disable: 4786) //disable warning in +#endif + +#include +#include +#include +#include +#include "IccTagMPE.h" +#include "IccIO.h" +#include "IccMpeFactory.h" +#include +#include "IccUtil.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** + ****************************************************************************** + * Name: CIccApplyMpe::CIccApplyMpe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccApplyMpe::CIccApplyMpe(CIccMultiProcessElement *pElem) +{ + m_pElem = pElem; +} + + +/** + ****************************************************************************** + * Name: CIccApplyMpe::~CIccApplyMpe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccApplyMpe::~CIccApplyMpe() +{ +} + + +/** + ****************************************************************************** + * Name: CIccMultiProcessElement::Create + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMultiProcessElement* CIccMultiProcessElement::Create(icElemTypeSignature sig) +{ + return CIccMpeCreator::CreateElement(sig); +} + +/** + ****************************************************************************** + * Name: CIccMultiProcessElement::GetNewApply() + * + * Purpose: + * + * Args: + * + * Return: +******************************************************************************/ +CIccApplyMpe* CIccMultiProcessElement::GetNewApply( CIccApplyTagMpe *pApplyTag ) +{ + return new CIccApplyMpe(this); +} + + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::CIccMpeUnknown + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeUnknown::CIccMpeUnknown() +{ + m_sig = icSigUnknownElemType; + m_nReserved = 0; + m_nInputChannels = 0; + m_nOutputChannels = 0; + m_nSize = 0; + m_pData = 0; +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::CIccMpeUnknown + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeUnknown::CIccMpeUnknown(const CIccMpeUnknown &elem) +{ + m_sig = elem.m_sig; + m_nReserved = elem.m_nReserved; + m_nInputChannels = elem.m_nInputChannels; + m_nOutputChannels = elem.m_nOutputChannels; + m_nSize = elem.m_nSize; + if (m_nSize) { + m_pData = (icUInt8Number*)malloc(m_nSize); + memcpy(m_pData, elem.m_pData, m_nSize); + } + else + m_pData = NULL; +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeUnknown &CIccMpeUnknown::operator=(const CIccMpeUnknown &elem) +{ + if (m_pData) + free(m_pData); + + m_sig = elem.m_sig; + m_nReserved = elem.m_nReserved; + m_nInputChannels = elem.m_nInputChannels; + m_nOutputChannels = elem.m_nOutputChannels; + m_nSize = elem.m_nSize; + if (m_nSize) { + m_pData = (icUInt8Number*)malloc(m_nSize); + memcpy(m_pData, elem.m_pData, m_nSize); + } + else + m_pData = NULL; + + return (*this); +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::~CIccMpeUnknown + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccMpeUnknown::~CIccMpeUnknown() +{ + if (m_pData) + free(m_pData); +} + +/** +****************************************************************************** +* Name: CIccMpeUnknown::SetType +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +void CIccMpeUnknown::SetType(icElemTypeSignature sig) +{ + m_sig = sig; +} + +/** +****************************************************************************** +* Name: CIccMpeUnknown::Describe +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +void CIccMpeUnknown::SetChannels(icUInt16Number nInputChannels, icUInt16Number nOutputChannels) +{ + m_nInputChannels = nInputChannels; + m_nOutputChannels = nOutputChannels; +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccMpeUnknown::Describe(std::string &sDescription) +{ + icChar buf[128], sigbuf[40]; + + sprintf(buf, "Unknown Element(%s) Type of %u Bytes.", + icGetSig(sigbuf, m_sig), m_nSize); + sDescription += buf; + + sDescription += "\r\n\r\nData Follows:\r\n"; + + icMemDump(sDescription, m_pData, m_nSize); + +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::SetDataSize + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeUnknown::SetDataSize(icUInt32Number nSize, bool bZeroData/*=true*/) +{ + bool rv = true; + if (m_pData) + free(m_pData); + + m_nSize = nSize; + if (m_nSize) { + m_pData = (icUInt8Number*)malloc(m_nSize); + if (!m_pData) { + rv = false; + m_nSize = 0; + } + } + else + m_pData = NULL; + + return rv; +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeUnknown::Read(icUInt32Number nSize, CIccIO *pIO) +{ + icUInt32Number nHeaderSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt16Number) + + sizeof(icUInt16Number); + + if (nHeaderSize > nSize) + return false; + + if (!pIO) { + return false; + } + + if (!pIO->Read32(&m_sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&m_nInputChannels)) + return false; + + if (!pIO->Read16(&m_nOutputChannels)) + return false; + + icUInt32Number nDataSize = nSize - nHeaderSize; + + if (nDataSize) { + if (!SetDataSize(nDataSize, false)) + return false; + + if (pIO->Read8(m_pData, nDataSize)!=(icInt32Number)nDataSize) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccMpeUnknown::Write(CIccIO *pIO) +{ + if (!pIO) + return false; + + //icUInt32Number elemStart = pIO->Tell(); + + if (!pIO->Write32(&m_sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (m_nSize) { + if (pIO->Write8(m_pData, m_nSize)!=(icInt32Number)m_nSize) + return false; + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccMpeUnknown::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccMpeUnknown::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + CIccInfo Info; + icChar buf[40]; + std::string sSigName = Info.GetSigName(sig); + + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " - Element "; + sSigName = Info.GetSigName(GetType()); + sReport += sSigName; + sReport += " - Contains unknown processing element type ("; + icGetSig(buf, m_sig, true); + sReport += buf; + sReport += ").\r\n"; + + return icValidateCriticalError; +} + + +/** + ****************************************************************************** + * Name: CIccProcessElement::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccMultiProcessElement::Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE/*=NULL*/) const +{ + icValidateStatus rv = icValidateOK; + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + if (m_nReserved!=0) { + sReport += icValidateNonCompliantMsg; + sReport += sSigName; + sReport += " - Element "; + sSigName = Info.GetSigName(GetType()); + sReport += sSigName; + sReport += " - Reserved Value must be zero.\r\n"; + + rv = icValidateNonCompliant; + } + + return rv; +} + + +/** + ****************************************************************************** + * Name: CIccDblPixelBuffer::CIccDblPixelBuffer + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccDblPixelBuffer::CIccDblPixelBuffer() +{ + m_nMaxChannels = 0; + m_nLastNumChannels = 0; + m_pixelBuf1 = NULL; + m_pixelBuf2 = NULL; +} + + +/** + ****************************************************************************** + * Name: CIccDblPixelBuffer::CIccDblPixelBuffer + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccDblPixelBuffer::CIccDblPixelBuffer(const CIccDblPixelBuffer &buf) +{ + m_nMaxChannels = buf.m_nMaxChannels; + if (m_nMaxChannels) { + m_pixelBuf1 = (icFloatNumber*)malloc(m_nMaxChannels*sizeof(icFloatNumber)); + if (m_pixelBuf1) + memcpy(m_pixelBuf1, buf.m_pixelBuf1, m_nMaxChannels*sizeof(icFloatNumber)); + + m_pixelBuf2 = (icFloatNumber*)malloc(m_nMaxChannels*sizeof(icFloatNumber)); + if (m_pixelBuf2) + memcpy(m_pixelBuf2, buf.m_pixelBuf2, m_nMaxChannels*sizeof(icFloatNumber)); + } + else { + m_pixelBuf1 = NULL;; + m_pixelBuf2 = NULL; + } +} + + +/** + ****************************************************************************** + * Name: CIccDblPixelBuffer::CIccDblPixelBuffer + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccDblPixelBuffer& CIccDblPixelBuffer::operator=(const CIccDblPixelBuffer &buf) +{ + Clean(); + + m_nMaxChannels = buf.m_nMaxChannels; + if (m_nMaxChannels) { + m_pixelBuf1 = (icFloatNumber*)malloc(m_nMaxChannels*sizeof(icFloatNumber)); + if (m_pixelBuf1) + memcpy(m_pixelBuf1, buf.m_pixelBuf1, m_nMaxChannels*sizeof(icFloatNumber)); + + m_pixelBuf2 = (icFloatNumber*)malloc(m_nMaxChannels*sizeof(icFloatNumber)); + if (m_pixelBuf2) + memcpy(m_pixelBuf2, buf.m_pixelBuf2, m_nMaxChannels*sizeof(icFloatNumber)); + } + else { + m_pixelBuf1 = NULL;; + m_pixelBuf2 = NULL; + } + + return *this; +} + +/** + ****************************************************************************** + * Name: CIccDblPixelBuffer::~CIccDblPixelBuffer + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccDblPixelBuffer::~CIccDblPixelBuffer() +{ + Clean(); +} + + +/** + ****************************************************************************** + * Name: CIccDblPixelBuffer::CIccDblPixelBuffer + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccDblPixelBuffer::Clean() +{ + if (m_pixelBuf1) { + free(m_pixelBuf1); + m_pixelBuf1 = NULL; + } + if (m_pixelBuf2) { + free(m_pixelBuf2); + m_pixelBuf2 = NULL; + } + m_nMaxChannels = 0; + m_nLastNumChannels = 0; +} + +/** + ****************************************************************************** + * Name: CIccDblPixelBuffer::CIccDblPixelBuffer + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccDblPixelBuffer::Begin() +{ + m_pixelBuf1 = (icFloatNumber*)calloc(m_nMaxChannels, sizeof(icFloatNumber)); + m_pixelBuf2 = (icFloatNumber*)calloc(m_nMaxChannels, sizeof(icFloatNumber)); + + return (!m_nMaxChannels || (m_pixelBuf1!=NULL && m_pixelBuf2!=NULL)); +} + + +/** +****************************************************************************** +* Name: CIccApplyTagMpe::CIccApplyTagMpe +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccApplyTagMpe::CIccApplyTagMpe(CIccTagMultiProcessElement *pTag) +{ + m_pTag = pTag; + m_list = NULL; +} + + +/** +****************************************************************************** +* Name: CIccApplyTagMpe::~CIccApplyTagMpe +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccApplyTagMpe::~CIccApplyTagMpe() +{ + if (m_list) { + CIccApplyMpeList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + delete i->ptr; + } + + delete m_list; + } +} + + +/** +****************************************************************************** +* Name: CIccApplyTagMpe::CIccApplyTagMpe +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +bool CIccApplyTagMpe::AppendElem(CIccMultiProcessElement *pElem) +{ + if (!m_list) + m_list = new CIccApplyMpeList(); + + if (!m_list) + return false; + + CIccApplyMpe *pApply = pElem->GetNewApply(this); + + if (!pApply) + return false; + + CIccApplyMpePtr ptr; + + ptr.ptr = pApply; + m_list->push_back(ptr); + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::CIccTagMultiProcessElement + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagMultiProcessElement::CIccTagMultiProcessElement(icUInt16Number nInputChannels/* =0 */, icUInt16Number nOutputChannels/* =0 */) +{ + m_nReserved = 0; + m_list = NULL; + m_nProcElements = 0; + m_position = NULL; + + m_nInputChannels = nInputChannels; + m_nOutputChannels = nOutputChannels; +} + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::CIccTagMultiProcessElement + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagMultiProcessElement::CIccTagMultiProcessElement(const CIccTagMultiProcessElement &lut) +{ + m_nReserved = lut.m_nReserved; + + if (lut.m_list) { + m_list = new CIccMultiProcessElementList(); + + CIccMultiProcessElementList::iterator i; + CIccMultiProcessElementPtr ptr; + + for (i=lut.m_list->begin(); i!= lut.m_list->end(); i++) { + ptr.ptr = (CIccMultiProcessElement*)i->ptr->NewCopy(); + m_list->push_back(ptr); + } + } + m_nInputChannels = lut.m_nInputChannels; + m_nOutputChannels = lut.m_nOutputChannels; + + if (lut.m_nProcElements && lut.m_position) { + m_position = (icPositionNumber*)malloc(lut.m_nProcElements*sizeof(icPositionNumber)); + if (m_position) { + memcpy(m_position, lut.m_position, lut.m_nProcElements*sizeof(icPositionNumber)); + } + m_nProcElements = lut.m_nProcElements; + } + +} + +/** + ****************************************************************************** + * Name: &operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagMultiProcessElement &CIccTagMultiProcessElement::operator=(const CIccTagMultiProcessElement &lut) +{ + Clean(); + + m_nReserved = lut.m_nReserved; + + if (lut.m_list) { + m_list = new CIccMultiProcessElementList(); + + CIccMultiProcessElementList::iterator i; + CIccMultiProcessElementPtr ptr; + + for (i=lut.m_list->begin(); i!= lut.m_list->end(); i++) { + ptr.ptr = (CIccMultiProcessElement*)i->ptr->NewCopy(); + m_list->push_back(ptr); + } + } + m_nInputChannels = lut.m_nInputChannels; + m_nOutputChannels = lut.m_nOutputChannels; + + if (lut.m_nProcElements && lut.m_position) { + m_position = (icPositionNumber*)malloc(lut.m_nProcElements*sizeof(icPositionNumber)); + if (m_position) { + memcpy(m_position, lut.m_position, lut.m_nProcElements*sizeof(icPositionNumber)); + } + m_nProcElements = lut.m_nProcElements; + } + + return *this; +} + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::~CIccTagMultiProcessElement + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagMultiProcessElement::~CIccTagMultiProcessElement() +{ + Clean(); +} + +typedef std::map CIccLutPtrMap; +typedef std::map CIccLutOffsetMap; +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Clean + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccTagMultiProcessElement::Clean() +{ + if (m_list) { + CIccLutPtrMap map; + CIccMultiProcessElementList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + if (!map[i->ptr].offset) { + map[i->ptr].offset = 1; + delete i->ptr; + } + } + + delete m_list; + m_list = NULL; + } + + if (m_position) { + free(m_position); + m_position = NULL; + } + + m_nProcElements = 0; +} + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::IsSupported + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagMultiProcessElement::IsSupported() +{ + if (m_list) { + CIccMultiProcessElementList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + if (!i->ptr->IsSupported()) + return false; + } + } + + return true; +} + + + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccTagMultiProcessElement::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sprintf(buf, "BEGIN MULTI_PROCESS_ELEMENT_TAG %d %d\r\n", m_nInputChannels, m_nOutputChannels); + sDescription += buf; + sDescription += "\r\n"; + + CIccMultiProcessElementList::iterator i; + int j; + + for (j=0, i=m_list->begin(); i!=m_list->end(); j++, i++) { + sprintf(buf, "PROCESS_ELEMENT #%d\r\n", j+1); + sDescription += buf; + i->ptr->Describe(sDescription); + sDescription += "\r\n"; + } +} + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Attach + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccTagMultiProcessElement::Attach(CIccMultiProcessElement *pElement) +{ + if (!m_list) { + m_list = new CIccMultiProcessElementList(); + } + + CIccMultiProcessElementPtr ptr; + + ptr.ptr = pElement; + + m_list->push_back(ptr); +} + + + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagMultiProcessElement::Read(icUInt32Number size, CIccIO *pIO) +{ + icTagTypeSignature sig; + + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt8Number) + + sizeof(icUInt8Number) + + sizeof(icUInt16Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + Clean(); + + icUInt32Number tagStart = pIO->Tell(); + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + if (!pIO->Read16(&m_nInputChannels)) + return false; + + if (!pIO->Read16(&m_nOutputChannels)) + return false; + + if (!pIO->Read32(&m_nProcElements)) + return false; + + if (headerSize + m_nProcElements*sizeof(icUInt32Number) > size) + return false; + + m_list = new CIccMultiProcessElementList(); + + if (!m_list) + return false; + + icUInt32Number i; + + m_position = (icPositionNumber*)calloc(m_nProcElements, sizeof(icPositionNumber)); + + if (!m_position) + return false; + + CIccLutOffsetMap loadedElements; + + for (i=0; iRead32(&m_position[i].offset)) + return false; + if (!pIO->Read32(&m_position[i].size)) + return false; + } + + CIccMultiProcessElementPtr ptr; + icElemTypeSignature sigElem; + + for (i=0; i size) { + return false; + } + + //Use hash to cache offset duplication + CIccMultiProcessElement *element = loadedElements[m_position[i].offset]; + if (!element) { + icUInt32Number pos = tagStart + m_position[i].offset; + + if (pIO->Seek(pos, icSeekSet)!=(icInt32Number)pos) { + return false; + } + + if (!pIO->Read32(&sigElem)) { + return false; + } + + if (pIO->Seek(pos, icSeekSet)!=(icInt32Number)pos) { + return false; + } + + element = CIccMultiProcessElement::Create(sigElem); + if (!element) { + return false; + } + + if (!element->Read(m_position[i].size, pIO)) { + delete element; + return false; + } + + loadedElements[m_position[i].offset] = element; + } + ptr.ptr = element; + + m_list->push_back(ptr); + } + + return true; +} + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagMultiProcessElement::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + icUInt32Number tagStart = pIO->Tell(); + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + if (!pIO->Write16(&m_nInputChannels)) + return false; + + if (!pIO->Write16(&m_nOutputChannels)) + return false; + + if (m_list) { + m_nProcElements = (icUInt32Number)m_list->size(); + } + else { + m_nProcElements = 0; + } + + if (!pIO->Write32(&m_nProcElements)) + return false; + + if (m_nProcElements) { + icUInt32Number offsetPos = pIO->Tell(); + + if (m_position) { + delete [] m_position; + } + + m_position = (icPositionNumber*)calloc(m_nProcElements, sizeof(icPositionNumber)); + + if (!m_position) + return false; + + //Write an empty position table + icUInt32Number j, zeros[2] = { 0, 0 }; + for (j=0; jWrite32(zeros, 2)!=2) + return false; + } + + CIccLutPtrMap map; + CIccMultiProcessElementList::iterator i; + icUInt32Number start, end; + icPositionNumber position; + + //Write out each process element + for (j=0, i=m_list->begin(); i!=m_list->end(); i++, j++) { + if (map.find(i->ptr)==map.end()) { + start = pIO->Tell(); + + if (!i->ptr->Write(pIO)) + return false; + + end = pIO->Tell(); + + if (!pIO->Sync32()) + return false; + + position.offset = start - tagStart; + position.size = end - start; + + map[i->ptr] = position; + } + m_position[j] = map[i->ptr]; + } + + icUInt32Number endPos = pIO->Tell(); + + if (pIO->Seek(offsetPos, icSeekSet)<0) + return false; + + for (j=0; jWrite32(&m_position[j].offset)) + return false; + if (!pIO->Write32(&m_position[j].size)) + return false; + } + + if (pIO->Seek(endPos, icSeekSet)<0) + return false; + } + + return true; +} + +/** +****************************************************************************** +* Name: CIccTagMultiProcessElement::GetElement +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccMultiProcessElement *CIccTagMultiProcessElement::GetElement(int nIndex) +{ + if (!m_list) + return NULL; + + CIccMultiProcessElementList::iterator i; + int j; + + for(i=m_list->begin(), j=0; jend(); i++, j++); + + if (i!=m_list->end()) + return i->ptr; + + return NULL; +} + +/** +****************************************************************************** +* Name: CIccTagMultiProcessElement::GetNextElemIterator +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +void CIccTagMultiProcessElement::GetNextElemIterator(CIccMultiProcessElementList::iterator &itr) +{ + itr++; +} + + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Begin + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagMultiProcessElement::Begin(icElemInterp nInterp/* =icElemInterpLinear */) +{ + if (!m_list || !m_list->size()) { + if (m_nInputChannels != m_nOutputChannels) + return false; + else + return true; + } + + CIccMultiProcessElementList::iterator i; + + m_nBufChannels=0; + + //Now we initialize each processing element checking channel matching as we go + CIccMultiProcessElement *last=NULL; + i = m_list->begin(); + if (i->ptr->NumInputChannels() != m_nInputChannels) + return false; + + for (; i!= m_list->end(); i++) { + if (last) { + if (i->ptr->NumInputChannels() != last->NumOutputChannels()) + return false; + } + last = i->ptr; + + if (m_nBufChannelsNumOutputChannels()) + m_nBufChannels = last->NumOutputChannels(); + + if (!last->Begin(nInterp, this)) + return false; + } + + //The output channels must match + if (last && last->NumOutputChannels() != m_nOutputChannels) + return false; + + return true; +} + + + + +/** +****************************************************************************** +* Name: CIccTagMultiProcessElement::ElementIndex +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +icInt32Number CIccTagMultiProcessElement::ElementIndex(CIccMultiProcessElement *pElem) +{ + CIccMultiProcessElementList::iterator i; + icInt32Number n; + + for (n=0, i=m_list->begin(); i!= m_list->end(); i++, n++) { + if (i->ptr == pElem) + break; + } + if (i==m_list->end()) + n=-1; + + return n; +} + +CIccMultiProcessElementList::iterator CIccTagMultiProcessElement::GetFirstElem() +{ + return m_list->begin(); +} + +CIccMultiProcessElementList::iterator CIccTagMultiProcessElement::GetLastElem() +{ + return m_list->end(); +} + + +/** +****************************************************************************** +* Name: CIccTagMultiProcessElement::GetNewApply +* +* Purpose: +* +* Args: +* +* Return: +******************************************************************************/ +CIccApplyTagMpe *CIccTagMultiProcessElement::GetNewApply() +{ + CIccApplyTagMpe *pApply = new CIccApplyTagMpe(this); + + if (!pApply) + return NULL; + + CIccDblPixelBuffer *pApplyBuf = pApply->GetBuf(); + pApplyBuf->UpdateChannels(m_nBufChannels); + if (!pApplyBuf->Begin()) { + delete pApply; + return NULL; + } + + if (!m_list || !m_list->size()) + return pApply; + + CIccMultiProcessElementList::iterator i, last; + last = GetLastElem(); + for (i=GetFirstElem(); i!=last;) { + pApply->AppendElem(i->ptr); + + GetNextElemIterator(i); + } + + return pApply; +} + + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Apply + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccTagMultiProcessElement::Apply(CIccApplyTagMpe *pApply, icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) const +{ + if (!pApply || !pApply->GetList() || !pApply->GetList()->size()) { + memcpy(pDestPixel, pSrcPixel, m_nInputChannels*sizeof(icFloatNumber)); + return; + } + + CIccDblPixelBuffer *pApplyBuf = pApply->GetBuf(); + CIccApplyMpeIter i = pApply->begin(); + CIccApplyMpeIter next; + + next = i; + next++; + + if (next==pApply->end()) { + //Elements rely on pDestPixel != pSrcPixel + if (pSrcPixel==pDestPixel) { + i->ptr->Apply(pApplyBuf->GetDstBuf(), pSrcPixel); + memcpy(pDestPixel, pApplyBuf->GetDstBuf(), m_nOutputChannels*sizeof(icFloatNumber)); + } + else { + i->ptr->Apply(pDestPixel, pSrcPixel); + } + } + else { + i->ptr->Apply(pApplyBuf->GetDstBuf(), pSrcPixel); + i++; + next++; + pApplyBuf->Switch(); + + while (next != pApply->end()) { + CIccMultiProcessElement *pElem = i->ptr->GetElem(); + + if (!pElem->IsAcs()) { + i->ptr->Apply(pApplyBuf->GetDstBuf(), pApplyBuf->GetSrcBuf()); + pApplyBuf->Switch(); + } + + i++; + next++; + } + + i->ptr->Apply(pDestPixel, pApplyBuf->GetSrcBuf()); + } +} + + +/** + ****************************************************************************** + * Name: CIccTagMultiProcessElement::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccTagMultiProcessElement::Validate(icTagSignature sig, std::string &sReport, + const CIccProfile* pProfile /*=NULL*/) const +{ + icValidateStatus rv = icValidateOK; + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + if (!m_list || !m_list->size()) { + if (m_nInputChannels != m_nOutputChannels) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " No processing elements and input and output channels do not match!\r\n"; + return icValidateCriticalError; + } + else { + sReport += icValidateWarningMsg; + sReport += sSigName; + sReport += " No processing elements.\r\n"; + return icValidateWarning; + } + } + + CIccMultiProcessElementList::iterator i = m_list->begin(); + CIccMultiProcessElement *last=NULL; + + if (i->ptr->NumInputChannels() != m_nInputChannels) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " Mis-matching number of input channels!\r\n"; + return icValidateCriticalError; + } + + for (; i!= m_list->end(); i++) { + if (last) { + if (i->ptr->NumInputChannels() != last->NumOutputChannels()) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + + sReport += "("; + sReport += last->GetClassName(); + sReport += "->"; + sReport += i->ptr->GetClassName(); + + sReport += " Mis-matching number of channels!\r\n"; + return icValidateCriticalError; + } + } + last = i->ptr; + + rv = icMaxStatus(rv, last->Validate(sig, sReport, this)); + } + + if (last && last->NumOutputChannels() != m_nOutputChannels) { + sReport += icValidateCriticalErrorMsg; + sReport += sSigName; + sReport += " Mis-matching number of output channels!\r\n"; + return icValidateCriticalError; + } + + return rv; +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccTagMPE.h b/library/src/main/cpp/icc/IccTagMPE.h new file mode 100644 index 00000000..5a949211 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagMPE.h @@ -0,0 +1,410 @@ +/** @file +File: IccTagMPE.h + +Contains: Header for implementation of CIccTagMultiProcessElement +and supporting classes + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2005-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Jan 30, 2005 +// Initial CIccFloatTag prototype development +// +// -Nov 6, 2006 +// Prototype Merged into release +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCTAGMPE_H +#define _ICCTAGMPE_H + +#include "IccTag.h" +#include "IccTagFactory.h" +#include "icProfileHeader.h" +#include +#include + + +//CIccFloatTag support +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +typedef enum { + icElemInterpLinear, + icElemInterpTetra, +} icElemInterp; + +class CIccTagMultiProcessElement; +class CIccMultiProcessElement; + +class CIccApplyTagMpe; +class CIccApplyMpe; + +/** +**************************************************************************** +* Class: CIccProcessElementPtr +* +* Purpose: Get std list class to work with pointers to elements rather than +* element objects so they can be shared. +***************************************************************************** +*/ +class CIccMultiProcessElementPtr +{ +public: + CIccMultiProcessElement *ptr; +}; + +typedef std::list CIccMultiProcessElementList; +typedef CIccMultiProcessElementList::iterator CIccMultiProcessElementIter; + +#define icSigMpeLevel0 ((icSignature)0x6D706530) /* 'mpe0' */ + +class CIccApplyMpePtr +{ +public: + CIccApplyMpe *ptr; +}; + +typedef std::list CIccApplyMpeList; +typedef CIccApplyMpeList::iterator CIccApplyMpeIter; + +class IIccExtensionMpe +{ +public: + virtual const char *GetExtClassName() const=0; +}; + +/** +**************************************************************************** +* Class: CIccMultiProcessElement +* +* Purpose: Base Class for Multi Process Elements +***************************************************************************** +*/ +class CIccMultiProcessElement +{ +public: + CIccMultiProcessElement() {} + + virtual ~CIccMultiProcessElement() {} + + static CIccMultiProcessElement* Create(icElemTypeSignature sig); + + virtual CIccMultiProcessElement *NewCopy() const = 0; + + virtual icElemTypeSignature GetType() const = 0; + virtual const icChar *GetClassName() const = 0; + + virtual icUInt16Number NumInputChannels() const { return m_nInputChannels; } + virtual icUInt16Number NumOutputChannels() const { return m_nOutputChannels; } + + virtual bool IsSupported() { return true; } + + virtual void Describe(std::string &sDescription) = 0; + + virtual bool Read(icUInt32Number size, CIccIO *pIO) = 0; + virtual bool Write(CIccIO *pIO) = 0; + + virtual bool Begin(icElemInterp nIterp=icElemInterpLinear, CIccTagMultiProcessElement *pMPE=NULL) = 0; + + virtual CIccApplyMpe* GetNewApply(CIccApplyTagMpe *pApplyTag); + virtual void Apply(CIccApplyMpe *pApply, icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) const = 0; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const = 0; + + //Future Acs Expansion Element Accessors + virtual bool IsAcs() { return false; } + virtual icAcsSignature GetBAcsSig() { return icSigAcsZero; } + virtual icAcsSignature GetEAcsSig() { return icSigAcsZero; } + + // Allow MPE objects to be extended and get extended object type. + virtual IIccExtensionMpe *GetExtension() { return NULL; } + + //All elements start with a reserved value. Allocate a place to put it. + icUInt32Number m_nReserved; + +protected: + icUInt16Number m_nInputChannels; + icUInt16Number m_nOutputChannels; +}; + +/** +**************************************************************************** +* Class: CIccApplyMpe +* +* Purpose: Base Class for Apply storage for Multi Process Elements +***************************************************************************** +*/ +class CIccApplyMpe +{ +public: + CIccApplyMpe(CIccMultiProcessElement *pElem); + virtual ~CIccApplyMpe(); + + virtual icElemTypeSignature GetType() const { return icSigUnknownElemType; } + virtual const icChar *GetClassName() const { return "CIccApplyMpe"; } + + CIccMultiProcessElement *GetElem() const { return m_pElem; } + + void Apply(icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) { m_pElem->Apply(this, pDestPixel, pSrcPixel); } + +protected: + CIccApplyTagMpe *m_pApplyTag; + + CIccMultiProcessElement *m_pElem; +}; + + +/** +**************************************************************************** +* Class: CIccMpeUnknown +* +* Purpose: Base Class for Process Elements +***************************************************************************** +*/ +class CIccMpeUnknown : public CIccMultiProcessElement +{ +public: + CIccMpeUnknown(); + CIccMpeUnknown(const CIccMpeUnknown &elem); + CIccMpeUnknown &operator=(const CIccMpeUnknown &elem); + virtual CIccMultiProcessElement *NewCopy() const { return new CIccMpeUnknown(*this);} + virtual ~CIccMpeUnknown(); + + virtual icElemTypeSignature GetType() const { return m_sig; } + virtual const icChar *GetClassName() const { return "CIccMpeUnknown"; } + + virtual bool IsSupported() { return false; } + + virtual void Describe(std::string &sDescription); + + void SetType(icElemTypeSignature sig); + void SetChannels(icUInt16Number nInputChannels, icUInt16Number nOutputChannels); + + bool SetDataSize(icUInt32Number nSize, bool bZeroData=true); + icUInt8Number *GetData() { return m_pData; } + + virtual bool Read(icUInt32Number nSize, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual bool Begin(icElemInterp nIterp=icElemInterpLinear, CIccTagMultiProcessElement *pMPE=NULL) { return false; } + virtual CIccApplyMpe *GetNewApply() { return NULL; } + virtual void Apply(CIccApplyMpe *pApply, icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) const {} + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccTagMultiProcessElement* pMPE=NULL) const; + +protected: + icElemTypeSignature m_sig; + icUInt32Number m_nReserved; + icUInt16Number m_nInputChannels; + icUInt16Number m_nOutputChannels; + icUInt32Number m_nSize; + icUInt8Number *m_pData; +}; + + +/** +**************************************************************************** +* Class: CIccDblPixelBuffer +* +* Purpose: The general purpose pixel storage buffer for pixel apply +***************************************************************************** +*/ +class CIccDblPixelBuffer +{ +public: + CIccDblPixelBuffer(); + CIccDblPixelBuffer(const CIccDblPixelBuffer &buf); + CIccDblPixelBuffer &operator=(const CIccDblPixelBuffer &buf); + virtual ~CIccDblPixelBuffer(); + + void Clean(); + void Reset() { m_nLastNumChannels = 0; } + + void UpdateChannels(icUInt16Number nNumChannels) { + m_nLastNumChannels = nNumChannels; + if (nNumChannels>m_nMaxChannels) + m_nMaxChannels=nNumChannels; + } + + bool Begin(); + + icUInt16Number GetMaxChannels() { return m_nMaxChannels; } + icFloatNumber *GetSrcBuf() { return m_pixelBuf1; } + icFloatNumber *GetDstBuf() { return m_pixelBuf2; } + + void Switch() { icFloatNumber *tmp; tmp=m_pixelBuf2; m_pixelBuf2=m_pixelBuf1; m_pixelBuf1=tmp; } + + icUInt16Number GetAvailChannels() { return m_nLastNumChannels & 0x7fff; } + +protected: + //For application + icUInt16Number m_nMaxChannels; + icUInt16Number m_nLastNumChannels; + icFloatNumber *m_pixelBuf1; + icFloatNumber *m_pixelBuf2; +}; + + +/** +**************************************************************************** +* Class: CIccTagMultiProcessElement +* +* Purpose: Apply storage for MPE general purpose processing tags +***************************************************************************** +*/ +class CIccApplyTagMpe +{ +public: + CIccApplyTagMpe(CIccTagMultiProcessElement *pTag); + virtual ~CIccApplyTagMpe(); + + CIccTagMultiProcessElement *GetTag() { return m_pTag; } + + virtual bool AppendElem(CIccMultiProcessElement *pElem); + + CIccDblPixelBuffer *GetBuf() { return &m_applyBuf; } + CIccApplyMpeList *GetList() { return m_list; } + + CIccApplyMpeIter begin() { return m_list->begin(); } + CIccApplyMpeIter end() { return m_list->end(); } + +protected: + CIccTagMultiProcessElement *m_pTag; + + //List of processing elements + CIccApplyMpeList *m_list; + + //Pixel data for Apply + CIccDblPixelBuffer m_applyBuf; +}; + +/** +**************************************************************************** +* Class: CIccTagMultiProcessElement +* +* Purpose: A general purpose processing tag +***************************************************************************** +*/ +class CIccTagMultiProcessElement : public CIccTag +{ +public: + CIccTagMultiProcessElement(icUInt16Number nInputChannels=0, icUInt16Number nOutputChannels=0); + CIccTagMultiProcessElement(const CIccTagMultiProcessElement &lut); + CIccTagMultiProcessElement &operator=(const CIccTagMultiProcessElement &lut); + virtual CIccTag *NewCopy() const { return new CIccTagMultiProcessElement(*this);} + virtual ~CIccTagMultiProcessElement(); + + virtual bool IsSupported(); + + virtual icTagTypeSignature GetType() const { return icSigMultiProcessElementType; } + virtual const icChar *GetClassName() const { return "CIccTagMultiProcessElement"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual void Attach(CIccMultiProcessElement *pElement); + + CIccMultiProcessElement *GetElement(int nIndex); + void DeleteElement(int nIndex); + + virtual bool Begin(icElemInterp nInterp=icElemInterpLinear); + virtual CIccApplyTagMpe *GetNewApply(); + + virtual void Apply(CIccApplyTagMpe *pApply, icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) const; + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + icUInt16Number NumInputChannels() const { return m_nInputChannels; } + icUInt16Number NumOutputChannels() const { return m_nOutputChannels; } + +protected: + virtual void Clean(); + virtual void GetNextElemIterator(CIccMultiProcessElementList::iterator &itr); + virtual icInt32Number ElementIndex(CIccMultiProcessElement *pElem); + + virtual CIccMultiProcessElementList::iterator GetFirstElem(); + virtual CIccMultiProcessElementList::iterator GetLastElem(); + + icUInt16Number m_nInputChannels; + icUInt16Number m_nOutputChannels; + + //List of processing elements + CIccMultiProcessElementList *m_list; + + //Offsets of loaded elements + icUInt32Number m_nProcElements; + icPositionNumber *m_position; + + //Number of Buffer Channels needed + icUInt16Number m_nBufChannels; +}; + + +//CIccMpeTag support +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif //_ICCTAGMPE_H diff --git a/library/src/main/cpp/icc/IccTagProfSeqId.cpp b/library/src/main/cpp/icc/IccTagProfSeqId.cpp new file mode 100644 index 00000000..9c4965c3 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagProfSeqId.cpp @@ -0,0 +1,693 @@ +/** @file + File: IccProfSeqId.cpp + + Contains: Implementation of prototype profileSequenceIdentifier Tag + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak Oct-21-2006 +// +////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) || defined(WIN64) +#pragma warning( disable: 4786) //disable warning in +#endif + +#include +#include +#include +#include +#include "IccTagProfSeqId.h" +#include "IccUtil.h" +#include "IccIO.h" + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::CIccProfileIdDesc +* +* Purpose: +* +* Args: +* +* Return: +* +***************************************************************************** +*/ +CIccProfileIdDesc::CIccProfileIdDesc() +{ + memset(&m_profileID, 0, sizeof(m_profileID)); +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::CIccProfileIdDesc +* +* Purpose: +* +* Args: +* CIccProfile &profile +* +* Return: +* +***************************************************************************** +*/ +CIccProfileIdDesc::CIccProfileIdDesc(CIccProfile &profile) +{ + m_profileID = profile.m_Header.profileID; + CIccTag *pTag = profile.FindTag(icSigProfileDescriptionTag); + + if (pTag) { + switch (pTag->GetType()) { + case icSigMultiLocalizedUnicodeType: + { + m_desc = *((CIccTagMultiLocalizedUnicode*)pTag); + } + break; + + case icSigTextDescriptionType: + { + CIccTagTextDescription *pText = (CIccTagTextDescription*)pTag; + + m_desc.SetText(pText->GetText()); + } + break; + + case icSigTextType: + { + CIccTagText *pText = (CIccTagText*)pTag; + + m_desc.SetText(pText->GetText()); + } + break; + + default: + break; + } + } +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::CIccProfileIdDesc +* +* Purpose: +* +* Args: +* icProfileID id +* CIccMultiLocalizedUnicode desc +* +* Return: +* +***************************************************************************** +*/ +CIccProfileIdDesc::CIccProfileIdDesc(icProfileID id, CIccTagMultiLocalizedUnicode desc) +{ + m_profileID = id; + m_desc = desc; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::CIccProfileIdDesc +* +* Purpose: +* +* Args: +* const CIccProfileIdDesc &pid +* +* Return: +* +***************************************************************************** +*/ +CIccProfileIdDesc::CIccProfileIdDesc(const CIccProfileIdDesc &pid) +{ + m_profileID = pid.m_profileID; + m_desc = pid.m_desc; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::operator= +* +* Purpose: +* +* Args: +* const CIccProfileIdDesc &pid +* +* Return: +* CIccProfileIdDesc & +***************************************************************************** +*/ +CIccProfileIdDesc &CIccProfileIdDesc::operator=(const CIccProfileIdDesc &pid) +{ + if (&pid == this) + return *this; + + m_profileID = pid.m_profileID; + m_desc = pid.m_desc; + + return *this; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::Describe +* +* Purpose: +* +* Args: +* std::string &sDescription +* +* Return: +* void +***************************************************************************** +*/ +void CIccProfileIdDesc::Describe(std::string &sDescription) +{ + std::string Dump; + + sDescription += "ProfileID:\r\n"; + + size_t i; + char buf[20]; + for (i=0; i size) + return false; + + if (pIO->Read8(&m_profileID, sizeof(icProfileID))!=sizeof(icProfileID)) + return false; + + if (!m_desc.Read(size - sizeof(icProfileID), pIO)) + return false; + + return true; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::Write +* +* Purpose: +* +* Args: +* CIccIO *pIO +* +* Return: +* bool +***************************************************************************** +*/ +bool CIccProfileIdDesc::Write(CIccIO *pIO) +{ + pIO->Write8(&m_profileID, sizeof(icProfileID)); + m_desc.Write(pIO); + + return true; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccProfileIdDesc::Validate +* +* Purpose: +* +* Args: +* std::string &sReport +* +* Return: +* icValidateStatus +***************************************************************************** +*/ +icValidateStatus CIccProfileIdDesc::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile) const +{ + return m_desc.Validate(sig, sReport, pProfile); +} + + + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::CIccTagProfileSequenceId + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagProfileSequenceId::CIccTagProfileSequenceId() +{ + m_list = new CIccProfileIdDescList(); +} + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::CIccTagProfileSequenceId + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagProfileSequenceId::CIccTagProfileSequenceId(const CIccTagProfileSequenceId &psi) +{ + m_list = new CIccProfileIdDescList(); + + *m_list = *psi.m_list; +} + +/** + ****************************************************************************** + * Name: &operator= + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagProfileSequenceId &CIccTagProfileSequenceId::operator=(const CIccTagProfileSequenceId &psi) +{ + if (&psi == this) + return *this; + + *m_list = *psi.m_list; + + return *this; +} + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::~CIccTagProfileSequenceId + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagProfileSequenceId::~CIccTagProfileSequenceId() +{ + delete m_list; +} + + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::ParseMem + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +CIccTagProfileSequenceId* CIccTagProfileSequenceId::ParseMem(icUInt8Number *pMem, icUInt32Number size) +{ + CIccMemIO IO; + + if (!IO.Attach(pMem, size)) + return NULL; + + CIccTagProfileSequenceId *pProSeqId = new CIccTagProfileSequenceId; + + if (!pProSeqId->Read(size, &IO)) { + delete pProSeqId; + return NULL; + } + + return pProSeqId; +} + + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::Describe + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +void CIccTagProfileSequenceId::Describe(std::string &sDescription) +{ + icChar buf[128]; + + sprintf(buf, "BEGIN ProfileSequenceIdentification_TAG\r\n"); + sDescription += buf; + sDescription += "\r\n"; + + int i; + CIccProfileIdDescList::iterator j; + for (i=0, j=m_list->begin(); j!=m_list->end(); i++, j++) { + sprintf(buf, "ProfileDescription_%d:\r\n", i+1); + sDescription += buf; + j->Describe(sDescription); + } + + sprintf(buf, "END ProfileSequenceIdentification_TAG\r\n"); + sDescription += buf; + sDescription += "\r\n"; +} + + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::Read + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagProfileSequenceId::Read(icUInt32Number size, CIccIO *pIO) +{ + icUInt32Number headerSize = sizeof(icTagTypeSignature) + + sizeof(icUInt32Number) + + sizeof(icUInt32Number); + + if (headerSize > size) + return false; + + if (!pIO) { + return false; + } + + m_list->empty(); + + icUInt32Number sig; + icUInt32Number tagStart = pIO->Tell(); + + if (!pIO->Read32(&sig)) + return false; + + if (!pIO->Read32(&m_nReserved)) + return false; + + icUInt32Number count, i; + + if (!pIO->Read32(&count)) + return false; + + if (headerSize + count*sizeof(icUInt32Number)*2 > size) + return false; + + if (!count) { + return true; + } + + icPositionNumber *pos = new icPositionNumber[count]; + if (!pos) + return false; + + //Read TagDir + for (i=0; iRead32(&pos[i].offset) || + !pIO->Read32(&pos[i].size)) { + delete [] pos; + return false; + } + } + + CIccProfileIdDesc pid; + + for (i=0; i size) { + delete [] pos; + return false; + } + pIO->Seek(tagStart + pos[i].offset, icSeekSet); + + if (!pid.Read(pos[i].size, pIO)) { + delete [] pos; + return false; + } + + m_list->push_back(pid); + } + + delete [] pos; + + return true; +} + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::Write + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +bool CIccTagProfileSequenceId::Write(CIccIO *pIO) +{ + icTagTypeSignature sig = GetType(); + + if (!pIO) + return false; + + icUInt32Number tagStart = pIO->Tell(); + + if (!pIO->Write32(&sig)) + return false; + + if (!pIO->Write32(&m_nReserved)) + return false; + + icUInt32Number i, count = (icUInt32Number)m_list->size(); + + pIO->Write32(&count); + + icPositionNumber *pos = new icPositionNumber[count]; + if (!pos) + return false; + + icUInt32Number dirpos = pIO->Tell(); + + //Write Unintialized TagDir + for (i=0; iWrite32(&pos[i].offset); + pIO->Write32(&pos[i].size); + } + + CIccProfileIdDescList::iterator j; + + //Write Tags + for (i=0, j=m_list->begin(); j!= m_list->end(); i++, j++) { + pos[i].offset = pIO->Tell(); + + j->Write(pIO); + pos[i].size = pIO->Tell() - pos[i].offset; + pos[i].offset -= tagStart; + + pIO->Align32(); + } + + icUInt32Number endpos = pIO->Tell(); + + pIO->Seek(dirpos, icSeekSet); + + //Write TagDir with offsets and sizes + for (i=0; iWrite32(&pos[i].offset); + pIO->Write32(&pos[i].size); + } + + pIO->Seek(endpos, icSeekSet); + + return true; +} + + +/** + ****************************************************************************** + * Name: CIccTagProfileSequenceId::Validate + * + * Purpose: + * + * Args: + * + * Return: + ******************************************************************************/ +icValidateStatus CIccTagProfileSequenceId::Validate(icTagSignature sig, std::string &sReport, + const CIccProfile* pProfile /*=NULL*/) const +{ + icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile); + + CIccInfo Info; + std::string sSigName = Info.GetSigName(sig); + + CIccProfileIdDescList::iterator i; + + for (i=m_list->begin(); i!=m_list->end(); i++) { + rv = icMaxStatus(rv, i->Validate(sig, sReport, pProfile)); + } + + return rv; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccTagProfileSequenceId::AddProfileDescription +* +* Purpose: +* +* Args: +* CIccProfileIdDesc &profileDesc +* +* Return: +* bool +***************************************************************************** +*/ +bool CIccTagProfileSequenceId::AddProfileDescription(const CIccProfileIdDesc &profileDesc) +{ + m_list->push_back(profileDesc); + + return true; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccTagProfileSequenceId::GetFirst +* +* Purpose: +* +* Args: +* +* Return: +* CIccProfileIdDesc * +***************************************************************************** +*/ +CIccProfileIdDesc *CIccTagProfileSequenceId::GetFirst() +{ + if (m_list->size()) + return &(*(m_list->begin())); + + return NULL; +} + + +/** +**************************************************************************** +* Name: sampleICC::CIccTagProfileSequenceId::GetLast +* +* Purpose: +* +* Args: +* +* Return: +* CIccProfileIdDesc * +***************************************************************************** +*/ +CIccProfileIdDesc *CIccTagProfileSequenceId::GetLast() +{ + if (m_list->size()) + return &(*(m_list->rbegin())); + + return NULL; +} + diff --git a/library/src/main/cpp/icc/IccTagProfSeqId.h b/library/src/main/cpp/icc/IccTagProfSeqId.h new file mode 100644 index 00000000..54277940 --- /dev/null +++ b/library/src/main/cpp/icc/IccTagProfSeqId.h @@ -0,0 +1,157 @@ +/** @file +File: IccTagProfSeqId.h + +Contains: Header for implementation of CIccTagProfSeqId +and supporting classes + +Version: V1 + +Copyright: see ICC Software License +*/ + +/* +* The ICC Software License, Version 0.2 +* +* +* Copyright (c) 2005-2015 The International Color Consortium. All rights +* reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* 3. In the absence of prior written permission, the names "ICC" and "The +* International Color Consortium" must not be used to imply that the +* ICC organization endorses or promotes products derived from this +* software. +* +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR +* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +* ==================================================================== +* +* This software consists of voluntary contributions made by many +* individuals on behalf of the The International Color Consortium. +* +* +* Membership in the ICC is encouraged when this software is used for +* commercial purposes. +* +* +* For more information on The International Color Consortium, please +* see . +* +* +*/ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Jun 3, 2007 +// Initial CIccTagProfSeqId development +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCTAGPROFSEQID_H +#define _ICCTAGPROFSEQID_H + +#include "IccProfile.h" +#include "IccTag.h" +#include +#include + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +class ICCPROFLIB_API CIccProfileIdDesc +{ +public: + CIccProfileIdDesc(); + CIccProfileIdDesc(CIccProfile &profile); + CIccProfileIdDesc(icProfileID id, CIccTagMultiLocalizedUnicode desc); + CIccProfileIdDesc(const CIccProfileIdDesc &pid); + CIccProfileIdDesc &operator=(const CIccProfileIdDesc &pid); + + void Describe(std::string &sDescription); + + bool Read(icUInt32Number size, CIccIO *pIO); + bool Write(CIccIO *pIO); + + icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + CIccTagMultiLocalizedUnicode m_desc; + icProfileID m_profileID; +}; + +typedef std::list CIccProfileIdDescList; + +/** +**************************************************************************** +* Class: CIccTagProfileSequenceId +* +* Purpose: The ProfileSequenceId tag +***************************************************************************** +*/ +class ICCPROFLIB_API CIccTagProfileSequenceId : public CIccTag +{ +public: + CIccTagProfileSequenceId(); + CIccTagProfileSequenceId(const CIccTagProfileSequenceId &lut); + CIccTagProfileSequenceId &operator=(const CIccTagProfileSequenceId &lut); + virtual CIccTag *NewCopy() const { return new CIccTagProfileSequenceId(*this);} + virtual ~CIccTagProfileSequenceId(); + + static CIccTagProfileSequenceId *ParseMem(icUInt8Number *pMem, icUInt32Number size); + + virtual icTagTypeSignature GetType() const { return icSigProfileSequceIdType; } + virtual const icChar *GetClassName() const { return "CIccTagProfileSequenceId"; } + + virtual void Describe(std::string &sDescription); + + virtual bool Read(icUInt32Number size, CIccIO *pIO); + virtual bool Write(CIccIO *pIO); + + virtual icValidateStatus Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile=NULL) const; + + bool AddProfileDescription(CIccProfile &profile) { return AddProfileDescription(CIccProfileIdDesc(profile)); } + bool AddProfileDescription(const CIccProfileIdDesc &profileDesc); + + CIccProfileIdDesc *GetFirst(); + CIccProfileIdDesc *GetLast(); + + CIccProfileIdDescList::iterator begin() { return m_list->begin(); } + CIccProfileIdDescList::iterator end() { return m_list->end(); } + +protected: + void Cleanup(); + + CIccProfileIdDescList *m_list; +}; + + + +//CIccTagProfSeq support +#ifdef USESAMPLEICCNAMESPACE +} +#endif + +#endif //_ICCTAGPROFSEQID_H diff --git a/library/src/main/cpp/icc/IccUtil.cpp b/library/src/main/cpp/icc/IccUtil.cpp new file mode 100644 index 00000000..d6159898 --- /dev/null +++ b/library/src/main/cpp/icc/IccUtil.cpp @@ -0,0 +1,2026 @@ +/* + File: IccUtil.cpp + + Contains: Implementation of utility classes/functions + + Version: V1 + + Copyright: � see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#include "IccIO.h" +#include "IccUtil.h" +#include "IccTagFactory.h" +#include "IccConvertUTF.h" +#include +#include +#include +#include +#include +#include +#include + +#define PI 3.1415926535897932384626433832795 + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +const char *icValidateWarningMsg = "Warning! - "; +const char *icValidateNonCompliantMsg = "NonCompliant! - "; +const char *icValidateCriticalErrorMsg = "Error! - "; + +/** + ****************************************************************************** +* Name: icRoundOffset +* +* Purpose: Adds offset to floating point value for purposes of rounding +* by casting to and integer based value +* +* Args: +* v - value to offset +* +* Return: +* v with offset added - suitable for casting to some form of integer +****************************************************************************** +*/ +double icRoundOffset(double v) +{ + if (v < 0.0) + return v - 0.5; + else + return v + 0.5; +} + + +/** + ****************************************************************************** + * Name: icMaxStatus + * + * Purpose: return worst status + * + * Args: + * s1, s2 + * + * Return: + ****************************************************************************** + */ +icValidateStatus icMaxStatus(icValidateStatus s1, icValidateStatus s2) +{ + if (s1>s2) + return s1; + return s2; +} + +static icInt32Number icHexDigit(icChar digit) +{ + if (digit>='0' && digit<='9') + return digit-'0'; + if (digit>='A' && digit<='F') + return digit-'A'+10; +/* if (digit>='a' && digit<='f') + return digit-'a'+10;*/ + return -1; +} + + +bool icIsSpaceCLR(icColorSpaceSignature sig) +{ + switch(sig) { + case icSig2colorData: + case icSig3colorData: + case icSig4colorData: + case icSig5colorData: + case icSig6colorData: + case icSig7colorData: + case icSig8colorData: + case icSig9colorData: + case icSig10colorData: + case icSig11colorData: + case icSig12colorData: + case icSig13colorData: + case icSig14colorData: + case icSig15colorData: + return true; + + default: + return false; + } + + return false; +} + +void icColorIndexName(icChar *szName, icColorSpaceSignature csSig, + int nIndex, int nColors, const icChar *szUnknown) +{ + icChar szSig[5]; + int i; + + if (csSig!=icSigUnknownData) { + szSig[0] = (icChar)(csSig>>24); + szSig[1] = (icChar)(csSig>>16); + szSig[2] = (icChar)(csSig>>8); + szSig[3] = (icChar)(csSig); + szSig[4] = '\0'; + + for (i=3; i>0; i--) { + if (szSig[i]==' ') + szSig[i]='\0'; + } + if (nColors==1) { + strcpy(szName, szSig); + } + else if ((size_t)nColors == strlen(szSig)) { + sprintf(szName, "%s_%c", szSig, szSig[nIndex]); + } + else { + sprintf(szName, "%s_%d", szSig, nIndex+1); + } + } + else if (nColors==1) { + strcpy(szName, szUnknown); + } + else { + sprintf(szName, "%s_%d", szUnknown, nIndex+1); + } +} + +void icColorValue(icChar *szValue, icFloatNumber nValue, + icColorSpaceSignature csSig, int nIndex, + bool bUseLegacy) +{ + if (csSig==icSigLabData) { + if (!bUseLegacy) { + if (!nIndex || nIndex>2) + sprintf(szValue, "%7.3lf", nValue * 100.0); + else + sprintf(szValue, "%8.3lf", nValue * 255.0 - 128.0); + } + else { + if (!nIndex || nIndex>2) + sprintf(szValue, "%7.3lf", nValue * 100.0 * 65535.0 / 65280.0); + else + sprintf(szValue, "%8.3lf", nValue * 255.0 * 65535.0 / 65280.0 - 128.0); + } + } + else if (csSig==icSigUnknownData) { + sprintf(szValue, "%8.5lf", nValue); + } + else { + sprintf(szValue, "%7.3lf", nValue * 100.0); + } +} + +/** +************************************************************************** +* Name: icMatrixInvert3x3 +* +* Purpose: +* Inversion of a 3x3 matrix using the Adjoint Cofactor and the determinant of +* the 3x3 matrix. +* +* Note: Matrix index positions: +* 0 1 2 +* 3 4 5 +* 6 7 8 +* +* Args: +* M = matrix to invert. +* +* Return: +* true = matrix is invertible and stored back into M, false = matrix is not +* invertible. +************************************************************************** +*/ +bool icMatrixInvert3x3(icFloatNumber *M) +{ + icFloatNumber m48 = M[4]*M[8]; + icFloatNumber m75 = M[7]*M[5]; + icFloatNumber m38 = M[3]*M[8]; + icFloatNumber m65 = M[6]*M[5]; + icFloatNumber m37 = M[3]*M[7]; + icFloatNumber m64 = M[6]*M[4]; + + icFloatNumber det = M[0]*(m48 - m75) - + M[1]*(m38 - m65) + + M[2]*(m37 - m64); + + if (!det) + return false; + + icFloatNumber Co[9]; + + Co[0] = +(m48 - m75); + Co[1] = -(m38 - m65); + Co[2] = +(m37 - m64); + + Co[3] = -(M[1]*M[8] - M[7]*M[2]); + Co[4] = +(M[0]*M[8] - M[6]*M[2]); + Co[5] = -(M[0]*M[7] - M[6]*M[1]); + + Co[6] = +(M[1]*M[5] - M[4]*M[2]); + Co[7] = -(M[0]*M[5] - M[3]*M[2]); + Co[8] = +(M[0]*M[4] - M[3]*M[1]); + + M[0] = Co[0] / det; + M[1] = Co[3] / det; + M[2] = Co[6] / det; + + M[3] = Co[1] / det; + M[4] = Co[4] / det; + M[5] = Co[7] / det; + + M[6] = Co[2] / det; + M[7] = Co[5] / det; + M[8] = Co[8] / det; + + return true; +} + +/** +************************************************************************** +* Name: icMatrixMultiply3x3 +* +* Purpose: +* Multiply two 3x3 matricies resulting in a 3x3 matrix. +* +* Note: Matrix index positions: +* 0 1 2 +* 3 4 5 +* 6 7 8 +* +* Args: +* result = matrix to recieve result. +* l = left matrix to multiply (matrix multiplication is order dependent) +* r = right matrix to multiply (matrix multiplicaiton is order dependent) +* +************************************************************************** +*/ +void icMatrixMultiply3x3(icFloatNumber* result, + const icFloatNumber* l, + const icFloatNumber* r) +{ + const unsigned int e11 = 0; + const unsigned int e12 = 1; + const unsigned int e13 = 2; + const unsigned int e21 = 3; + const unsigned int e22 = 4; + const unsigned int e23 = 5; + const unsigned int e31 = 6; + const unsigned int e32 = 7; + const unsigned int e33 = 8; + result[e11] = l[e11] * r[e11] + l[e12] * r[e21] + l[e13] * r[e31]; + result[e12] = l[e11] * r[e12] + l[e12] * r[e22] + l[e13] * r[e32]; + result[e13] = l[e11] * r[e13] + l[e12] * r[e23] + l[e13] * r[e33]; + result[e21] = l[e21] * r[e11] + l[e22] * r[e21] + l[e23] * r[e31]; + result[e22] = l[e21] * r[e12] + l[e22] * r[e22] + l[e23] * r[e32]; + result[e23] = l[e21] * r[e13] + l[e22] * r[e23] + l[e23] * r[e33]; + result[e31] = l[e31] * r[e11] + l[e32] * r[e21] + l[e33] * r[e31]; + result[e32] = l[e31] * r[e12] + l[e32] * r[e22] + l[e33] * r[e32]; + result[e33] = l[e31] * r[e13] + l[e32] * r[e23] + l[e33] * r[e33]; +} + +/** +************************************************************************** +* Name: icVectorApplyMatrix3x3 +* +* Purpose: +* Applies a 3x3 matrix to a 3 element column vector. +* +* Note: Matrix index positions: +* 0 1 2 +* 3 4 5 +* 6 7 8 +* +* Note: result = m x v +* +* Args: +* result = vector to receive result. +* m = matrix to multiply +* v = vector to apply matrix to +* +************************************************************************** +*/ +void icVectorApplyMatrix3x3(icFloatNumber* result, + const icFloatNumber* m, + const icFloatNumber* v) +{ + const unsigned int e11 = 0; + const unsigned int e12 = 1; + const unsigned int e13 = 2; + const unsigned int e21 = 3; + const unsigned int e22 = 4; + const unsigned int e23 = 5; + const unsigned int e31 = 6; + const unsigned int e32 = 7; + const unsigned int e33 = 8; + result[0] = m[e11] * v[0] + m[e12] * v[1] + m[e13] * v[2]; + result[1] = m[e21] * v[0] + m[e22] * v[1] + m[e23] * v[2]; + result[2] = m[e31] * v[0] + m[e32] * v[1] + m[e33] * v[2]; +} + + +static inline icFloatNumber icSq(icFloatNumber x) +{ + return x*x; +} + + +icFloatNumber icDeltaE(icFloatNumber *lab1, icFloatNumber *lab2) +{ + return sqrt(icSq(lab1[0]-lab2[0]) + icSq(lab1[1]-lab2[1]) + icSq(lab1[2]-lab2[2])); +} + + +icS15Fixed16Number icDtoF(icFloatNumber num) +{ + icS15Fixed16Number rv; + + if (num<-32768.0) + num = -32768.0; + else if (num>32767.0) + num = 32767.0; + + rv = (icS15Fixed16Number)icRoundOffset((double)num*65536.0); + + return rv; +} + +icFloatNumber icFtoD(icS15Fixed16Number num) +{ + icFloatNumber rv = (icFloatNumber)((double)num / 65536.0); + + return rv; +} + +icU16Fixed16Number icDtoUF(icFloatNumber num) +{ + icU16Fixed16Number rv; + + if (num<0) + num = 0; + else if (num>65535.0) + num = 65535.0; + + rv = (icU16Fixed16Number)icRoundOffset((double)num*65536.0); + + return rv; +} + +icFloatNumber icUFtoD(icU16Fixed16Number num) +{ + icFloatNumber rv = (icFloatNumber)((double)num / 65536.0); + + return rv; +} + +icU1Fixed15Number icDtoUSF(icFloatNumber num) +{ + icU1Fixed15Number rv; + + if (num<0) + num = 0; + else if (num>65535.0/32768.0) + num = 65535.0/32768.0; + + rv = (icU1Fixed15Number)icRoundOffset(num*32768.0); + + return rv; +} + +icFloatNumber icUSFtoD(icU1Fixed15Number num) +{ + icFloatNumber rv = (icFloatNumber)((icFloatNumber)num / 32768.0); + + return rv; +} + +icU8Fixed8Number icDtoUCF(icFloatNumber num) +{ + icU8Fixed8Number rv; + + if (num<0) + num = 0; + else if (num>255.0) + num = 255.0; + + rv = (icU8Fixed8Number)icRoundOffset(num*256.0); + + return rv; +} + +icFloatNumber icUCFtoD(icU8Fixed8Number num) +{ + icFloatNumber rv = (icFloatNumber)((icFloatNumber)num / 256.0); + + return rv; +} + +icUInt8Number icFtoU8(icFloatNumber num) +{ + icUInt8Number rv; + + if (num<0) + num = 0; + else if (num>1.0) + num = 1.0; + + rv = (icUInt8Number)icRoundOffset(num*255.0); + + return rv; +} + +icFloatNumber icU8toF(icUInt8Number num) +{ + icFloatNumber rv = (icFloatNumber)((icFloatNumber)num / 255.0); + + return rv; +} + +icUInt16Number icFtoU16(icFloatNumber num) +{ + icUInt16Number rv; + + if (num<0) + num = 0; + else if (num>1.0) + num = 1.0; + + rv = (icUInt16Number)icRoundOffset(num*65535.0); + + return rv; +} + +icFloatNumber icU16toF(icUInt16Number num) +{ + icFloatNumber rv = (icFloatNumber)((icFloatNumber)num / 65535.0); + + return rv; +} + +icUInt8Number icABtoU8(icFloatNumber num) +{ + icFloatNumber v = num + 128.0f; + if (v<0) + v=0; + else if (v>255) + v=255; + + return (icUInt8Number)(v + 0.5); +} + +icFloatNumber icU8toAB(icUInt8Number num) +{ + return (icFloatNumber)num - 128.0f; +} + +icFloatNumber icD50XYZ[3] = { 0.9642f, 1.0000f, 0.8249f }; +icFloatNumber icD50XYZxx[3] = { 96.42f, 100.00f, 82.49f }; + +void icNormXyz(icFloatNumber *XYZ, icFloatNumber *WhiteXYZ) +{ + if (!WhiteXYZ) + WhiteXYZ = icD50XYZ; + + XYZ[0] = XYZ[0] / WhiteXYZ[0]; + XYZ[1] = XYZ[1] / WhiteXYZ[1]; + XYZ[2] = XYZ[2] / WhiteXYZ[2]; +} + +void icDeNormXyz(icFloatNumber *XYZ, icFloatNumber *WhiteXYZ) +{ + if (!WhiteXYZ) + WhiteXYZ = icD50XYZ; + + XYZ[0] = XYZ[0] * WhiteXYZ[0]; + XYZ[1] = XYZ[1] * WhiteXYZ[1]; + XYZ[2] = XYZ[2] * WhiteXYZ[2]; +} + +static icFloatNumber cubeth(icFloatNumber v) +{ + if (v> 0.008856) { + return (icFloatNumber)ICC_CBRTF(v); + } + else { + return (icFloatNumber)(7.787037037037037037037037037037*v + 16.0/116.0); + } +} + +static icFloatNumber icubeth(icFloatNumber v) +{ + if (v > 0.20689303448275862068965517241379) + return v*v*v; + else +#ifndef SAMPLEICC_NOCLIPLABTOXYZ + if (v>16.0/116.0) +#endif + return (icFloatNumber)((v - 16.0 / 116.0) / 7.787037037037037037037037037037); +#ifndef SAMPLEICC_NOCLIPLABTOXYZ + else + return 0.0; +#endif +} + +void icLabtoXYZ(icFloatNumber *XYZ, icFloatNumber *Lab /*=NULL*/, icFloatNumber *WhiteXYZ /*=NULL*/) +{ + if (!Lab) + Lab = XYZ; + + if (!WhiteXYZ) + WhiteXYZ = icD50XYZ; + + icFloatNumber fy = (icFloatNumber)((Lab[0] + 16.0) / 116.0); + + XYZ[0] = icubeth((icFloatNumber)(Lab[1]/500.0 + fy)) * WhiteXYZ[0]; + XYZ[1] = icubeth(fy) * WhiteXYZ[1]; + XYZ[2] = icubeth((icFloatNumber)(fy - Lab[2]/200.0)) * WhiteXYZ[2]; + +} + +void icXYZtoLab(icFloatNumber *Lab, icFloatNumber *XYZ /*=NULL*/, icFloatNumber *WhiteXYZ /*=NULL*/) +{ + icFloatNumber Xn, Yn, Zn; + + if (!XYZ) + XYZ = Lab; + + if (!WhiteXYZ) + WhiteXYZ = icD50XYZ; + + Xn = cubeth(XYZ[0] / WhiteXYZ[0]); + Yn = cubeth(XYZ[1] / WhiteXYZ[1]); + Zn = cubeth(XYZ[2] / WhiteXYZ[2]); + + Lab[0] = (icFloatNumber)(116.0 * Yn - 16.0); + Lab[1] = (icFloatNumber)(500.0 * (Xn - Yn)); + Lab[2] = (icFloatNumber)(200.0 * (Yn - Zn)); + +} + +void icLch2Lab(icFloatNumber *Lab, icFloatNumber *Lch /*=NULL*/) +{ + if (!Lch) { + Lch = Lab; + } + else + Lab[0] = Lch[0]; + + icFloatNumber a = (icFloatNumber)(Lch[1] * cos(Lch[2] * PI / 180.0)); + icFloatNumber b = (icFloatNumber)(Lch[1] * sin(Lch[2] * PI / 180.0)); + + Lab[1] = a; + Lab[2] = b; +} + +void icLab2Lch(icFloatNumber *Lch, icFloatNumber *Lab /*=NULL*/) +{ + if (!Lab) { + Lab = Lch; + } + else + Lch[0] = Lab[0]; + + icFloatNumber c = sqrt(Lab[1]*Lab[1] + Lab[2]*Lab[2]); + icFloatNumber h = (icFloatNumber)(atan2(Lab[2], Lab[1]) * 180.0 / PI); + while (h<0.0) + h+=360.0; + + Lch[1] = c; + Lch[2] = h; +} + +icFloatNumber icMin(icFloatNumber v1, icFloatNumber v2) +{ + return( v1 < v2 ? v1 : v2 ); +} + +icFloatNumber icMax(icFloatNumber v1, icFloatNumber v2) +{ + return( v1 > v2 ? v1 : v2 ); +} + +icUInt32Number icIntMin(icUInt32Number v1, icUInt32Number v2) +{ + return( v1 < v2 ? v1 : v2 ); +} + +icUInt32Number icIntMax(icUInt32Number v1, icUInt32Number v2) +{ + return( v1 > v2 ? v1 : v2 ); +} + + +void icLabFromPcs(icFloatNumber *Lab) +{ + Lab[0] *= 100.0; + Lab[1] = (icFloatNumber)(Lab[1]*255.0 - 128.0); + Lab[2] = (icFloatNumber)(Lab[2]*255.0 - 128.0); +} + + +void icLabToPcs(icFloatNumber *Lab) +{ + Lab[0] /= 100.0; + Lab[1] = (icFloatNumber)((Lab[1] + 128.0) / 255.0); + Lab[2] = (icFloatNumber)((Lab[2] + 128.0) / 255.0); +} + +void icXyzFromPcs(icFloatNumber *XYZ) +{ + XYZ[0] = (icFloatNumber)(XYZ[0] * 65535.0 / 32768.0); + XYZ[1] = (icFloatNumber)(XYZ[1] * 65535.0 / 32768.0); + XYZ[2] = (icFloatNumber)(XYZ[2] * 65535.0 / 32768.0); +} + +void icXyzToPcs(icFloatNumber *XYZ) +{ + XYZ[0] = (icFloatNumber)(XYZ[0] * 32768.0 / 65535.0); + XYZ[1] = (icFloatNumber)(XYZ[1] * 32768.0 / 65535.0); + XYZ[2] = (icFloatNumber)(XYZ[2] * 32768.0 / 65535.0); +} + + +#define DUMPBYTESPERLINE 16 + +void icMemDump(std::string &sDump, void *pBuf, icUInt32Number nNum) +{ + icUInt8Number *pData = (icUInt8Number *)pBuf; + icChar buf[80], num[10]; + + icInt32Number i, j; + icUInt8Number c; + + icInt32Number lines = (nNum + DUMPBYTESPERLINE - 1)/DUMPBYTESPERLINE; + sDump.reserve(sDump.size() + lines*79); + + for (i=0; i<(icInt32Number)nNum; i++, pData++) { + j=i%DUMPBYTESPERLINE; + if (!j) { + if (i) { + sDump += (const icChar*)buf; + } + memset(buf, ' ', 76); + buf[76] = '\r'; + buf[77] = '\n'; + buf[78] = '\0'; + sprintf(num, "%08X:", i); + strncpy(buf, num, 9); + } + + sprintf(num, "%02X", *pData); + strncpy(buf+10+j*3, num, 2); + + c=*pData; + if (!isprint(c)) + c='.'; + buf[10+16*3 + 1 + j] = c; + } + sDump += buf; +} + +void icMatrixDump(std::string &sDump, icS15Fixed16Number *pMatrix) +{ + icChar buf[128]; + + sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n", icFtoD(pMatrix[0]), icFtoD(pMatrix[1]), icFtoD(pMatrix[2])); + sDump += buf; + sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n", icFtoD(pMatrix[3]), icFtoD(pMatrix[4]), icFtoD(pMatrix[5])); + sDump += buf; + sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n", icFtoD(pMatrix[6]), icFtoD(pMatrix[7]), icFtoD(pMatrix[8])); + sDump += buf; +} + +const icChar *icGetSig(icChar *pBuf, icUInt32Number nSig, bool bGetHexVal) +{ + int i; + icUInt32Number sig=nSig; + icUInt8Number c; + + if (!nSig) { + strcpy(pBuf, "NULL"); + return pBuf; + } + + pBuf[0] = '\''; + for (i=1; i<5; i++) { + c=(icUInt8Number)(sig>>24); + if (!isprint(c)) + c='?'; + pBuf[i]=c; + sig <<=8; + } + + if (bGetHexVal) + sprintf(pBuf+5, "' = %08X", nSig); + else + sprintf(pBuf+5, "'"); + + return pBuf; +} + +const icChar *icGetSigStr(icChar *pBuf, icUInt32Number nSig) +{ + int i, j=-1; + icUInt32Number sig=nSig; + icUInt8Number c; + bool bGetHexVal = false; + + for (i=0; i<4; i++) { + c=(icUInt8Number)(sig>>24); + if (!c) { + j=i; + } + else if (j!=-1) { + bGetHexVal = true; + } + else if (!isprint(c)) { + c='?'; + bGetHexVal = true; + } + pBuf[i]=c; + sig <<=8; + } + + if (bGetHexVal) + sprintf(pBuf, "%08Xh", nSig); + else + pBuf[4] = '\0'; + + return pBuf; +} + +icUInt32Number icGetSigVal(const icChar *pBuf) +{ + switch(strlen(pBuf)) { + case 0: + return 0; + + case 1: + return (((unsigned long)pBuf[0])<<24) + + 0x202020; + + case 2: + return (((unsigned long)pBuf[0])<<24) + + (((unsigned long)pBuf[1])<<16) + + 0x2020; + + case 3: + return (((unsigned long)pBuf[0])<<24) + + (((unsigned long)pBuf[1])<<16) + + (((unsigned long)pBuf[2])<<8) + + 0x20; + + case 4: + default: + return (((unsigned long)pBuf[0])<<24) + + (((unsigned long)pBuf[1])<<16) + + (((unsigned long)pBuf[2])<<8) + + (((unsigned long)pBuf[3])); + + case 9: + icUInt32Number v; + sscanf(pBuf, "%x", &v); + return v; + } +} + + +icUInt32Number icGetSpaceSamples(icColorSpaceSignature sig) +{ + switch(sig) { + case icSigGrayData: + case icSigGamutData: + return 1; + + case icSig2colorData: + return 2; + + case icSigXYZData: + case icSigLabData: + case icSigLuvData: + case icSigYCbCrData: + case icSigYxyData: + case icSigRgbData: + case icSigHsvData: + case icSigHlsData: + case icSigCmyData: + case icSig3colorData: + case icSigDevLabData: + case icSigDevXYZData: + return 3; + + case icSigCmykData: + case icSig4colorData: + return 4; + + case icSig5colorData: + return 5; + + case icSig6colorData: + return 6; + + case icSig7colorData: + return 7; + + case icSig8colorData: + return 8; + + case icSig9colorData: + return 9; + + case icSig10colorData: + return 10; + + case icSig11colorData: + return 11; + + case icSig12colorData: + return 12; + + case icSig13colorData: + return 13; + + case icSig14colorData: + return 14; + + case icSig15colorData: + return 15; + + case icSigNamedData: + default: + { + //check for non-ICC compliant 'MCHx' case provided by littlecms + if ((sig&0xffffff00)==0x4d434800) { + int d0=icHexDigit(sig&0xff); + if (d0>0) + return d0; + } + + } + return 0; + } +} + +const icChar *CIccInfo::GetUnknownName(icUInt32Number val) +{ + icChar buf[24]; + if (!val) + return "Unknown"; + + sprintf(m_szStr, "Unknown %s", icGetSig(buf, val)); + + return m_szStr; +} + +const icChar *CIccInfo::GetVersionName(icUInt32Number val) +{ + icFloatNumber ver = (icFloatNumber)(((val>>28)&0xf)*10.0 + ((val>>24)&0xf) + + ((val>>20)&0xf)/10.0 + ((val>>16)&0xf)/100.0); + + sprintf(m_szStr, "%.2lf", ver); + + return m_szStr; +} + +const icChar *CIccInfo::GetDeviceAttrName(icUInt64Number val) +{ + if (val & icTransparency) + strcpy(m_szStr, "Transparency"); + else + strcpy(m_szStr, "Reflective"); + + int l=(int)strlen(m_szStr); + + if (val & icMatte) + strcpy(m_szStr+l, " | Matte"); + else + strcpy(m_szStr+l, " | Glossy"); + + return m_szStr; +} + +const icChar *CIccInfo::GetProfileFlagsName(icUInt32Number val) +{ + if (val & icEmbeddedProfileTrue) + strcpy(m_szStr, "EmbeddedProfileTrue"); + else + strcpy(m_szStr, "EmbeddedProfileFalse"); + + int l=(int)strlen(m_szStr); + + if (val & icUseWithEmbeddedDataOnly) + strcpy(m_szStr+l, " | UseWithEmbeddedDataOnly"); + else + strcpy(m_szStr+l, " | UseAnywhere"); + + return m_szStr; +} + +const icChar *CIccInfo::GetTagSigName(icTagSignature sig) +{ + const icChar *rv = CIccTagCreator::GetTagSigName(sig); + if (rv) { + return rv; + } + return GetUnknownName(sig); +} + +const icChar *CIccInfo::GetTechnologySigName(icTechnologySignature sig) +{ + switch(sig) { + case icSigDigitalCamera: + return "DigitalCamera"; + + case icSigFilmScanner: + return "FilmScanner"; + + case icSigReflectiveScanner: + return "ReflectiveScanner"; + + case icSigInkJetPrinter: + return "InkJetPrinter"; + + case icSigThermalWaxPrinter: + return "ThermalWaxPrinter"; + + case icSigElectrophotographicPrinter: + return "ElectrophotographicPrinter"; + + case icSigElectrostaticPrinter: + return "ElectrostaticPrinter"; + + case icSigDyeSublimationPrinter: + return "DyeSublimationPrinter"; + + case icSigPhotographicPaperPrinter: + return "PhotographicPaperPrinter"; + + case icSigFilmWriter: + return "FilmWriter"; + + case icSigVideoMonitor: + return "VideoMonitor"; + + case icSigVideoCamera: + return "VideoCamera"; + + case icSigProjectionTelevision: + return "ProjectionTelevision"; + + case icSigCRTDisplay: + return "CRTDisplay"; + + case icSigPMDisplay: + return "PMDisplay"; + + case icSigAMDisplay: + return "AMDisplay"; + + case icSigPhotoCD: + return "PhotoCD"; + + case icSigPhotoImageSetter: + return "PhotoImageSetter"; + + case icSigGravure: + return "Gravure"; + + case icSigOffsetLithography: + return "OffsetLithography"; + + case icSigSilkscreen: + return "Silkscreen"; + + case icSigFlexography: + return "Flexography"; + + default: + return GetUnknownName(sig); + } +} + +const icChar *CIccInfo::GetTagTypeSigName(icTagTypeSignature sig) +{ + const icChar *rv = CIccTagCreator::GetTagTypeSigName(sig); + if (rv) { + return rv; + } + + return GetUnknownName(sig); +} + + +const icChar *CIccInfo::GetColorSpaceSigName(icColorSpaceSignature sig) +{ + switch (sig) { + case icSigXYZData: + case icSigDevXYZData: + return "XYZData"; + + case icSigLabData: + case icSigDevLabData: + return "LabData"; + + case icSigLuvData: + return "LuvData"; + + case icSigYCbCrData: + return "YCbCrData"; + + case icSigYxyData: + return "YxyData"; + + case icSigRgbData: + return "RgbData"; + + case icSigGrayData: + return "GrayData"; + + case icSigHsvData: + return "HsvData"; + + case icSigHlsData: + return "HlsData"; + + case icSigCmykData: + return "CmykData"; + + case icSigCmyData: + return "CmyData"; + + + case icSigMCH1Data: + return "MCH1Data/1colorData"; + + case icSigMCH2Data: + return "MCH2Data/2colorData"; + + case icSigMCH3Data: + return "MCH3Data/3colorData"; + + case icSigMCH4Data: + return "MCH4Data/4colorData"; + + case icSigMCH5Data: + return "MCH5Data/5colorData"; + + case icSigMCH6Data: + return "MCH6Data/6colorData"; + + case icSigMCH7Data: + return "MCH7Data/7colorData"; + + case icSigMCH8Data: + return "MCH8Data/8colorData"; + + case icSigMCH9Data: + return "MCH9Data/9colorData"; + + case icSigMCHAData: + return "MCHAData/10colorData"; + + case icSigMCHBData: + return "MCHBData/11colorData"; + + case icSigMCHCData: + return "MCHCData/12colorData"; + + case icSigMCHDData: + return "MCHDData/13colorData"; + + case icSigMCHEData: + return "MCHEData/14colorData"; + + case icSigMCHFData: + return "MCHFData/15colorData"; + + case icSigGamutData: + return "GamutData"; + + case icSigNamedData: + return "NamedData"; + + default: + return GetUnknownName(sig); + } +} + +const icChar *CIccInfo::GetProfileClassSigName(icProfileClassSignature sig) +{ + switch (sig) { + case icSigInputClass: + return "InputClass"; + + case icSigDisplayClass: + return "DisplayClass"; + + case icSigOutputClass: + return "OutputClass"; + + case icSigLinkClass: + return "LinkClass"; + + case icSigAbstractClass: + return "AbstractClass"; + + case icSigColorSpaceClass: + return "ColorSpaceClass"; + + case icSigNamedColorClass: + return "NamedColorClass"; + + default: + return GetUnknownName(sig); + } +} + +const icChar *CIccInfo::GetPlatformSigName(icPlatformSignature sig) +{ + switch (sig) { + case icSigMacintosh: + return "Macintosh"; + + case icSigMicrosoft: + return "Microsoft"; + + case icSigSolaris: + return "Solaris"; + + case icSigSGI: + return "SGI"; + + case icSigTaligent: + return "Taligent"; + + case icSigUnkownPlatform: + return "Unknown"; + + default: + return GetUnknownName(sig); + } +} + + +//The following signatures come from the signature registry +//Return the Description (minus CMM). +const icChar *CIccInfo::GetCmmSigName(icCmmSignature sig) +{ + switch (sig) { + case icSigAdobe: + return "Adobe"; + + case icSigApple: + return "Apple"; + + case icSigColorGear: + return "ColorGear"; + + case icSigColorGearLite: + return "ColorGear Lite"; + + case icSigFujiFilm: + return "Fuji Film"; + + case icSigHarlequinRIP: + return "Harlequin RIP"; + + case icSigArgyllCMS: + return "Argyll CMS"; + + case icSigLogoSync: + return "LogoSync"; + + case icSigHeidelberg: + return "Heidelberg"; + + case icSigLittleCMS: + return "Little CMS"; + + case icSigKodak: + return "Kodak"; + + case icSigKonicaMinolta: + return "Konica Minolta"; + + case icSigMutoh: + return "Mutoh"; + + case icSigSampleICC: + return "SampleIcc"; + + case icSigTheImagingFactory: + return "the imaging factory"; + + default: + return GetUnknownName(sig); + } +} + + +const icChar *CIccInfo::GetReferenceMediumGamutSigNameName(icReferenceMediumGamutSignature sig) +{ + switch (sig) { + case icSigPerceptualReferenceMediumGamut: + return "perceptualReferenceMediumGamut"; + + default: + return GetUnknownName(sig); + } +} + + +const icChar *CIccInfo::GetColorimetricIntentImageStateName(icColorimetricIntentImageStateSignature sig) +{ + switch (sig) { + case icSigSceneColorimetryEstimates: + return "Scene Colorimetry Estimates"; + + case icSigSceneAppearanceEstimates: + return "Scene Appearance Estimates"; + + case icSigFocalPlaneColorimetryEstimates: + return "Focal Plane Colorimetry Estimates"; + + case icSigReflectionHardcopyOriginalColorimetry: + return "Reflection Hardcopy Original Colorimetry"; + + case icSigReflectionPrintOutputColorimetry: + return "Reflection Print Output Colorimetry"; + + default: + return GetUnknownName(sig); + } +} + + +const icChar *CIccInfo::GetSigName(icUInt32Number sig) +{ + const icChar *rv; + + rv = GetTagSigName((icTagSignature)sig); + if (rv != m_szStr) + return rv; + + rv = GetTechnologySigName((icTechnologySignature)sig); + if (rv != m_szStr) + return rv; + + rv = GetTagTypeSigName((icTagTypeSignature)sig); + if (rv != m_szStr) + return rv; + + rv = GetColorSpaceSigName((icColorSpaceSignature)sig); + if (rv != m_szStr) + return rv; + + rv = GetProfileClassSigName((icProfileClassSignature)sig); + if (rv != m_szStr) + return rv; + + rv = GetPlatformSigName((icPlatformSignature)sig); + if (rv != m_szStr) + return rv; + + rv = GetReferenceMediumGamutSigNameName((icReferenceMediumGamutSignature)sig); + if (rv != m_szStr) + return rv; + + return GetColorimetricIntentImageStateName((icColorimetricIntentImageStateSignature)sig); +} + + +const icChar *CIccInfo::GetMeasurementFlareName(icMeasurementFlare val) +{ + switch (val) { + case icFlare0: + return "Flare 0"; + + case icFlare100: + return "Flare 100"; + + case icMaxEnumFlare: + return "Max Flare"; + + default: + sprintf(m_szStr, "Unknown Flare '%d'", (int)val); + return m_szStr; + } +} + +const icChar *CIccInfo::GetMeasurementGeometryName(icMeasurementGeometry val) +{ + switch (val) { + case icGeometryUnknown: + return "Geometry Unknown"; + + case icGeometry045or450: + return "Geometry 0-45 or 45-0"; + + case icGeometry0dord0: + return "Geometry 0-d or d-0"; + + case icMaxEnumGeometry: + return "Max Geometry"; + + default: + sprintf(m_szStr, "Unknown Geometry '%d'", (int)val); + return m_szStr; + } +} + +const icChar *CIccInfo::GetRenderingIntentName(icRenderingIntent val) +{ + switch (val) { + case icPerceptual: + return "Perceptual"; + + case icRelativeColorimetric: + return "Relative Colorimetric"; + + case icSaturation: + return "Saturation"; + + case icAbsoluteColorimetric: + return "Absolute Colorimetric"; + + default: + sprintf(m_szStr, "Unknown Intent '%d", val); + return m_szStr; + } +} + +const icChar *CIccInfo::GetSpotShapeName(icSpotShape val) +{ + switch (val) { + case icSpotShapeUnknown: + return "Spot Shape Unknown"; + + case icSpotShapePrinterDefault: + return "Spot Shape Printer Default"; + + case icSpotShapeRound: + return "Spot Shape Round"; + + case icSpotShapeDiamond: + return "Spot Shape Diamond"; + + case icSpotShapeEllipse: + return "Spot Shape Ellipse"; + + case icSpotShapeLine: + return "Spot Shape Line"; + + case icSpotShapeSquare: + return "Spot Shape Square"; + + case icSpotShapeCross: + return "Spot Shape Cross"; + + default: + sprintf(m_szStr, "Unknown Spot Shape '%d", val); + return m_szStr; + } +} + +const icChar *CIccInfo::GetStandardObserverName(icStandardObserver val) +{ + switch (val) { + case icStdObsUnknown: + return "Unknown observer"; + + case icStdObs1931TwoDegrees: + return "CIE 1931 (two degree) standard observer"; + + case icStdObs1964TenDegrees: + return "CIE 964 (ten degree) standard observer"; + + default: + sprintf(m_szStr, "Unknown Observer '%d", val); + return m_szStr; + } +} + +const icChar *CIccInfo::GetIlluminantName(icIlluminant val) +{ + switch (val) { + case icIlluminantUnknown: + return "Illuminant Unknown"; + + case icIlluminantD50: + return "Illuminant D50"; + + case icIlluminantD65: + return "Illuminant D65"; + + case icIlluminantD93: + return "Illuminant D93"; + + case icIlluminantF2: + return "Illuminant F2"; + + case icIlluminantD55: + return "Illuminant D55"; + + case icIlluminantA: + return "Illuminant A"; + + case icIlluminantEquiPowerE: + return "Illuminant EquiPowerE"; + + case icIlluminantF8: + return "Illuminant F8"; + + default: + sprintf(m_szStr, "Unknown Illuminant '%d", val); + return m_szStr; + } +} + +const icChar *CIccInfo::GetMeasurementUnit(icSignature sig) +{ + switch (sig) { + case icSigStatusA: + return "Status A"; + + case icSigStatusE: + return "Status E"; + + case icSigStatusI: + return "Status I"; + + case icSigStatusT: + return "Status T"; + + case icSigStatusM: + return "Status M"; + + case icSigDN: + return "DIN with no polarizing filter"; + + case icSigDNP: + return "DIN with polarizing filter"; + + case icSigDNN: + return "Narrow band DIN with no polarizing filter"; + + case icSigDNNP: + return "Narrow band DIN with polarizing filter"; + + default: + { + char buf[10]; + buf[0] = (char)(sig>>24); + buf[1] = (char)(sig>>16); + buf[2] = (char)(sig>>8); + buf[3] = (char)(sig); + buf[4] = '\0'; + + sprintf(m_szStr, "Unknown Measurement Type '%s'", buf); + return m_szStr; + } + } +} + + +const icChar *CIccInfo::GetProfileID(icProfileID *profileID) +{ + char *ptr = m_szStr; + int i; + + for (i=0; i<16; i++, ptr+=2) { + sprintf(ptr, "%02x", profileID->ID8[i]); + } + + return m_szStr; +} + +bool CIccInfo::IsProfileIDCalculated(icProfileID *profileID) +{ + int i; + + for (i=0; i<16; i++) { + if (profileID->ID8[i]) + break; + } + + return i<16; +} + +const icChar *CIccInfo::GetColorantEncoding(icColorantEncoding colorant) +{ + switch(colorant) { + case icColorantITU: + return "ITU-R BT.709"; + + case icColorantSMPTE: + return "SMPTE RP145-1994"; + + case icColorantEBU: + return "EBU Tech.3213-E"; + + case icColorantP22: + return "P22"; + + default: + return "Customized Encoding"; + } +} + +icValidateStatus CIccInfo::CheckData(std::string &sReport, const icXYZNumber &XYZ) +{ + icValidateStatus rv = icValidateOK; + + if (XYZ.X < 0) { + sReport += icValidateNonCompliantMsg; + sReport += " - XYZNumber: Negative X value!\r\n"; + rv = icValidateNonCompliant; + } + + if (XYZ.Y < 0) { + sReport += icValidateNonCompliantMsg; + sReport += " - XYZNumber: Negative Y value!\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + if (XYZ.Z < 0) { + sReport += icValidateNonCompliantMsg; + sReport += " - XYZNumber: Negative Z value!\r\n"; + rv = icMaxStatus(rv, icValidateNonCompliant); + } + + return rv; +} + +icValidateStatus CIccInfo::CheckData(std::string &sReport, const icDateTimeNumber &dateTime) +{ + icValidateStatus rv = icValidateOK; + + struct tm *newtime; + time_t long_time; + + time( &long_time ); /* Get time as long integer. */ + newtime = localtime( &long_time ); + + icChar buf[128]; + if (dateTime.year<1992) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid year!\r\n",dateTime.year); + sReport += buf; + rv = icValidateWarning; + } + + int year = newtime->tm_year+1900; + if (newtime->tm_mon==11 && newtime->tm_mday==31) { + if (dateTime.year>(year+1)) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid year!\r\n",dateTime.year); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + } + else { + if (dateTime.year>year) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid year!\r\n",dateTime.year); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + } + + if (dateTime.month<1 || dateTime.month>12) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid month!\r\n",dateTime.month); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + if (dateTime.day<1 || dateTime.day>31) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid day!\r\n",dateTime.day); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + if (dateTime.month==2) { + if (dateTime.day>29) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid day for February!\r\n",dateTime.day); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + if (dateTime.day==29) { + if ((dateTime.year%4)!=0) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid day for February, year is not a leap year(%u)!\r\n",dateTime.day, dateTime.year); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + } + } + + if (dateTime.hours>23) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid hour!\r\n",dateTime.hours); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + if (dateTime.minutes>59) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid minutes!\r\n",dateTime.minutes); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + if (dateTime.seconds>59) { + sReport += icValidateWarningMsg; + sprintf(buf," - %u: Invalid seconds!\r\n",dateTime.hours); + sReport += buf; + rv = icMaxStatus(rv, icValidateWarning); + } + + return rv; +} + +bool CIccInfo::IsValidSpace(icColorSpaceSignature sig) +{ + bool rv = true; + + switch(sig) { + case icSigXYZData: + case icSigLabData: + case icSigLuvData: + case icSigYCbCrData: + case icSigYxyData: + case icSigRgbData: + case icSigGrayData: + case icSigHsvData: + case icSigHlsData: + case icSigCmykData: + case icSigCmyData: + case icSigMCH1Data: + case icSigNamedData: + case icSigGamutData: + case icSig2colorData: + case icSig3colorData: + case icSig4colorData: + case icSig5colorData: + case icSig6colorData: + case icSig7colorData: + case icSig8colorData: + case icSig9colorData: + case icSig10colorData: + case icSig11colorData: + case icSig12colorData: + case icSig13colorData: + case icSig14colorData: + case icSig15colorData: + break; + + default: + rv = false; + } + + return rv; +} + +CIccUTF16String::CIccUTF16String() +{ + m_alloc=64; + m_len = 0; + m_str = (icUInt16Number*)calloc(m_alloc, sizeof(icUInt16Number)); +} + +CIccUTF16String::CIccUTF16String(const icUInt16Number *uzStr) +{ + m_len = WStrlen(uzStr); + m_alloc = AllocSize(m_len+1); + + m_str = (icUInt16Number *)malloc(m_alloc*sizeof(icUInt16Number)); + memcpy(m_str, uzStr, (m_len+1)*sizeof(icUInt16Number)); +} + +CIccUTF16String::CIccUTF16String(const char *szStr) +{ + size_t sizeSrc = strlen(szStr); + + if (sizeSrc) { + m_alloc = AllocSize(sizeSrc*2+2); + m_str = (UTF16 *)calloc(m_alloc, sizeof(icUInt16Number)); //overallocate to allow for up to 4 bytes per character + UTF16 *szDest = m_str; + icConvertUTF8toUTF16((const UTF8 **)&szStr, (const UTF8 *)&szStr[sizeSrc], &szDest, &szDest[m_alloc], lenientConversion); + if (m_str[0]==0xfeff) { + size_t i; + for (i=1; m_str[i]; i++) + m_str[i-1] = m_str[i]; + m_str[i-1] = 0; + } + m_len = WStrlen(m_str); + } + else { + m_alloc = 64; + m_len = 0; + m_str = (icUInt16Number*)calloc(m_alloc, sizeof(icUInt16Number)); + } +} + +CIccUTF16String::CIccUTF16String(const CIccUTF16String &str) +{ + m_alloc = str.m_alloc; + m_len = str.m_len; + m_str = (icUInt16Number*)malloc(m_alloc*sizeof(icUInt16Number)); + + memcpy(m_str, str.m_str, (m_alloc)*sizeof(icUInt16Number)); +} + +CIccUTF16String::~CIccUTF16String() +{ + free(m_str); +} + +void CIccUTF16String::Clear() +{ + m_len = 0; + m_str[0] = 0; +} + +void CIccUTF16String::Resize(size_t len) +{ + if (len>m_alloc) { + size_t nAlloc = AllocSize(len+1); + + m_str = (icUInt16Number*)realloc(m_str, nAlloc*sizeof(icUInt16Number)); + m_alloc = nAlloc; + } + + if (len>m_len) { + memset(&m_str[m_len], 0x0020, (len-m_len)*sizeof(icUInt16Number)); + } + m_len = len; + m_str[m_len] = 0; +} + +size_t CIccUTF16String::WStrlen(const icUInt16Number *uzStr) +{ + size_t n=0; + while(uzStr[n]) n++; + + return n; +} + +CIccUTF16String& CIccUTF16String::operator=(const CIccUTF16String &wstr) +{ + if (m_alloc<=wstr.m_alloc) { + m_str = (icUInt16Number*)realloc(m_str, wstr.m_alloc*sizeof(icUInt16Number)); + m_alloc = wstr.m_alloc; + } + m_len = wstr.m_len; + + memcpy(m_str, wstr.m_str, (m_len+1)*sizeof(icUInt16Number)); + + return *this; +} + +CIccUTF16String& CIccUTF16String::operator=(const char *szStr) +{ + FromUtf8(szStr, 0); + + return *this; +} + +CIccUTF16String& CIccUTF16String::operator=(const icUInt16Number *uzStr) +{ + size_t n = WStrlen(uzStr); + size_t nAlloc = AllocSize(n+1); + + if (m_alloc<=nAlloc) { + m_str = (icUInt16Number*)realloc(m_str, nAlloc*sizeof(icUInt16Number)); + m_alloc =nAlloc; + } + m_len = n; + + memcpy(m_str, uzStr, (m_len+1)*sizeof(icUInt16Number)); + + return *this; +} + +bool CIccUTF16String::operator==(const CIccUTF16String &str) const +{ + if (str.m_len != m_len) + return false; + + size_t i; + + for (i=0; i. + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Initial implementation by Max Derhak 5-15-2003 +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCUTIL_H +#define _ICCUTIL_H + +#include "IccDefs.h" +#include "IccProfLibConf.h" +#include + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +double ICCPROFLIB_API icRoundOffset(double v); + +icValidateStatus ICCPROFLIB_API icMaxStatus(icValidateStatus s1, icValidateStatus s2); +bool ICCPROFLIB_API icIsSpaceCLR(icColorSpaceSignature sig); + +void ICCPROFLIB_API icColorIndexName(icChar *szName, icColorSpaceSignature csSig, + int nIndex, int nColors, const icChar *szUnknown); +void ICCPROFLIB_API icColorValue(icChar *szValue, icFloatNumber nValue, + icColorSpaceSignature csSig, int nIndex, bool bUseLegacy=false); + +bool ICCPROFLIB_API icMatrixInvert3x3(icFloatNumber *matrix); +void ICCPROFLIB_API icMatrixMultiply3x3(icFloatNumber *result, + const icFloatNumber *l, + const icFloatNumber *r); +void ICCPROFLIB_API icVectorApplyMatrix3x3(icFloatNumber *result, + const icFloatNumber *m, + const icFloatNumber *v); + +icS15Fixed16Number ICCPROFLIB_API icDtoF(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icFtoD(icS15Fixed16Number num); + +icU16Fixed16Number ICCPROFLIB_API icDtoUF(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icUFtoD(icU16Fixed16Number num); + +icU1Fixed15Number ICCPROFLIB_API icDtoUSF(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icUSFtoD(icU1Fixed15Number num); + +icU8Fixed8Number ICCPROFLIB_API icDtoUCF(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icUCFtoD(icU8Fixed8Number num); + +/*0 to 255 <-> 0.0 to 1.0*/ +icUInt8Number ICCPROFLIB_API icFtoU8(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icU8toF(icUInt8Number num); + +/*0 to 65535 <-> 0.0 to 1.0*/ +icUInt16Number ICCPROFLIB_API icFtoU16(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icU16toF(icUInt16Number num); + +/*0 to 255 <-> -128.0 to 127.0*/ +icUInt8Number ICCPROFLIB_API icABtoU8(icFloatNumber num); +icFloatNumber ICCPROFLIB_API icU8toAB(icUInt8Number num); + +extern ICCPROFLIB_API icFloatNumber icD50XYZ[3]; +extern ICCPROFLIB_API icFloatNumber icD50XYZxx[3]; + +void ICCPROFLIB_API icNormXYZ(icFloatNumber *XYZ, icFloatNumber *WhiteXYZ=NULL); +void ICCPROFLIB_API icDeNormXYZ(icFloatNumber *XYZ, icFloatNumber *WhiteXYZ=NULL); + +void ICCPROFLIB_API icXYZtoLab(icFloatNumber *Lab, icFloatNumber *XYZ=NULL, icFloatNumber *WhiteXYZ=NULL); +void ICCPROFLIB_API icLabtoXYZ(icFloatNumber *XYZ, icFloatNumber *Lab=NULL, icFloatNumber *WhiteXYZ=NULL); + +void ICCPROFLIB_API icLab2Lch(icFloatNumber *Lch, icFloatNumber *Lab=NULL); +void ICCPROFLIB_API icLch2Lab(icFloatNumber *Lab, icFloatNumber *Lch=NULL); + +icFloatNumber ICCPROFLIB_API icMin(icFloatNumber v1, icFloatNumber v2); +icFloatNumber ICCPROFLIB_API icMax(icFloatNumber v1, icFloatNumber v2); + +icUInt32Number ICCPROFLIB_API icIntMin(icUInt32Number v1, icUInt32Number v2); +icUInt32Number ICCPROFLIB_API icIntMax(icUInt32Number v1, icUInt32Number v2); + +icFloatNumber ICCPROFLIB_API icDeltaE(icFloatNumber *Lab1, icFloatNumber *Lab2); + +/**Floating point encoding of Lab in PCS is in range 0.0 to 1.0 */ +///Here are some conversion routines to convert to regular Lab encoding +void ICCPROFLIB_API icLabFromPcs(icFloatNumber *Lab); +void ICCPROFLIB_API icLabToPcs(icFloatNumber *Lab); + +/** Floating point encoding of XYZ in PCS is in range 0.0 to 1.0 + (Note: X=1.0 is encoded as about 0.5)*/ +///Here are some conversion routines to convert to regular XYZ encoding +void ICCPROFLIB_API icXyzFromPcs(icFloatNumber *XYZ); +void ICCPROFLIB_API icXyzToPcs(icFloatNumber *XYZ); + + +void ICCPROFLIB_API icMemDump(std::string &sDump, void *pBuf, icUInt32Number nNum); +void ICCPROFLIB_API icMatrixDump(std::string &sDump, icS15Fixed16Number *pMatrix); +ICCPROFLIB_API const icChar* icGetSig(icChar *pBuf, icUInt32Number sig, bool bGetHexVal=true); +ICCPROFLIB_API const icChar* icGetSigStr(icChar *pBuf, icUInt32Number nSig); + +icUInt32Number ICCPROFLIB_API icGetSigVal(const icChar *pBuf); +icUInt32Number ICCPROFLIB_API icGetSpaceSamples(icColorSpaceSignature sig); + +ICCPROFLIB_API extern const char *icValidateWarningMsg; +ICCPROFLIB_API extern const char *icValidateNonCompliantMsg; +ICCPROFLIB_API extern const char *icValidateCriticalErrorMsg; + +#ifdef ICC_BYTE_ORDER_LITTLE_ENDIAN +inline void icSwab16Ptr(void *pVoid) +{ + icUInt8Number *ptr = (icUInt8Number*)pVoid; + icUInt8Number tmp; + + tmp = ptr[0]; ptr[0] = ptr[1]; ptr[1] = tmp; +} + +inline void icSwab16Array(void *pVoid, int num) +{ + icUInt8Number *ptr = (icUInt8Number*)pVoid; + icUInt8Number tmp; + + while (num>0) { + tmp = ptr[0]; ptr[0] = ptr[1]; ptr[1] = tmp; + ptr += 2; + num--; + } +} + +inline void icSwab32Ptr(void *pVoid) +{ + icUInt8Number *ptr = (icUInt8Number*)pVoid; + icUInt8Number tmp; + + tmp = ptr[0]; ptr[0] = ptr[3]; ptr[3] = tmp; + tmp = ptr[1]; ptr[1] = ptr[2]; ptr[2] = tmp; +} + +inline void icSwab32Array(void *pVoid, int num) +{ + icUInt8Number *ptr = (icUInt8Number*)pVoid; + icUInt8Number tmp; + + while (num>0) { + tmp = ptr[0]; ptr[0] = ptr[3]; ptr[3] = tmp; + tmp = ptr[1]; ptr[1] = ptr[2]; ptr[2] = tmp; + ptr += 4; + num--; + } + +} + +inline void icSwab64Ptr(void *pVoid) +{ + icUInt8Number *ptr = (icUInt8Number*)pVoid; + icUInt8Number tmp; + + tmp = ptr[0]; ptr[0] = ptr[7]; ptr[7] = tmp; + tmp = ptr[1]; ptr[1] = ptr[6]; ptr[6] = tmp; + tmp = ptr[2]; ptr[2] = ptr[5]; ptr[5] = tmp; + tmp = ptr[3]; ptr[3] = ptr[4]; ptr[4] = tmp; +} + +inline void icSwab64Array(void *pVoid, int num) +{ + icUInt8Number *ptr = (icUInt8Number*)pVoid; + icUInt8Number tmp; + + while (num>0) { + tmp = ptr[0]; ptr[0] = ptr[7]; ptr[7] = tmp; + tmp = ptr[1]; ptr[1] = ptr[6]; ptr[6] = tmp; + tmp = ptr[2]; ptr[2] = ptr[5]; ptr[5] = tmp; + tmp = ptr[3]; ptr[3] = ptr[4]; ptr[4] = tmp; + ptr += 8; + num--; + } + +} +#else //!ICC_BYTE_ORDER_LITTLE_ENDIAN +#define icSwab16Ptr(x) +#define icSwab16Array(x, n) +#define icSwab32Ptr(x) +#define icSwab32Array(x, n) +#define icSwab64Ptr(x) +#define icSwab64Array(x, n) +#endif + +#define icSwab16(x) icSwab16Ptr(&x) +#define icSwab32(x) icSwab32Ptr(&x) +#define icSwab64(x) icSwab64Ptr(&x) + + +/** + ************************************************************************** + * Type: Class + * + * Purpose: + * This is a utility class which can be used to get profile info + * for printing. The member functions are used to convert signatures + * and other enum values to character strings for printing. + ************************************************************************** + */ +class ICCPROFLIB_API CIccInfo { +public: + //Signature values + const icChar *GetVersionName(icUInt32Number val); + const icChar *GetDeviceAttrName(icUInt64Number val); + const icChar *GetProfileFlagsName(icUInt32Number val); + + const icChar *GetTagSigName(icTagSignature sig); + const icChar *GetTechnologySigName(icTechnologySignature sig); + const icChar *GetTagTypeSigName(icTagTypeSignature sig); + const icChar *GetColorSpaceSigName(icColorSpaceSignature sig); + const icChar *GetProfileClassSigName(icProfileClassSignature sig); + const icChar *GetPlatformSigName(icPlatformSignature sig); + const icChar *GetCmmSigName(icCmmSignature sig); + const icChar *GetReferenceMediumGamutSigNameName(icReferenceMediumGamutSignature sig); + const icChar *GetColorimetricIntentImageStateName(icColorimetricIntentImageStateSignature sig); + + const icChar *GetSigName(icUInt32Number val); + + //Other values + const icChar *GetMeasurementFlareName(icMeasurementFlare val); + const icChar *GetMeasurementGeometryName(icMeasurementGeometry val); + const icChar *GetRenderingIntentName(icRenderingIntent val); + const icChar *GetSpotShapeName(icSpotShape val); + const icChar *GetStandardObserverName(icStandardObserver val); + const icChar *GetIlluminantName(icIlluminant val); + + const icChar *GetUnknownName(icUInt32Number val); + const icChar *GetMeasurementUnit(icSignature sig); + const icChar *GetProfileID(icProfileID *profileID); + const icChar *GetColorantEncoding(icColorantEncoding colorant); + + bool IsProfileIDCalculated(icProfileID *profileID); + icValidateStatus CheckData(std::string &sReport, const icDateTimeNumber &dateTime); + icValidateStatus CheckData(std::string &sReport, const icXYZNumber &XYZ); + + bool IsValidSpace(icColorSpaceSignature sig); + +protected: + icChar m_szStr[128]; + icChar m_szSigStr[128]; +}; + +extern ICCPROFLIB_API CIccInfo icInfo; + + +/** + ************************************************************************** + * Type: Class + * + * Purpose: + * This is a UTF16 string class that provides conversions + ************************************************************************** + */ +class ICCPROFLIB_API CIccUTF16String +{ +public: + CIccUTF16String(); + CIccUTF16String(const icUInt16Number *uzStr); + CIccUTF16String(const char *szStr); + CIccUTF16String(const CIccUTF16String &str); + virtual ~CIccUTF16String(); + + void Clear(); + bool Empty() const { return m_len==0; } + size_t Size() const { return m_len; } + void Resize(size_t len); + + CIccUTF16String& operator=(const CIccUTF16String &wstr); + CIccUTF16String& operator=(const char *szStr); + CIccUTF16String& operator=(const icUInt16Number *uzStr); + + bool operator==(const CIccUTF16String &str) const; + + icUInt16Number operator[](size_t nIndex) const { return m_str[nIndex]; } + + const icUInt16Number *c_str() const { return m_str; } + + void FromUtf8(const char *szStr, size_t sizeSrc=0); + const char *ToUtf8(std::string &buf) const; + void FromWString(const std::wstring &buf); + const wchar_t *ToWString(std::wstring &buf) const; + + static size_t WStrlen(const icUInt16Number *uzStr); + +protected: + static size_t AllocSize(size_t n) { return (((n+64)/64)*64); } + size_t m_alloc; + size_t m_len; + icUInt16Number *m_str; +}; + +const char * ICCPROFLIB_API icUtf16ToUtf8(std::string &buf, const icUInt16Number *szSrc, int sizeSrc=0); +const unsigned short * ICCPROFLIB_API icUtf8ToUtf16(CIccUTF16String &buf, const char *szSrc, int sizeSrc=0); + + + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif diff --git a/library/src/main/cpp/icc/IccXformFactory.cpp b/library/src/main/cpp/icc/IccXformFactory.cpp new file mode 100644 index 00000000..56c6dbd7 --- /dev/null +++ b/library/src/main/cpp/icc/IccXformFactory.cpp @@ -0,0 +1,171 @@ +/** @file + File: IccXformFactory.cpp + + Contains: Implementation of the CIccXform class and creation factories + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Oct 30, 2005 +// Added CICCXform Creation using factory support +// +////////////////////////////////////////////////////////////////////// + +#include "IccXformFactory.h" + +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +CIccXform* CIccBaseXformFactory::CreateXform(icXformType xformSig, CIccTag *pTag/*=NULL*/, CIccCreateXformHintManager *pHintManager/*=NULL*/) +{ + //We generally ignore pHint in the base creator (used by others to determine what form of xform to create) + switch(xformSig) { + case icXformTypeMatrixTRC: + return new CIccXformMatrixTRC(); + + case icXformType3DLut: + return new CIccXform3DLut(pTag); + + case icXformType4DLut: + return new CIccXform4DLut(pTag); + + case icXformTypeNDLut: + return new CIccXformNDLut(pTag); + + case icXformTypeNamedColor: + if (pHintManager) { + IIccCreateXformHint* pHint = pHintManager->GetHint("CIccCreateXformNamedColorHint"); + if (pHint) { + CIccCreateNamedColorXformHint *pNCHint = (CIccCreateNamedColorXformHint*)pHint; + return new CIccXformNamedColor(pTag, pNCHint->csPcs, pNCHint->csDevice); + } + } + return NULL; + + case icXformTypeMpe: + return new CIccXformMpe(pTag); + + case icXformTypeMonochrome: + return new CIccXformMonochrome(); + + default: + return NULL; + } +} + +std::auto_ptr CIccXformCreator::theXformCreator; + +CIccXformCreator::~CIccXformCreator() +{ + IIccXformFactory *pFactory = DoPopFactory(true); + + while (pFactory) { + delete pFactory; + pFactory = DoPopFactory(true); + } +} + +CIccXformCreator* CIccXformCreator::GetInstance() +{ + if (!theXformCreator.get()) { + theXformCreator = CIccXformCreatorPtr(new CIccXformCreator); + + theXformCreator->DoPushFactory(new CIccBaseXformFactory); + } + + return theXformCreator.get(); +} + +CIccXform* CIccXformCreator::DoCreateXform(icXformType xformTypeSig, CIccTag *pTag/*=NULL*/, CIccCreateXformHintManager *pHintManager/*=NULL*/) +{ + CIccXformFactoryList::iterator i; + CIccXform *rv = NULL; + + for (i=factoryStack.begin(); i!=factoryStack.end(); i++) { + rv = (*i)->CreateXform(xformTypeSig, pTag, pHintManager); + if (rv) + break; + } + return rv; +} + +void CIccXformCreator::DoPushFactory(IIccXformFactory *pFactory) +{ + factoryStack.push_front(pFactory); +} + +IIccXformFactory* CIccXformCreator::DoPopFactory(bool bAll /*=false*/) +{ + //int nNum = (bAll ? 0 : 1); + + if (factoryStack.size()>0) { + CIccXformFactoryList::iterator i=factoryStack.begin(); + IIccXformFactory* rv = (*i); + factoryStack.pop_front(); + return rv; + } + return NULL; +} + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif diff --git a/library/src/main/cpp/icc/IccXformFactory.h b/library/src/main/cpp/icc/IccXformFactory.h new file mode 100644 index 00000000..57ee9aa0 --- /dev/null +++ b/library/src/main/cpp/icc/IccXformFactory.h @@ -0,0 +1,248 @@ +/** @file + File: IccXformFactory.h + + Contains: Header for implementation of CIccXformFactory class and + creation factories + + Version: V1 + + Copyright: see ICC Software License +*/ + +/* + * The ICC Software License, Version 0.2 + * + * + * Copyright (c) 2007-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + +////////////////////////////////////////////////////////////////////// +// HISTORY: +// +// -Nov 21, 2007 +// A CIccXformCreator singleton class has been added to provide general +// support for dynamically creating xform classes using a xform type. +// Prototype and private xform type support can be added to the system +// by pushing additional IIccXformFactory based objects to the +// singleton CIccXformCreator object. +// +////////////////////////////////////////////////////////////////////// + +#ifndef _ICCXFORMFACTORY_H +#define _ICCXFORMFACTORY_H + +#include "IccCmm.h" +#include +#include +#include + +//CIccXform factory support +#ifdef USESAMPLEICCNAMESPACE +namespace sampleICC { +#endif + +/** + *********************************************************************** + * Class: IIccXformFactory + * + * Purpose: + * IIccXformFactory is a factory pattern interface for CIccXform creation. + * This class is pure virtual. + *********************************************************************** + */ +class IIccXformFactory +{ +public: + virtual ~IIccXformFactory() {} + + /** + * Function: CreateXform(xformTypeSig) + * Create a xform of type xformTypeSig. + * + * Parameter(s): + * xformTypeSig = signature of the ICC xform type for the xform to be created + * pTag = tag information for created xform + * pHintManager = contains additional information used to create xform + * + * Returns a new CIccXform object of the given signature type. If the xform + * factory doesn't support creation of xforms of type xformTypeSig then it + * should return NULL. + */ + virtual CIccXform* CreateXform(icXformType xformType, CIccTag *pTag=NULL, CIccCreateXformHintManager* pHintManager=0)=0; +}; + + +//A CIccXformFactoryList is used by CIccXformCreator to keep track of xform +//creation factories +typedef std::list CIccXformFactoryList; + + +/** + *********************************************************************** + * Class: CIccBaseXformFactory + * + * Purpose: + * CIccSpecXformFactory provides creation of Base CIccXform's. The + * CIccXformCreator always creates a CIccSpecXformFactory. + *********************************************************************** + */ +class CIccBaseXformFactory : public IIccXformFactory +{ +public: + /** + * Function: CreateXform(xformTypeSig) + * Create a xform of type xformTypeSig. + * + * Parameter(s): + * xformTypeSig = signature of the ICC xform type for the xform to be created + * pTag = tag information for created xform + * pHintManager = contains additional information used to create xform + * + * Returns a new CIccXform object of the given xform type. + * Unrecognized xformTypeSig's will be created as a CIccXformUnknown object. + */ + virtual CIccXform* CreateXform(icXformType xformType, CIccTag *pTag=NULL, CIccCreateXformHintManager *pHintManager=NULL); + +}; + +class CIccXformCreator; + +typedef std::auto_ptr CIccXformCreatorPtr; + +/** + *********************************************************************** + * Class: CIccXformCreator + * + * Purpose: + * CIccXformCreator uses a singleton pattern to provide dynamically + * upgradeable CIccXform derived object creation based on xform type. + *********************************************************************** + */ +class CIccXformCreator +{ +public: + ~CIccXformCreator(); + + /** + * Function: CreateXform(xformTypeSig) + * Create a xform of type xformTypeSig. + * + * Parameter(s): + * xformType = signature of the ICC xform type for the xform to be created + * pTag = tag information for created xform + * pHintManager = contains additional information used to create xform + * + * Returns a new CIccXform object of the given xform type. + * Each factory in the factoryStack is used until a factory supports the + * signature type. + */ + static CIccXform* CreateXform(icXformType xformType, CIccTag *pTag=NULL, CIccCreateXformHintManager *pHintManager=NULL) + { return CIccXformCreator::GetInstance()->DoCreateXform(xformType, pTag, pHintManager); } + + /** + * Function: PushFactory(pFactory) + * Add an IIccXformFactory to the stack of xform factories tracked by the system. + * + * Parameter(s): + * pFactory = pointer to an IIccXformFactory object to add to the system. + * The pFactory must be created with new, and will be owned CIccXformCreator + * until popped off the stack using PopFactory(). Any factories not + * popped off will be taken care of properly on application shutdown. + * + */ + static void PushFactory(IIccXformFactory *pFactory) + { CIccXformCreator::GetInstance()->CIccXformCreator::DoPushFactory(pFactory); } + + /** + * Function: PopFactory() + * Remove the top IIccXformFactory from the stack of xform factories tracked by the system. + * + * Parameter(s): + * None + * + * Returns the top IIccXformFactory from the stack of xform factories tracked by the system. + * The returned xform factory is no longer owned by the system and needs to be deleted + * to avoid memory leaks. + * + * Note: The initial CIccSpecXformFactory cannot be popped off the stack. + */ + static IIccXformFactory* PopFactory() + { return CIccXformCreator::GetInstance()->DoPopFactory(); } + +private: + /**Only GetInstance() can create the signleton*/ + CIccXformCreator() { } + + /** + * Function: GetInstance() + * Private static function to access singleton CiccXformCreator Object. + * + * Parameter(s): + * None + * + * Returns the singleton CIccXformCreator object. It will allocate + * a new one and push a single CIccSpecXform Factory object onto the factory + * stack if the singleton has not been intialized. + */ + static CIccXformCreator* GetInstance(); + + CIccXform* DoCreateXform(icXformType xformType, CIccTag *pTag=NULL, CIccCreateXformHintManager *pHintManager=NULL); + void DoPushFactory(IIccXformFactory *pFactory); + IIccXformFactory* DoPopFactory(bool bAll=false); + + static CIccXformCreatorPtr theXformCreator; + + CIccXformFactoryList factoryStack; +}; + +#ifdef USESAMPLEICCNAMESPACE +} //namespace sampleICC +#endif + +#endif //_ICCXFORMFACTORY_H diff --git a/library/src/main/cpp/icc/MainPage.h b/library/src/main/cpp/icc/MainPage.h new file mode 100644 index 00000000..8c23b545 --- /dev/null +++ b/library/src/main/cpp/icc/MainPage.h @@ -0,0 +1,457 @@ +/** @file + File: MainPage.h + + Note: This file was added to provide documentation in doxygen. Nothing in IccProfLib actually uses it. +*/ + +/** \mainpage + * + * The IccProfLib is an open source cross platform C++ library for reading, writing, manipulating, + * and applying ICC profiles. It is an attempt at a strict interpretation of the ICC profile + * specification. + * The structure of the library very closely follows the structure of the specification. + * A working knowledge of the ICC specification and color management workflows will aid in + * understanding the library and it's proper usage. For the latest ICC profile + * specification please visit http://www.color.org. Several useful white papers and resources + * are also available on the website. + * + * Note: More documentation on SampleICC's Color Management Modules (CMM's) can be found in the white + * paper titled "Implementation Notes for the IccLib CMM in SampleICC". + * (see http://www.color.org/ICC_white_paper_18_IccLib_Notes.pdf) + * + * Here are some of the things that the IccProfLib supports: + * - ICC profile file I/O in CIccProfile class + * - Version 4.2 profiles (read & write) + * - Version 2.x profiles (read) + * - C++ classes for all specified tag types (based on CIccTag). Default behavior for + * unrecognized private tag types is implemented using a generic Tag class. + * - Two basic Color Management Module (CMM) implementations + * - Basic pixel level transforms in CIccCmm class + * - Additional named color profile support in CIccNamedColorCmm class + * - File I/O can be re-directed + * - All operations performed using floating point. Pixel precision not limited to integers. + * - Transforms are done one pixel at a time. + * - Flexible number of profile transforms in a series (as long as the colorspaces match) + * - Multidimensional lookup table interpolation + * - Three dimensional interpolation uses either linear or tetrahedral interpolation + * (selectable at time profile is attached to the CMM). + * - Greater than three dimensional interpolation uses linear interpolation + * - Matrix/TRC support + * - Calculation of Profile ID using the MD5 fingerprinting method (see md5.h) + * - Dynamic creation and seemless use of private CIccTag derived objects that are implemented + * outside of IccProfLib (IE inside a private library or application that links with + * IccProfLib). + * + * USAGE COMMENTS + * -# The IccProfLib implements very basic CMMs. These may not + * provide the optimum speed in all situations. Profile transforms are done one pixel + * at a time for each profile in a profile transformation chain. Various techniques + * can possibly be used to improve performance. An initial thought would be to create a + * CMM that uses the basic CIccCmm to generate a single link transform (concatenating + * the profiles). Such a transform could employ integer math if needed. + * -# The IccProfLib can be used to open, generate, manipulate (by adding, removing, or + * modifying tags), and/or save profiles without needing to use the pixel transformations + * provided by the CMM classes. + * -# Several applications have been written (in SampleICC) that make use of the IccProfLib. + * It is advisable to examine these applications for additional guidance in making + * the best use of the IccProfLib. + * -# Before compiling on non-Windows and non Mac OSX platforms it will be necessary to edit + * the configuration parameters in IccProfLibConf.h. + * + * VERSION HISTORY + * - December 2015 - 1.6.10 release + * - 1.6.11 release + * - Fixed bug in validation of GamutTags + * + * - December 2015 - 1.6.10 release based on submission by Vitaly Bondar + * - 1.6.10 release + * - Fixed bug in copy data of copy constructors and copy operations of CIccTagUnkown, + * CIccTagNamedColor2, CIccTagChromaticity, CIccTagFixedNum, CIccTagNum, CIccTagData, + * and CIccTagColorantOrder + * + * - Sept 2015 - 1.6.9 release + * - 1.6.9 release + * - Added check to black point compensation to check for negative values going into square + * root calculation + * - Fixed bug in copying data in constructor and copy operator of CIccTagFixedNum + * - Updated copyright dates + * - Added use of WXVER environment variable to select wxWidgets library version for build + * of wxProfileDump + * + * - April 2014 - 1.6.8 release + * - 1.6.8 release + * - Modified CIccTagParametricCurve to use icFloatNumber rather than icS15Fixed16Number + * for internal storage purposes. Fixes crashing bug with profile verification. + * - Added check for named color profile class when icSigNamedColor2Tag is filed + * - Changed #ifdef WIN32 to #if defined(WIN32) || defined(WIN64) + * - Added zeros to end of PRMG gamut for easy detection of end of gamut + * - Removed 4 byte alignment check for profile length for versions before v4.2 + * - Fixed bug with copy of data in CIccTagColorantTable objects + * + * - August 2012 - 1.6.7 release + * - 1.6.7 release + * - Made const functions more consistent + * - Moved CIccUTF16String class from IccXML + * - Replace use of std::wstring in CIccTagDict with CIccUTF16String + * - Added ICC_ENUM_CONVENIENCE define that makes convenience enums part of the enum type + * + * - August 2011 - 1.6.6 release + * - Added iccGetBPCInfo command line tool to retrieve information about BPC connection + * - Changed CIccApplyBPC private members to protected members to allow object overridden + * and made CIccApplyBPC:calcBlackPoint virtual to support override in iccGetBPCInfo + * + * - April 2011 - 1.6.5 release + * - Modified .sln and .vcproj files to work with Visual Studio 2008 + * - Added _v8.sln and _v8.vcproj files to work with Visual Studio 2005 + * - Fixed bugs in CIccInfo::GetProfileID() and CIccInfo::IsProfileIDCalculated() + * + * - January 2011 - 1.6.4 release + * - Added CIccNullIO class that can be used by a caller to "write" the profile thus updating + * tag directory entries + * - Fixed various bugs related to setting text in CIccTagDict tags + * - Added CIccTagLut8::GetPrecision() function + * - Fixed bug in validation of CIccTextDescription class + * - Initialize m_nVendorflags in CIccTagNamedColor2 constructor + * - Fixed bug in CIccTagNamedColor2::SetSize() that was copying wrong thing + * - Fixed bug in CIccTagMultiLocalizedUnicode::Read() that was using wrong seek value at end + * - Defined initial values in CIccTagViewingCondions constructor + * - Modified CLUT interpolation in IccTagLut.cpp to perform clipping on input and no clipping + * on output (as opposed to the other way around). Fixes crashing bug found with absolute + * intent processing of colors that are whiter than media point. Also supports floating point range + * of output for MPE CLUT elements. + * - Renaming of MD5 calculation functions to avoid conflicts with other libraries + * + * - November 2010 - 1.6.3 release + * - Modification of type for CIccCLUT::m_nOutput to icUInt16Nubmer to better support MPE + * CLUT elements + * - Fixed typo in CIccTagUnknown::IsSupported() + * + * - August 2010 - 1.6.1 release + * - Fix bugs with reading and displaying metaDataTags using the dictTagType + * + * - August 2010 - 1.6.1 release + * - Modifications to CIccTagLut16 and CIccTagLut8 to correctly track curve mapping when table + * is used as an output table and PCS is XYZ. In this case M and B curves are swapped since + * the legacy Lut16 and Lut8 tags do not have M curves. + * - Removed check in CIccXform::Create() for BtoD0/DtoB0 tags if BtoDx/DtoBx tag for rendering + * intent not found (as this never made it into the approved specification). + * - Further changes from Joseph Goldstone that eliminate various compiler warnings + * + * - July 2010 - 1.6.0 release + * - Moved main Build for Windows systems to Build\MSVC folder with intent to add builds for + * other systems to Build folder + * - Incorporated changes from Joseph Goldstone that eliminate various compiler warnings + * - Modified CIccProfile::Write() to allow for options in how ProfileIDs are created + * (Example: ByProfileVersion/Always/Never) + * + * - May 2010 + * - Modifications for better support for compiling with 64 bit compilers + * - Added IccProfLibVer.h to provide a macro for defining the library version + * - Fixed crashing bug with gamut tags with XYZ PCS + * - Modified CLUT::dump to use reflect legacy encoding of when lut16 tags are used + * + * - April 2010 + * - Modified IccProfLibTest to allow modification of ProfileDescription and Copyright tags + * + * - March 2010 + * - Added support for PrintConditions tag implemented using Dictionary tag type + * + * - January 2009 + * - Added CIccCreateXformHintManager to allow for a list of hint object to be passed + * in at the time of CIccXform creation. + * - Modified PCS adjustment to use a scale and offset in new function CIccXform::AdjustPCS(). + * CIccXform::CheckSrcAbs and CIccXform::CheckDestAbs now use CIccXform::AdjustPCS()/ + * - Hint mechanism can now be used to set up scale and offset values. + * - Added CIccApplyBPCHint and CIccApplyBPC classes in IccApplyBPC.cpp and IccApplyBPC.h + * to provide optional support for Adobe Black Point Compensation + * - Since BPC is outside the scope of the ICC specifiction, users of CIccXform::Create + * must define and use a CIccApplyBPCHint object to enable BPC processing. + * - CIccApplyBPC temporarily instantiates a CIccCmm for the purpose of finding the black point + * of a profile. + * - Black point processing between two profiles is performed in two steps. The first profile's + * black point is mapped to the V4 perceptual black point. The second profile maps from the + * V4 perceptual black point to the second profile's black point. This allows BPC processing + * to be performed on a single profile. + * - iccApplyNamedCMM.cpp modified to support BPC using CIccApplyBPC + * - Added CIccProfile::ReadTags() to force all tags to be loaded into memory. (Used by CIccApplyBPC) + * - CIccTagMultiLocalizedUnicode::Read() now seeks to the end of the last record at end of the function + * - Added ICC_CBRTF macro that can allow for substitution of cbrtf() function if it is available + * - Commented several additional functions in IccCmm.cpp + * - Modified WinNT\ApplyProfiles to allow for applying an output profile to a Lab image file + * - Fixed header in cmyk8bit.txt and cmyk16bit.txt files + * + * - December 2008 + * - Added support for Monochrome ICC profile apply + * + * - November 2008 + * - Cleanup of build files for Linux + * - Revised License to version 0.2 + * + * - October 2008 + * - Added support for External extension of CIccTags and CIccMPE objects + * - Make CIccMultiProcessElement::m_nReserved public + * - Added CIccMpeUnknown:SetType() and CIccMpeUnknown::SetChannels() to allow unknown elements to be externally created + * - CIccCLUT::Init() now returns bool to indicate allocation failure + * - Added icDeltaE() funciton to IccUtil.cpp + * - Modified MPE Sampled Curve to conform to specification. First point is NOT stored in file. + * - Fixed MPE processing to not Clip PCS or apply Absolute Rendering Intent adjustments. + * - Added support for selective use of MPE tags in iccApplyNamedCmm.cpp + * - Modified IccV4ToMPE to correctly create SampledCurve segments by not saving first point. + * - wxProfileDump now supports option to perform round trip performance analysis. + * - Added fix to make CIccCmmMRU work after chages to add CIccApplyCmm architecture. +* + * - November 2007 + * - Addition of CIccXformCreator singleton factory and IIccXformFactory interface for dynamic + * creation of CIccXform objects based upon xform type. With a IIccXformFactory derived + * object properly registered using CIccXformCreator::PushFactory() overlaoded CIccXform objects + * seemleessly get created and applied. + * + * - October 2007 + * - Fixed Memory leak in CIccProfile Copy constructor and operator=. + * + * - September 2007 + * - Fixed bug with Tetrahedral Interpolation + * + * - August 2007 + * - MPE Formula Curve bug fixes. + * - Registered CMM signatures recognized and displayed correctly. + * - Unknown platform signature type added (00000000h). + * + * - June 2007 + * - Added support for optional ProfileSequenceId tags. These tags provide contents of + * profile description tags and id's for profiles used to create an device link profile. The + * CIccTagProfileSequeceId class implements these objects. + * - Added support for optional colorimetric Intent Image State tags. This tag provides information + * about the image state implied by the use of a profile containg this tag. + * + * - Febrary 2007 + * - Added a CIccMruCmm class that keeps track of the last 5 pixels that were applied. Used by the + * SampleIccCmm Windows CMM DLL project. + * + * - November 2006 + * - Added support for optional multiProcessingElementType tags. These tags provide + * an arbitrary order of curves, matricies, and N-D luts encoded using floating + * point. The CIccTagMultiProcessElement class implements these objects. MPE based tags + * can have 1 or more CIccMultiProcessElement based objects attached to them. + * See CIccMpeCurveSet, CIccMpeMatrix, CIccMpeCLUT for more details. Additional future + * placeholder elements CIccMpeBAcs and CIccMpeEAcs objects are defined, but provide no + * processing capabilities. See additions to Icc Specification for more details + * releated to optional MPE based tags. + * - Modified icProfileHeader.h to include newly approved Technololgy signatures for the + * digital motion picture industry. + * + * - October 2006 + * - Added direct accessors CIccTagMultiLocalizedUnicode::Find() and + * CIccTagMultiLocalizedUnicode::SetText() for easier creation of tags based on + * CIccTagMultiLocalizedUnicode + * - Added CIccTagCurve::SetGamma() function + * - Added validation check for single entry (gamma) curves to CIccTagLut8 and CIccTagLut16 + * - Added IsIdentity() function to the CIccCurve and CIccMatrix classes which returns true + * if they are identity + * - Modified the Xform objects in the CMM to use the IsIdentity() function. + * Now CIccXform::Apply() will not apply the curves or the matrix if + * they are identity, to improve the CMM performance + * + * - July 2006 + * - Fixed bug with displaying the icSigPerceptualRenderingIntentGamutTag tag's name correctly + * - Added icVectorApplyMatrix3x3() to IccUtil + * - Fixed bug in CIccTagChromaticity::Validate() to use fixed floating point encoding in + * comparisons rather than IEEE encoding + * + * - June 2006 + * - Added concept of device Lab and XYZ separate from PCS Lab and XYZ. The encoding for + * device Lab and XYZ can be different than that used by the PCS. + * Both CIccXform::GetSrcSpace() and CIccXform::GetDstSpace() now return icSigDevLabData + * (rather than icSigLabData) or icSigDevXYZData (rather than icSigXYZData) if the connection + * is to a device (rather than PCS). + * - The macros icSigDevLabData and icSigDevXYZData were added to IccDefs.h. + * - icGetSpaceSamples() and CIccInfo::GetColorSpaceSigName() were modified to recognize + * icSigDevLabData and icSigDevXYZData. + * + * - May 2006 + * - Added icSigSampleICC to IccDefs.h and CIccProfile.cpp now uses this to initialize + * default values for creator and cmm in header fields. + * - Renamed icMatrix3x3Invert() to icInvertMatrix3x3() in IccUtil + * - Added icMatrixMultipily3x3() to IccUtil + * + * - April 2006 + * - The CIccXform derived objects now have a virual GetType function to allow for easy + * identification and casting to an appropriate class type. + * - Modified CIccCmm to Allocate and use a single CIccPCS object rather than instantiating + * a new object on each call to Apply. The CIccPCS object creation is performed using + * a virtual member function. + * - Minor type casting for beter compilation on Linux + * - Added SAMPLEICC_NOCLIPLABTOXYZ macro to IccProfLibConf.h to remove clipping when + * converting from Lab to XYZ. This makes things round trip better but possibly results + * in imaginary (not well defined) XYZ values. + * - Added clipping to CIccTagCurve::Apply(v) to handle when v is out of range. + * - CIccLocalizedUnicode constructor now allocates enough data for a single 16 bit character. + * - CIccFileIO::Open() now appends a 'b' to szAttr if missing in WIN32. + * - Added check in profile validation for existance of colorantTableTag if output profile is xCLR. + * + * - March 2006 + * - Modified icProfileHeader.h with reduced ICC copyright notice and changed icRegionCode + * to icCountryCode to agree with ISO 3166 naming convention. + * + * - February 2006 + * - Modified CIccCLUT Interp interfaces to take separate src and dst pixel values. + * - Modified CIccCLUT interface with selectable clipping function. + * - Added IsSupported() function to CIccTag and CIccTagUnknown classes. This function + * is used to find out if tag is supported (for apply purposes). + * - Modified ToInternalEncoding and FromInternalEncoding to add icEncodeValue support + * for XYZ data. The icEncodePercent was also modified to take Y=100.0 into and out of + * XYZ internal PCS encoding. + * - TagFactory interface for GetSigName() didn't function properly. It was modified to + * provide better support for GetSigName() and GetSigTypeName(). + * - Additional cleanup of icProfileHeader.h. Noticable Difference icProfileID.ID was + * chaged to icProfileID.ID8 + * + * - December 2005 + * - Moved most of the contents of IccDefs.h to icProfileHeader.h which corresponds to the "C" + * header file published on ICC Web site. The file icProfileHeader.h has been updated to reduce + * complications with compilers, missing version 4 items were added, and basic cleanup was + * performed. + * - A cross platform GUI based ICC Profile Viewer tool named wxProfileDump was added that + * makes use of the wxWidgets (http://www.wxWidgets.org) version 2.6.2 cross platform development + * framework. + * - Addition of CIccTagCreator singleton factory and IIccTagFactory interface for dynamic + * creation of CIccTag objects based upon tag signature. The CIccTag::Create() funciton now uses + * a CIccTagCreator singleton object to create all CIccTag derived objects. With a IIccTagFactory + * derived object properly registered using CIccTagCreator::PushFactory() private CIccTag objecs + * seemleessly load, save and validate. + * - CIccProfile::Write() modified to check for version 4 before calculating ProfileID value. + * + * - October 2005 + * - Fixed bugs in copy constructors for CIccProfile, CIccTagCurve, and CIccTagText. + * - Added comments to IccDefs.h to indicate convenience enums. + * - Changed icMaxFlare to icMaxEnumFlare and icMaxGeometry to icMaxEnumGeometry to improve + * consistancy. + * - Corrected spelling of icMaxEnumIluminant to icMaxEnumIlluminant. + * + * - September 2005 + * - Moved InvertMatrix to ICCUtils + * + * - August 2005 + * - Cleaned up more warnings. + * - Added additional CIccCmm::AddXform() method for easily attaching memory based profiles. + * - Added CIccCmm::ToInternalEncoding() and CIccCmm::FromInternalEncoding() methods that + * make use of Cmm's tracking of source and destination color spaces. + * + * - July 2005 + * - Renamed IccLib to IccProfLib to avoid confusion with Graeme Gill's "ICCLIB" project. + * + * - June 2005 + * - Cleaned up warnings. + * - Added support for applying Preview and Gamut Tags in CIccCmm and CIccNamedColorCmm. This + * is accomplished through the new nLutType argument to the CIccCmm::AddXform() methods. + * + * - May 2005 + * - Fixed bug in ParametricCurve type introduced with enhanced profile validation support. + * + * - April 2005 + * - Greatly enhanced Profile Validation support. (Note: Validation is a separate step from + * reading profiles for speed purposes). + * - The CIccProfile class's ValidateProfile() function provides a Validation report + * within a string in addition to returning a validation status. + * - Additional functions were added to the profile class for Validation purposes. + * - Tags now have a Validate() member function to check out the validity of the data + * in the tags. (No check is made for color accuracy). + * - Tags now store reserved data to provide better validation reporting. + * - Added support for perceptualRenderingIntentGamutTag and saturationRederingIntentGamutTag. + * - Split Tag implementation into two files IccTagBasic and IccTagLut. + * - Fixed bug with reading testDescriptionTagType. + * + * - March 2005 + * - Fixed bugs with N-Dimensional interpolation. + * - Fixed bugs with Lut8 Writing. + * - Added new CIccCLUT::Iterate() function to allow for manipulating data in a CLUT without having + * to mess with the details of dimension and granularity. + * + * - February 2005 + * - Added ability for IccProfLib to be compiled as a DLL. + * - Fixed bugs in CIccCmm::ToInternalEncoding() and CIccCmm::FromInternalEncoding() + * + * - January 2005 + * - Complete support for version 4.2 profiles as defined in ICC specification ICC.1:2004-10. + * - Added support for all tag types + * - N-dimensional interpolation function added (NOT TESTED) + * - Added support for calculation of profile ID using MD5 fingerprinting method + * - Profile validation function added + * - Added support for named color tags + * - Additional CMM class was added which supports named color profiles + * - Added copy constructors and copy operators for all Tag classes and Profile class. + * - Comments in the code were modified to allow the use of doxygen. Additional comments + * were added, and HTML documentation pages were generated. + * - Modified IccProfLib classes so that the library can be compiled as a DLL and gain access to + * IccProfLib objects from this separate DLL. + * + * - February 2004 + * - Merged in changes to get Mac OS X compatibility with the gnu compiler. + * - Added boiler plate disclaimers to all the source files. + * + * - November 2003 \n + * - There has been some limited testing by members of the ICC, and changes have + * been made as appropriate. Development was done on a WINTEL platform using Microsoft Visual C++ 6.0. + * It should work for this environment. Modifications have been made so that the + * projects can be converted and work with Visual Studio .NET.\n + * The IccProfLib was written to be platform independent. Peter McCloud of Adobe + * was able to get IccProfLib to compile and run on Mac OS X. + * + * TODO List + * + * - Create OS specific loadable library CMM wrappers to IccProfLib CMM objects. + * - Naming Convention Cleanup of conversion functions in IccUtil. + * - Restructure profile validation to use Tag Factory mechanism. + * + * The ICC Software License, Version 0.2 + * + * Copyright � 2003-2015 The International Color Consortium. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. In the absence of prior written permission, the names "ICC" and "The + * International Color Consortium" must not be used to imply that the + * ICC organization endorses or promotes products derived from this + * software. + * + * + * ====================================================================\n + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR\n + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n + * SUCH DAMAGE.\n + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * CONTACT + * + * Please send your questions, comments, and or suggestions to forums + * on the SampleICC project site. (http://sourceforge.net/projects/sampleicc/).\n + * + */ + diff --git a/library/src/main/cpp/icc/Makefile.am b/library/src/main/cpp/icc/Makefile.am new file mode 100644 index 00000000..c7e68a1b --- /dev/null +++ b/library/src/main/cpp/icc/Makefile.am @@ -0,0 +1,58 @@ +## Process this file with automake to produce Makefile.in + +lib_LTLIBRARIES = libSampleICC.la + +libSampleICC_la_SOURCES = \ + IccApplyBPC.cpp \ + IccCmm.cpp \ + IccConvertUTF.cpp \ + IccEval.cpp \ + IccXformFactory.cpp \ + IccIO.cpp \ + IccMpeACS.cpp \ + IccMpeBasic.cpp \ + IccMpeFactory.cpp \ + IccPrmg.cpp \ + IccProfile.cpp \ + IccTagBasic.cpp \ + IccTagDict.cpp \ + IccTagFactory.cpp \ + IccTagLut.cpp \ + IccTagMPE.cpp \ + IccTagProfSeqId.cpp \ + IccUtil.cpp \ + md5.cpp + +libSampleICC_la_LDFLAGS = -version-info @LIBTOOL_VERSION@ + +libSampleICCincludedir = $(includedir)/SampleICC + +libSampleICCinclude_HEADERS = \ + IccApplyBPC.h \ + IccCmm.h \ + IccConvertUTF.h \ + IccEval.h \ + IccXformFactory.h \ + IccDefs.h \ + IccIO.h \ + IccMpeACS.h \ + IccMpeBasic.h \ + IccMpeFactory.h \ + IccPrmg.h \ + IccProfLibConf.h \ + IccProfLibVer.h \ + IccProfile.h \ + IccTag.h \ + IccTagBasic.h \ + IccTagDict.h \ + IccTagFactory.h \ + IccTagLut.h \ + IccTagMPE.h \ + IccTagProfSeqId.h \ + IccUtil.h \ + icProfileHeader.h \ + md5.h + +INCLUDES = -I$(top_builddir) -I$(top_srcdir)/SampleICC + +EXTRA_DIST = MainPage.h diff --git a/library/src/main/cpp/icc/Makefile.in b/library/src/main/cpp/icc/Makefile.in new file mode 100644 index 00000000..8a58ac33 --- /dev/null +++ b/library/src/main/cpp/icc/Makefile.in @@ -0,0 +1,728 @@ +# Makefile.in generated by automake 1.13.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = IccProfLib +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp \ + $(libSampleICCinclude_HEADERS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(libSampleICCincludedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libSampleICC_la_LIBADD = +am_libSampleICC_la_OBJECTS = IccApplyBPC.lo IccCmm.lo IccConvertUTF.lo \ + IccEval.lo IccXformFactory.lo IccIO.lo IccMpeACS.lo \ + IccMpeBasic.lo IccMpeFactory.lo IccPrmg.lo IccProfile.lo \ + IccTagBasic.lo IccTagDict.lo IccTagFactory.lo IccTagLut.lo \ + IccTagMPE.lo IccTagProfSeqId.lo IccUtil.lo md5.lo +libSampleICC_la_OBJECTS = $(am_libSampleICC_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libSampleICC_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(libSampleICC_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libSampleICC_la_SOURCES) +DIST_SOURCES = $(libSampleICC_la_SOURCES) +HEADERS = $(libSampleICCinclude_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CXXFLAGS = @AM_CXXFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION = @LIBTOOL_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OSX_APPLICATION_LIBS = @OSX_APPLICATION_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SAMPLEICC_MAJOR_VERSION = @SAMPLEICC_MAJOR_VERSION@ +SAMPLEICC_MICRO_VERSION = @SAMPLEICC_MICRO_VERSION@ +SAMPLEICC_MINOR_VERSION = @SAMPLEICC_MINOR_VERSION@ +SAMPLEICC_VERSION = @SAMPLEICC_VERSION@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SICC_ICC_APPLY_PROFILES = @SICC_ICC_APPLY_PROFILES@ +STRIP = @STRIP@ +TIFF_CPPFLAGS = @TIFF_CPPFLAGS@ +TIFF_LDFLAGS = @TIFF_LDFLAGS@ +TIFF_LIBS = @TIFF_LIBS@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +lib_LTLIBRARIES = libSampleICC.la +libSampleICC_la_SOURCES = \ + IccApplyBPC.cpp \ + IccCmm.cpp \ + IccConvertUTF.cpp \ + IccEval.cpp \ + IccXformFactory.cpp \ + IccIO.cpp \ + IccMpeACS.cpp \ + IccMpeBasic.cpp \ + IccMpeFactory.cpp \ + IccPrmg.cpp \ + IccProfile.cpp \ + IccTagBasic.cpp \ + IccTagDict.cpp \ + IccTagFactory.cpp \ + IccTagLut.cpp \ + IccTagMPE.cpp \ + IccTagProfSeqId.cpp \ + IccUtil.cpp \ + md5.cpp + +libSampleICC_la_LDFLAGS = -version-info @LIBTOOL_VERSION@ +libSampleICCincludedir = $(includedir)/SampleICC +libSampleICCinclude_HEADERS = \ + IccApplyBPC.h \ + IccCmm.h \ + IccConvertUTF.h \ + IccEval.h \ + IccXformFactory.h \ + IccDefs.h \ + IccIO.h \ + IccMpeACS.h \ + IccMpeBasic.h \ + IccMpeFactory.h \ + IccPrmg.h \ + IccProfLibConf.h \ + IccProfLibVer.h \ + IccProfile.h \ + IccTag.h \ + IccTagBasic.h \ + IccTagDict.h \ + IccTagFactory.h \ + IccTagLut.h \ + IccTagMPE.h \ + IccTagProfSeqId.h \ + IccUtil.h \ + icProfileHeader.h \ + md5.h + +INCLUDES = -I$(top_builddir) -I$(top_srcdir)/SampleICC +EXTRA_DIST = MainPage.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu IccProfLib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu IccProfLib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libSampleICC.la: $(libSampleICC_la_OBJECTS) $(libSampleICC_la_DEPENDENCIES) $(EXTRA_libSampleICC_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libSampleICC_la_LINK) -rpath $(libdir) $(libSampleICC_la_OBJECTS) $(libSampleICC_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccApplyBPC.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccCmm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccConvertUTF.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccEval.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccIO.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccMpeACS.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccMpeBasic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccMpeFactory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccPrmg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccProfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccTagBasic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccTagDict.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccTagFactory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccTagLut.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccTagMPE.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccTagProfSeqId.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccUtil.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IccXformFactory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-libSampleICCincludeHEADERS: $(libSampleICCinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(libSampleICCincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libSampleICCincludedir)" + @list='$(libSampleICCinclude_HEADERS)'; test -n "$(libSampleICCincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libSampleICCincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(libSampleICCincludedir)" || exit $$?; \ + done + +uninstall-libSampleICCincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libSampleICCinclude_HEADERS)'; test -n "$(libSampleICCincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libSampleICCincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libSampleICCincludedir)" && rm -f $$files + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libSampleICCincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-libSampleICCincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES \ + uninstall-libSampleICCincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES \ + install-libSampleICCincludeHEADERS install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \ + uninstall-libSampleICCincludeHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/library/src/main/cpp/icc/icProfileHeader.h b/library/src/main/cpp/icc/icProfileHeader.h new file mode 100644 index 00000000..1d14c16d --- /dev/null +++ b/library/src/main/cpp/icc/icProfileHeader.h @@ -0,0 +1,1666 @@ +/** @file + File: icProfileHeader.h + + Contains: ICC profile definitions and structures including Version 4 extensions + + Copyright: see ICC Software License + + * + * This version of the header file corresponds to the profile + * specification version 4.2 as defined in ICC Specificion ICC.1:2004-04. + * + * Some definitions only provided by version 2.x profiles are also included. + * + * This header file should not be considered as a replacement for the ICC + * profile specification. The ICC profile specification should always be + * considered the ULTIMATE authority related to the specifiation for + * contents in ICC profile file. Conflicts between this header file + * and the ICC profile specification (if they exist) should be deferred + * to the ICC profile specification. + * + * + * All header file entries are pre-fixed with "ic" to help + * avoid name space collisions. Signatures are pre-fixed with + * icSig. + * + * Note: This header assumes that int is at least a 32 bit quantity + * + * The structures defined in this header file were created to + * represent a description of an ICC profile on disk. Rather + * than use pointers a technique is used where a single byte array + * was placed at the end of each structure. This allows us in "C" + * to extend the structure by allocating more data than is needed + * to account for variable length structures. + * + * This also ensures that data following is allocated + * contiguously and makes it easier to write and read data from + * the file. + * + * For example to allocate space for a 256 count length UCR + * and BG array, and fill the allocated data. Note strlen + 1 + * to remember NULL terminator. + * + icUcrBgCurve *ucrCurve, *bgCurve; + int ucr_nbytes, bg_nbytes, string_bytes; + icUcrBg *ucrBgWrite; + char ucr_string[100], *ucr_char; + + strcpy(ucr_string, "Example ucrBG curves"); + ucr_nbytes = sizeof(icUInt32Number) + + (UCR_CURVE_SIZE * sizeof(icUInt16Number)); + bg_nbytes = sizeof(icUInt32Number) + + (BG_CURVE_SIZE * sizeof(icUInt16Number)); + string_bytes = strlen(ucr_string) + 1; + + ucrBgWrite = (icUcrBg *)malloc( + (ucr_nbytes + bg_nbytes + string_bytes)); + +ucrCurve = (icUcrBgCurve *)ucrBgWrite->data; +ucrCurve->count = UCR_CURVE_SIZE; +for (i=0; icount; i++) +ucrCurve->curve[i] = (icUInt16Number)i; + + bgCurve = (icUcrBgCurve *)((char *)ucrCurve + ucr_nbytes); +bgCurve->count = BG_CURVE_SIZE; +for (i=0; icount; i++) +bgCurve->curve[i] = 255 - (icUInt16Number)i; + + ucr_char = (char *)((char *)bgCurve + bg_nbytes); + memcpy(ucr_char, ucr_string, string_bytes); + + * Many of the structures contain variable length arrays. This + * is represented by the use of the convention. + * + * type data[icAny]; + */ + +/* + * + * + * Copyright (c) 2003-2015 The International Color Consortium. + * + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the The International Color Consortium. + * + * + * Membership in the ICC is encouraged when this software is used for + * commercial purposes. + * + * + * For more information on The International Color Consortium, please + * see . + * + * + */ + + +/***************************************************************** + Copyright (c) 2002 Heidelberger Druckmaschinen AG + + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. +******************************************************************/ + +/***************************************************************** + Copyright (c) 1994 SunSoft, Inc. + + Rights Reserved + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restrict- +ion, including without limitation the rights to use, copy, modify, +merge, publish distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- +INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT +COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of SunSoft, Inc. +shall not be used in advertising or otherwise to promote the +sale, use or other dealings in this Software without written +authorization from SunSoft Inc. +******************************************************************/ + + + +/* Header file guard bands */ +#ifndef icPROFILEHEADER_H +#define icPROFILEHEADER_H + + +/* In order for structures to work it is important to ensure that + * the structure packing is set to 1. On many compilers this + * can be accomplished using #pragma pack(1). Define the macro + * ICSETBYTEPACKING to enable the following.*/ +#ifdef ICSETBYTEPACKING +#pragma pack(1) +#endif + +/*------------------------------------------------------------------------*/ + +/** + * Defines used in the specification + */ +#define icMagicNumber 0x61637370 /* 'acsp' */ +#define icVersionNumber 0x02000000 /* 2.0, BCD */ +#define icVersionNumberV2_1 0x02100000 /* 2.1, BCD */ +#define icVersionNumberV4 0x04000000 /* 4.0, BCD */ +#define icVersionNumberV4_2 0x04200000 /* 4.2, BCD */ + +/** Screening Encodings */ +#define icPrtrDefaultScreensFalse 0x00000000 /* Bit position 0 */ +#define icPrtrDefaultScreensTrue 0x00000001 /* Bit position 0 */ +#define icLinesPerInch 0x00000002 /* Bit position 1 */ +#define icLinesPerCm 0x00000000 /* Bit position 1 */ + +/** + * Device attributes, currently defined values correspond + * to the low 4 bytes of the 8 byte attribute quantity, see + * the header for their location. + */ +#define icReflective 0x00000000 /* Bit position 0 */ +#define icTransparency 0x00000001 /* Bit position 0 */ +#define icGlossy 0x00000000 /* Bit position 1 */ +#define icMatte 0x00000002 /* Bit position 1 */ +#define icMediaPositive 0x00000000 /* Bit position 2 */ +#define icMediaNegative 0x00000004 /* Bit position 2 */ +#define icMediaColour 0x00000000 /* Bit position 3 */ +#define icMediaBlackAndWhite 0x00000008 /* Bit position 3 */ + +/** + * Profile header flags, the low 16 bits are reserved for consortium + * use. + */ +#define icEmbeddedProfileFalse 0x00000000 /* Bit position 0 */ +#define icEmbeddedProfileTrue 0x00000001 /* Bit position 0 */ +#define icUseAnywhere 0x00000000 /* Bit position 1 */ +#define icUseWithEmbeddedDataOnly 0x00000002 /* Bit position 1 */ + +/** Ascii or Binary data */ +#define icAsciiData 0x00000000 /* Used in dataType */ +#define icBinaryData 0x00000001 + +/** + * Define used to indicate that this is a variable length array + */ +#define icAny 1 + +/** + * Number definitions + * + * NOTE: + * Integer definitions vary from compiler to compiler. Rather than + * provide complex checking for compiler and system, default implementations + * are provided with the ability to redefine actual meaning based upon + * macros. This can be accomplished in a separate header file that first defines + * the macros and then includes this header, or by defining macro values on + * a project level. + */ + +/** Unsigned integer numbers */ +#ifdef ICUINT8TYPE +typedef ICUINT8TYPE icUInt8Number; +#else +typedef unsigned char icUInt8Number; +#endif + +#ifdef ICUINT16TYPE +typedef ICUINT16TYPE icUInt16Number; +#else +typedef unsigned short icUInt16Number; +#endif + +#ifdef ICUINT32TYPE +typedef ICUINT32TYPE icUInt32Number; +#else +typedef unsigned long icUInt32Number; +#endif + +#ifdef ICUINT64TYPE +typedef ICUINT64TYPE icUInt64Number; +#else +typedef icUInt32Number icUInt64Number[2]; +#endif + +typedef icUInt32Number icSignature; + + +/** Signed numbers */ +#ifdef ICINT8TYPE +typedef ICINT8TYPE icInt8Number; +#else +typedef char icInt8Number; +#endif + +#ifdef ICINT16TYPE +typedef ICINT16TYPE icInt16Number; +#else +typedef short icInt16Number; +#endif + +#ifdef ICINT32TYPE +typedef ICINT32TYPE icInt32Number; +#else +typedef long icInt32Number; +#endif + +#ifdef ICINT64TYPE +typedef ICINT64TYPE icInt64Number; +#else +typedef icInt32Number icInt64Number[2]; +#endif + + +/** Fixed numbers */ +typedef icInt32Number icS15Fixed16Number; +typedef icUInt32Number icU16Fixed16Number; + + +/** IEEE float storage numbers */ +typedef float icFloat32Number; +typedef double icFloat64Number; + +/** Useful macros for defining Curve Segment breakpoints **/ +#define icMaxFloat32Number 3.402823466e+38F +#define icMinFloat32Number -3.402823466e+38F + +/** 16-bit unicode characters **/ +typedef icUInt16Number icUnicodeChar; + +/*------------------------------------------------------------------------*/ + +/** + * public tags and sizes + */ +typedef enum { + icSigAToB0Tag = 0x41324230, /* 'A2B0' */ + icSigAToB1Tag = 0x41324231, /* 'A2B1' */ + icSigAToB2Tag = 0x41324232, /* 'A2B2' */ + icSigBlueColorantTag = 0x6258595A, /* 'bXYZ' */ + icSigBlueMatrixColumnTag = 0x6258595A, /* 'bXYZ' */ + icSigBlueTRCTag = 0x62545243, /* 'bTRC' */ + icSigBToA0Tag = 0x42324130, /* 'B2A0' */ + icSigBToA1Tag = 0x42324131, /* 'B2A1' */ + icSigBToA2Tag = 0x42324132, /* 'B2A2' */ + icSigCalibrationDateTimeTag = 0x63616C74, /* 'calt' */ + icSigCharTargetTag = 0x74617267, /* 'targ' */ + icSigChromaticAdaptationTag = 0x63686164, /* 'chad' */ + icSigChromaticityTag = 0x6368726D, /* 'chrm' */ + icSigColorantOrderTag = 0x636C726F, /* 'clro' */ + icSigColorantTableTag = 0x636C7274, /* 'clrt' */ + icSigColorantTableOutTag = 0x636C6F74, /* 'clot' */ + icSigColorimetricIntentImageStateTag = 0x63696973, /* 'ciis' */ + icSigCopyrightTag = 0x63707274, /* 'cprt' */ + icSigCrdInfoTag = 0x63726469, /* 'crdi' Removed in V4 */ + icSigDataTag = 0x64617461, /* 'data' Removed in V4 */ + icSigDateTimeTag = 0x6474696D, /* 'dtim' Removed in V4 */ + icSigDeviceMfgDescTag = 0x646D6E64, /* 'dmnd' */ + icSigDeviceModelDescTag = 0x646D6464, /* 'dmdd' */ + icSigDeviceSettingsTag = 0x64657673, /* 'devs' Removed in V4 */ + icSigDToB0Tag = 0x44324230, /* 'D2B0' */ + icSigDToB1Tag = 0x44324231, /* 'D2B1' */ + icSigDToB2Tag = 0x44324232, /* 'D2B2' */ + icSigDToB3Tag = 0x44324233, /* 'D2B3' */ + icSigBToD0Tag = 0x42324430, /* 'B2D0' */ + icSigBToD1Tag = 0x42324431, /* 'B2D1' */ + icSigBToD2Tag = 0x42324432, /* 'B2D2' */ + icSigBToD3Tag = 0x42324433, /* 'B2D3' */ + icSigGamutTag = 0x67616D74, /* 'gamt' */ + icSigGrayTRCTag = 0x6b545243, /* 'kTRC' */ + icSigGreenColorantTag = 0x6758595A, /* 'gXYZ' */ + icSigGreenMatrixColumnTag = 0x6758595A, /* 'gXYZ' */ + icSigGreenTRCTag = 0x67545243, /* 'gTRC' */ + icSigLuminanceTag = 0x6C756d69, /* 'lumi' */ + icSigMeasurementTag = 0x6D656173, /* 'meas' */ + icSigMediaBlackPointTag = 0x626B7074, /* 'bkpt' */ + icSigMediaWhitePointTag = 0x77747074, /* 'wtpt' */ + icSigMetaDataTag = 0x6D657461, /* 'meta' */ +#if 0 + icSigNamedColorTag = 0x6E636f6C, /* 'ncol' OBSOLETE, use ncl2 */ +#endif + icSigNamedColor2Tag = 0x6E636C32, /* 'ncl2' */ + icSigOutputResponseTag = 0x72657370, /* 'resp' */ + icSigPerceptualRenderingIntentGamutTag = 0x72696730, /* 'rig0' */ + icSigPreview0Tag = 0x70726530, /* 'pre0' */ + icSigPreview1Tag = 0x70726531, /* 'pre1' */ + icSigPreview2Tag = 0x70726532, /* 'pre2' */ + icSigPrintConditionTag = 0x7074636e, /* 'ptcn' */ + icSigProfileDescriptionTag = 0x64657363, /* 'desc' */ + icSigProfileSequenceDescTag = 0x70736571, /* 'pseq' */ + icSigProfileSequceIdTag = 0x70736964, /* 'psid' */ + icSigPs2CRD0Tag = 0x70736430, /* 'psd0' Removed in V4 */ + icSigPs2CRD1Tag = 0x70736431, /* 'psd1' Removed in V4 */ + icSigPs2CRD2Tag = 0x70736432, /* 'psd2' Removed in V4 */ + icSigPs2CRD3Tag = 0x70736433, /* 'psd3' Removed in V4 */ + icSigPs2CSATag = 0x70733273, /* 'ps2s' Removed in V4 */ + icSigPs2RenderingIntentTag = 0x70733269, /* 'ps2i' Removed in V4 */ + icSigRedColorantTag = 0x7258595A, /* 'rXYZ' */ + icSigRedMatrixColumnTag = 0x7258595A, /* 'rXYZ' */ + icSigRedTRCTag = 0x72545243, /* 'rTRC' */ + icSigSaturationRenderingIntentGamutTag = 0x72696732, /* 'rig2' */ + icSigScreeningDescTag = 0x73637264, /* 'scrd' Removed in V4 */ + icSigScreeningTag = 0x7363726E, /* 'scrn' Removed in V4 */ + icSigTechnologyTag = 0x74656368, /* 'tech' */ + icSigUcrBgTag = 0x62666420, /* 'bfd ' Removed in V4 */ + icSigViewingCondDescTag = 0x76756564, /* 'vued' */ + icSigViewingConditionsTag = 0x76696577, /* 'view' */ +} icTagSignature; + +/** Convenience Enum Definitions - Not defined in ICC specification*/ +#define icSigUnknownTag ((icTagSignature) 0x3f3f3f3f) /* '????' */ +#define icMaxEnumTag ((icTagSignature) 0xFFFFFFFF) + + + +/** + * technology signature descriptions + */ +typedef enum { + icSigDigitalCamera = 0x6463616D, /* 'dcam' */ + icSigFilmScanner = 0x6673636E, /* 'fscn' */ + icSigReflectiveScanner = 0x7273636E, /* 'rscn' */ + icSigInkJetPrinter = 0x696A6574, /* 'ijet' */ + icSigThermalWaxPrinter = 0x74776178, /* 'twax' */ + icSigElectrophotographicPrinter = 0x6570686F, /* 'epho' */ + icSigElectrostaticPrinter = 0x65737461, /* 'esta' */ + icSigDyeSublimationPrinter = 0x64737562, /* 'dsub' */ + icSigPhotographicPaperPrinter = 0x7270686F, /* 'rpho' */ + icSigFilmWriter = 0x6670726E, /* 'fprn' */ + icSigVideoMonitor = 0x7669646D, /* 'vidm' */ + icSigVideoCamera = 0x76696463, /* 'vidc' */ + icSigProjectionTelevision = 0x706A7476, /* 'pjtv' */ + icSigCRTDisplay = 0x43525420, /* 'CRT ' */ + icSigPMDisplay = 0x504D4420, /* 'PMD ' */ + icSigAMDisplay = 0x414D4420, /* 'AMD ' */ + icSigPhotoCD = 0x4B504344, /* 'KPCD' */ + icSigPhotoImageSetter = 0x696D6773, /* 'imgs' */ + icSigGravure = 0x67726176, /* 'grav' */ + icSigOffsetLithography = 0x6F666673, /* 'offs' */ + icSigSilkscreen = 0x73696C6B, /* 'silk' */ + icSigFlexography = 0x666C6578, /* 'flex' */ + icSigMotionPictureFilmScanner = 0x6D706673, /* 'mpfs' */ + icSigMotionPictureFilmRecorder = 0x6D706672, /* 'mpfr' */ + icSigDigitalMotionPictureCamera = 0x646D7063, /* 'dmpc' */ + icSigDigitalCinemaProjector = 0x64636A70, /* 'dcpj' */ +} icTechnologySignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumTechnology ((icTechnologySignature) 0xFFFFFFFF) + +/** + * type signatures + */ +typedef enum { + icSigChromaticityType = 0x6368726D, /* 'chrm' */ + icSigColorantOrderType = 0x636C726F, /* 'clro' */ + icSigColorantTableType = 0x636C7274, /* 'clrt' */ + icSigCrdInfoType = 0x63726469, /* 'crdi' Removed in V4 */ + icSigCurveType = 0x63757276, /* 'curv' */ + icSigDataType = 0x64617461, /* 'data' */ + icSigDictType = 0x64696374, /* 'dict' */ + icSigDateTimeType = 0x6474696D, /* 'dtim' */ + icSigDeviceSettingsType = 0x64657673, /* 'devs' Removed in V4 */ + icSigLut16Type = 0x6d667432, /* 'mft2' */ + icSigLut8Type = 0x6d667431, /* 'mft1' */ + icSigLutAtoBType = 0x6d414220, /* 'mAB ' */ + icSigLutBtoAType = 0x6d424120, /* 'mBA ' */ + icSigMeasurementType = 0x6D656173, /* 'meas' */ + icSigMultiLocalizedUnicodeType = 0x6D6C7563, /* 'mluc' */ + icSigMultiProcessElementType = 0x6D706574, /* 'mpet' */ +#if 0 + icSigNamedColorType = 0x6E636f6C, /* 'ncol' OBSOLETE, use ncl2 */ +#endif + icSigNamedColor2Type = 0x6E636C32, /* 'ncl2' */ + icSigParametricCurveType = 0x70617261, /* 'para' */ + icSigProfileSequenceDescType = 0x70736571, /* 'pseq' */ + icSigProfileSequceIdType = 0x70736964, /* 'psid' */ + icSigResponseCurveSet16Type = 0x72637332, /* 'rcs2' */ + icSigS15Fixed16ArrayType = 0x73663332, /* 'sf32' */ + icSigScreeningType = 0x7363726E, /* 'scrn' Removed in V4 */ + icSigSignatureType = 0x73696720, /* 'sig ' */ + icSigTextType = 0x74657874, /* 'text' */ + icSigTextDescriptionType = 0x64657363, /* 'desc' Removed in V4 */ + icSigU16Fixed16ArrayType = 0x75663332, /* 'uf32' */ + icSigUcrBgType = 0x62666420, /* 'bfd ' Removed in V4 */ + icSigUInt16ArrayType = 0x75693136, /* 'ui16' */ + icSigUInt32ArrayType = 0x75693332, /* 'ui32' */ + icSigUInt64ArrayType = 0x75693634, /* 'ui64' */ + icSigUInt8ArrayType = 0x75693038, /* 'ui08' */ + icSigViewingConditionsType = 0x76696577, /* 'view' */ + icSigXYZType = 0x58595A20, /* 'XYZ ' */ + icSigXYZArrayType = 0x58595A20, /* 'XYZ ' */ +} icTagTypeSignature; + +/** Convenience Enum Definitions - Not defined in ICC specification*/ +#define icSigUnknownType ((icTagTypeSignature) 0x3f3f3f3f) /* '????' */ +#define icMaxEnumType ((icTagTypeSignature) 0xFFFFFFFF) + +/** + * Element type signatures + */ +typedef enum { + //DMP Proposal 1.0 elements + icSigCurveSetElemType = 0x63767374, /* 'cvst' */ + icSigMatrixElemType = 0x6D617466, /* 'matf' */ + icSigCLutElemType = 0x636C7574, /* 'clut' */ + icSigBAcsElemType = 0x62414353, /* 'bACS' */ + icSigEAcsElemType = 0x65414353, /* 'eACS' */ +} icElemTypeSignature; +/** Convenience Enum Definitions - Not defined in proposal*/ +#define icSigUnknownElemType ((icElemTypeSignature) 0x3f3f3f3f) /* '????' */ +#define icMaxEnumElemType ((icElemTypeSignature) 0xFFFFFFFF) + + +/** + * Color Space Signatures. + * Note that only icSigXYZData and icSigLabData are valid + * Profile Connection Spaces (PCSs) + */ +typedef enum { + icSigXYZData = 0x58595A20, /* 'XYZ ' */ + icSigLabData = 0x4C616220, /* 'Lab ' */ + icSigLuvData = 0x4C757620, /* 'Luv ' */ + icSigYCbCrData = 0x59436272, /* 'YCbr' */ + icSigYxyData = 0x59787920, /* 'Yxy ' */ + icSigRgbData = 0x52474220, /* 'RGB ' */ + icSigGrayData = 0x47524159, /* 'GRAY' */ + icSigHsvData = 0x48535620, /* 'HSV ' */ + icSigHlsData = 0x484C5320, /* 'HLS ' */ + icSigCmykData = 0x434D594B, /* 'CMYK' */ + icSigCmyData = 0x434D5920, /* 'CMY ' */ + + icSigMCH2Data = 0x32434C52, /* '2CLR' */ + icSigMCH3Data = 0x33434C52, /* '3CLR' */ + icSigMCH4Data = 0x34434C52, /* '4CLR' */ + icSigMCH5Data = 0x35434C52, /* '5CLR' */ + icSigMCH6Data = 0x36434C52, /* '6CLR' */ + icSigMCH7Data = 0x37434C52, /* '7CLR' */ + icSigMCH8Data = 0x38434C52, /* '8CLR' */ + icSigMCH9Data = 0x39434C52, /* '9CLR' */ + icSigMCHAData = 0x41434C52, /* 'ACLR' */ + icSigMCHBData = 0x42434C52, /* 'BCLR' */ + icSigMCHCData = 0x43434C52, /* 'CCLR' */ + icSigMCHDData = 0x44434C52, /* 'DCLR' */ + icSigMCHEData = 0x45434C52, /* 'ECLR' */ + icSigMCHFData = 0x46434C52, /* 'FCLR' */ + icSigNamedData = 0x6e6d636c, /* 'nmcl' */ + + icSig2colorData = 0x32434C52, /* '2CLR' */ + icSig3colorData = 0x33434C52, /* '3CLR' */ + icSig4colorData = 0x34434C52, /* '4CLR' */ + icSig5colorData = 0x35434C52, /* '5CLR' */ + icSig6colorData = 0x36434C52, /* '6CLR' */ + icSig7colorData = 0x37434C52, /* '7CLR' */ + icSig8colorData = 0x38434C52, /* '8CLR' */ + icSig9colorData = 0x39434C52, /* '9CLR' */ + icSig10colorData = 0x41434C52, /* 'ACLR' */ + icSig11colorData = 0x42434C52, /* 'BCLR' */ + icSig12colorData = 0x43434C52, /* 'CCLR' */ + icSig13colorData = 0x44434C52, /* 'DCLR' */ + icSig14colorData = 0x45434C52, /* 'ECLR' */ + icSig15colorData = 0x46434C52, /* 'FCLR' */ + +} icColorSpaceSignature; + +/** Defined by previous versions of header file but not defined in ICC specification */ +#define icSigMCH1Data ((icColorSpaceSignature) 0x31434C52) /* '1CLR' */ +#define icSigMCHGData ((icColorSpaceSignature) 0x47434C52) /* 'GCLR' */ +#define icSig1colorData ((icColorSpaceSignature) 0x31434C52) /* '1CLR' */ +#define icSig16colorData ((icColorSpaceSignature) 0x47434C52) /* 'GCLR' */ + +/** Defined by LittleCMS **/ + +/** Convenience Enum Definitions - Not defined in ICC specification*/ +#define icSigGamutData ((icColorSpaceSignature) 0x67616D74) /* 'gamt' */ +#define icSigUnknownData ((icColorSpaceSignature) 0x3f3f3f3f) /* '????' */ +#define icMaxEnumData ((icColorSpaceSignature) 0xFFFFFFFF) + + + +/** profileClass enumerations */ +typedef enum { + icSigInputClass = 0x73636E72, /* 'scnr' */ + icSigDisplayClass = 0x6D6E7472, /* 'mntr' */ + icSigOutputClass = 0x70727472, /* 'prtr' */ + icSigLinkClass = 0x6C696E6B, /* 'link' */ + icSigAbstractClass = 0x61627374, /* 'abst' */ + icSigColorSpaceClass = 0x73706163, /* 'spac' */ + icSigNamedColorClass = 0x6e6d636c, /* 'nmcl' */ +} icProfileClassSignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumClass ((icProfileClassSignature) 0xFFFFFFFF) + + + +/** Platform Signatures */ +typedef enum { + icSigMacintosh = 0x4150504C, /* 'APPL' */ + icSigMicrosoft = 0x4D534654, /* 'MSFT' */ + icSigSolaris = 0x53554E57, /* 'SUNW' */ + icSigSGI = 0x53474920, /* 'SGI ' */ + icSigTaligent = 0x54474E54, /* 'TGNT' */ + icSigUnkownPlatform = 0x00000000 +} icPlatformSignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumPlatform ((icPlatformSignature) 0xFFFFFFFF) + + +/** CMM signatures from the signature registry (as of Jan 10, 2007) */ +typedef enum { + icSigAdobe = 0x41444245, /* 'ADBE' */ + icSigApple = 0x6170706C, /* 'appl' */ + icSigColorGear = 0x43434D53, /* 'CCMS' */ + icSigColorGearLite = 0x5543434D, /* 'UCCM' */ + icSigFujiFilm = 0x46462020, /* 'FF ' */ + icSigHarlequinRIP = 0x48434d4d, /* 'HCMM' */ + icSigArgyllCMS = 0x6172676C, /* 'argl' */ + icSigLogoSync = 0x44676f53, /* 'LgoS' */ + icSigHeidelberg = 0x48444d20, /* 'HDM ' */ + icSigLittleCMS = 0x6C636d73, /* 'lcms' */ + icSigKodak = 0x4b434d53, /* 'KCMS' */ + icSigKonicaMinolta = 0x4d434d44, /* 'MCML' */ + icSigMutoh = 0x5349474E, /* 'SIGN' */ + icSigSampleICC = 0x53494343, /* 'SICC' */ + icSigTheImagingFactory = 0x33324254, /* '32BT' */ +} icCmmSignature; +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumCmm ((icCmmSignature) 0xFFFFFFFF) + + +/** Rendering Intent Gamut Signatures */ +typedef enum { + icSigPerceptualReferenceMediumGamut = 0x70726d67, /* 'prmg' */ +} icReferenceMediumGamutSignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumReferenceMediumGamut ((icReferenceMediumGamutSignature 0xFFFFFFFF) + + +/** Colorimetric Intent Image State Gamut Signatures */ +typedef enum { + icSigSceneColorimetryEstimates = 0x73636F65, /* 'scoe' */ + icSigSceneAppearanceEstimates = 0x73617065, /* 'sape' */ + icSigFocalPlaneColorimetryEstimates = 0x66706365, /* 'fpce' */ + icSigReflectionHardcopyOriginalColorimetry = 0x72686F63, /* 'rhoc' */ + icSigReflectionPrintOutputColorimetry = 0x72706F63, /* 'rpoc' */ +} icColorimetricIntentImageStateSignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumColorimetricIntentImageState ((icColorimetricIntentImageStateSignature 0xFFFFFFFF) + + +/** + * MPE Curve segment Signatures + */ +typedef enum { + icSigFormulaCurveSeg = 0x70617266, /* 'parf' */ + icSigSampledCurveSeg = 0x73616D66, /* 'samf' */ +} icCurveSegSignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxCurveSegSignature ((icCurveSegSignature 0xFFFFFFFF) + +/** + * MPE Curve Set Curve signature + */ +typedef enum { + icSigSementedCurve = 0x63757266, /* 'curf' */ +} icCurveElemSignature; + +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxCurveElemSignature ((icCurveElemSignature 0xFFFFFFFF) + +/** + * MPE Future Extension Acs signature + */ + +typedef icSignature icAcsSignature; + +/** Convenience Definition - Not defined in ICC specification*/ +#define icSigAcsZero ((icAcsSignature) 0x00000000) + +/*------------------------------------------------------------------------*/ + +/** + * Other enums + */ + +/** Measurement Flare, used in the measurmentType tag */ +typedef enum { + icFlare0 = 0x00000000, /* 0% flare */ + icFlare100 = 0x00000001, /* 100% flare */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumFlare = 0xFFFFFFFF, + icMaxFlare = 0xFFFFFFFF, /* as defined by earlier versions */ +#endif +} icMeasurementFlare; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumFlare ((icMeasurementFlare) 0xFFFFFFFF) +#define icMaxFlare ((icMeasurementFlare) 0xFFFFFFFF) /* as defined by earlier versions */ +#endif + + +/** Measurement Geometry, used in the measurmentType tag */ +typedef enum { + icGeometryUnknown = 0x00000000, /* Unknown geometry */ + icGeometry045or450 = 0x00000001, /* 0/45, 45/0 */ + icGeometry0dord0 = 0x00000002, /* 0/d or d/0 */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumGeometry = 0xFFFFFFFF, + icMaxGeometry = 0xFFFFFFFF, +#endif +} icMeasurementGeometry; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumGeometry ((icMeasurementGeometry) 0xFFFFFFFF) +#define icMaxGeometry ((icMeasurementGeometry) 0xFFFFFFFF) +#endif + + +/** Rendering Intents, used in the profile header */ +typedef enum { + icPerceptual = 0, + icRelativeColorimetric = 1, + icSaturation = 2, + icAbsoluteColorimetric = 3, + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definitions - Not defined in ICC specification*/ + icUnknownIntent = 0x3f3f3f3f, /* '????' */ + icMaxEnumIntent = 0xFFFFFFFF, +#endif +} icRenderingIntent; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definitions - Not defined in ICC specification*/ +#define icUnknownIntent ((icRenderingIntent) 0x3f3f3f3f) /* '????' */ +#define icMaxEnumIntent ((icRenderingIntent) 0xFFFFFFFF) +#endif + + + +/** Different Spot Shapes currently defined, used for screeningType */ +typedef enum { + icSpotShapeUnknown = 0, + icSpotShapePrinterDefault = 1, + icSpotShapeRound = 2, + icSpotShapeDiamond = 3, + icSpotShapeEllipse = 4, + icSpotShapeLine = 5, + icSpotShapeSquare = 6, + icSpotShapeCross = 7, + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumSpot = 0xFFFFFFFF, +#endif +} icSpotShape; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumSpot ((icSpotShape) 0xFFFFFFFF) +#endif + + + +/** Standard Observer, used in the measurmentType tag */ +typedef enum { + icStdObsUnknown = 0x00000000, /* Unknown observer */ + icStdObs1931TwoDegrees = 0x00000001, /* 1931 two degrees */ + icStdObs1964TenDegrees = 0x00000002, /* 1961 ten degrees */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definitions - Not defined in ICC specification*/ + icMaxEnumStdObs = 0xFFFFFFFF, + icMaxStdObs = 0xFFFFFFFF, +#endif +} icStandardObserver; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumStdObs ((icStandardObserver) 0xFFFFFFFF) +#define icMaxStdObs ((icStandardObserver) 0xFFFFFFFF) /* as defined by earlier versions */ +#endif + + + +/** Pre-defined illuminants, used in measurement and viewing conditions type */ +typedef enum { + icIlluminantUnknown = 0x00000000, + icIlluminantD50 = 0x00000001, + icIlluminantD65 = 0x00000002, + icIlluminantD93 = 0x00000003, + icIlluminantF2 = 0x00000004, + icIlluminantD55 = 0x00000005, + icIlluminantA = 0x00000006, + icIlluminantEquiPowerE = 0x00000007, /* Equi-Power (E) */ + icIlluminantF8 = 0x00000008, + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definitions - Not defined in ICC specification*/ + icMaxEnumIlluminant = 0xFFFFFFFF, + icMaxEnumIluminant = 0xFFFFFFFF, /* as defined by earlier versions */ +#endif +} icIlluminant; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definitions - Not defined in ICC specification*/ +#define icMaxEnumIlluminant ((icIlluminant) 0xFFFFFFFF) +#define icMaxEnumIluminant ((icIlluminant) 0xFFFFFFFF) /* as defined by earlier versions */ +#endif + + + +/** A not so exhaustive list of language codes */ +typedef enum { + icLanguageCodeEnglish = 0x656E, /* 'en' */ + icLanguageCodeGerman = 0x6465, /* 'de' */ + icLanguageCodeItalian = 0x6974, /* 'it' */ + icLanguageCodeDutch = 0x6E6C, /* 'nl' */ + icLanguageCodeSweden = 0x7376, /* 'sv' */ + icLanguageCodeSpanish = 0x6573, /* 'es' */ + icLanguageCodeDanish = 0x6461, /* 'da' */ + icLanguageCodeNorwegian = 0x6E6F, /* 'no' */ + icLanguageCodeJapanese = 0x6A61, /* 'ja' */ + icLanguageCodeFinnish = 0x6669, /* 'fi' */ + icLanguageCodeTurkish = 0x7472, /* 'tr' */ + icLanguageCodeKorean = 0x6B6F, /* 'ko' */ + icLanguageCodeChinese = 0x7A68, /* 'zh' */ + icLanguageCodeFrench = 0x6672, /* 'fr' */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumLanguageCode = 0xFFFF, +#endif +} icEnumLanguageCode; +typedef icUInt16Number icLanguageCode; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumLanguageCode ((icEnumLanguageCode) 0xFFFF) +#endif + + + +/** +* A not so exhaustive list of country codes. + * Helpful website: http://dev.krook.org ld.html */ +typedef enum { + icCountryCodeUSA = 0x5553, /* 'US' */ + icCountryCodeUnitedKingdom = 0x554B, /* 'UK' */ + icCountryCodeGermany = 0x4445, /* 'DE' */ + icCountryCodeItaly = 0x4954, /* 'IT' */ + icCountryCodeNetherlands = 0x4E4C, /* 'NL' */ + icCountryCodeSpain = 0x4543, /* 'ES' */ + icCountryCodeDenmark = 0x444B, /* 'DK' */ + icCountryCodeNorway = 0x4E4F, /* 'NO' */ + icCountryCodeJapan = 0x4A50, /* 'JP' */ + icCountryCodeFinland = 0x4649, /* 'FI' */ + icCountryCodeTurkey = 0x5452, /* 'TR' */ + icCountryCodeKorea = 0x4B52, /* 'KR' */ + icCountryCodeChina = 0x434E, /* 'CN' */ + icCountryCodeTaiwan = 0x5457, /* 'TW' */ + icCountryCodeFrance = 0x4652, /* 'FR' */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumCountryCode = 0xFFFF, +#endif +} icEnumCountryCode; +typedef icUInt16Number icCountryCode; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumCountryCode ((icEnumCountryCode) 0xFFFF) +#endif + + + +/** Measurement Unit Signatures used in ResponseCurveSet16Type */ +typedef enum { + icSigStatusA = 0x53746141, /* 'StaA' */ + icSigStatusE = 0x53746145, /* 'StaE' */ + icSigStatusI = 0x53746149, /* 'StaI' */ + icSigStatusT = 0x53746154, /* 'StaT' */ + icSigStatusM = 0x5374614D, /* 'StaM' */ + icSigDN = 0x444E2020, /* 'DN ' */ + icSigDNP = 0x444E2050, /* 'DN P' */ + icSigDNN = 0x444E4E20, /* 'DNN ' */ + icSigDNNP = 0x444E4E50, /* 'DNNP' */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumMeasurmentUnitSig = 0xffffffff, +#endif +} icMeasurementUnitSig; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumMeasurmentUnitSig ((icMeasurementUnitSig) 0xffffffff) +#endif + + + +/** Colorant and Phosphor Encodings used in chromaticity type */ +typedef enum { + icColorantUnknown = 0x0000, /* Unknown */ + icColorantITU = 0x0001, /* ITU-R BT.709 */ + icColorantSMPTE = 0x0002, /* SMPTE RP145-1994 */ + icColorantEBU = 0x0003, /* EBU Tech.3213-E */ + icColorantP22 = 0x0004, /* P22 */ + +#ifdef ICC_ENUM_CONVENIENCE + /** Convenience Enum Definition - Not defined in ICC specification*/ + icMaxEnumColorant = 0xFFFF, +#endif +} icColorantEncoding; + +#ifndef ICC_ENUM_CONVENIENCE +/** Convenience Enum Definition - Not defined in ICC specification*/ +#define icMaxEnumColorant ((icColorantEncoding) 0xFFFF) +#endif + + +/** + * Note: The next three enum types are for DeviceSettingType structures + * supported by V2 profiles. The DeviceSettingsType was removed in the + * V4 specificaiton.*/ + +/** DeviceSettingsType structure ID signatures for Microsoft 'msft' platform*/ +typedef enum { + icMSFTDevSetResolution = 0x72736C6E, /* 'rsln' */ + icMSFTDevSetMediaType = 0x6D747970, /* 'mtyp' */ + icMSFTDevSetMediaHalftone = 0x6866746E, /* 'hftn' */ + +} icMSFTDevSetSig; + +/** DeviceSettingsType media encodings for Microsoft 'msft' platform */ +typedef enum { + icDMMediaStandard = 0x0001, /* Standard paper */ + icDMMediaTransparancy = 0x0002, /* Transparency */ + icDMMediaGlossy = 0x0003, /* Glossy paper */ + icDMMediaUser = 0x0100, /* Device-specific type media + are >= 256 */ +} icDMMediaType; + +/** DeviceSettingsType media encodings for Microsoft 'msft' platform */ +typedef enum { + icDMDitherNone = 0x0001, /* No dithering */ + icDMDitherCoarse = 0x0002, /* Dither with a coarse brush */ + icDMDitherFine = 0x0003, /* Dither with a fine brush */ + icDMDitherLineArt = 0x0004, /* LineArt dithering */ + icDMDitherErrorDiffusion = 0x0005, /* Error Diffusion */ + icDMDitherReserved6 = 0x0006, + icDMDitherReserved7 = 0x0007, + icDMDitherReserved8 = 0x0008, + icDMDitherReserved9 = 0x0009, + icDMDitherGrayscale = 0x000A, /* Device does grayscaling */ + icDMDitherUser = 0x0100, /* Device-specifice halftones + are >= 256 */ +} icDMHalftoneType; + +/** +*------------------------------------------------------------------------ +* + * Arrays of numbers + */ + +/** Int8 Array */ +typedef struct { + icInt8Number data[icAny]; /* Variable array of values */ +} icInt8Array; + +/** UInt8 Array */ +typedef struct { + icUInt8Number data[icAny]; /* Variable array of values */ +} icUInt8Array; + +/** uInt16 Array */ +typedef struct { + icUInt16Number data[icAny]; /* Variable array of values */ +} icUInt16Array; + +/** Int16 Array */ +typedef struct { + icInt16Number data[icAny]; /* Variable array of values */ +} icInt16Array; + +/** uInt32 Array */ +typedef struct { + icUInt32Number data[icAny]; /* Variable array of values */ +} icUInt32Array; + +/** Int32 Array */ +typedef struct { + icInt32Number data[icAny]; /* Variable array of values */ +} icInt32Array; + +/** UInt64 Array */ +typedef struct { + icUInt64Number data[icAny]; /* Variable array of values */ +} icUInt64Array; + +/** Int64 Array */ +typedef struct { + icInt64Number data[icAny]; /* Variable array of values */ +} icInt64Array; + +/** u16Fixed16 Array */ +typedef struct { + icU16Fixed16Number data[icAny]; /* Variable array of values */ +} icU16Fixed16Array; + +/** s15Fixed16 Array */ +typedef struct { + icS15Fixed16Number data[icAny]; /* Variable array of values */ +} icS15Fixed16Array; + +/** The base date time number */ +typedef struct { + icUInt16Number year; + icUInt16Number month; + icUInt16Number day; + icUInt16Number hours; + icUInt16Number minutes; + icUInt16Number seconds; +} icDateTimeNumber; + +/** XYZ Number */ +typedef struct { + icS15Fixed16Number X; + icS15Fixed16Number Y; + icS15Fixed16Number Z; +} icXYZNumber; + +/** XYZ Array */ +typedef struct { + icXYZNumber data[icAny]; /* Variable array of XYZ numbers */ +} icXYZArray; + +/** xy Chromaticity Number */ +typedef struct { + icU16Fixed16Number x; + icU16Fixed16Number y; +} icChromaticityNumber; + +/** response16Number */ +typedef struct { + icUInt16Number deviceCode; + icUInt16Number reserved; + icS15Fixed16Number measurementValue; +} icResponse16Number; + +/** positionNumber **/ +typedef struct { + icUInt32Number offset; + icUInt32Number size; +} icPositionNumber; + + +/** Curve */ +typedef struct { + icUInt32Number count; /* Number of entries */ + icUInt16Number data[icAny]; /* The actual table data, real + * number is determined by count + * Interpretation depends on how + * data is used with a given tag + */ +} icCurve; + +/** Parametric Curve */ +typedef struct { + icUInt16Number funcType; /* Function Type */ + /* 0 = gamma only */ + icUInt16Number pad; /* Padding for byte alignment */ + icS15Fixed16Number gamma; /* xgamma */ + /* up to 7 values Y,a,b,c,d,e,f */ +} icParametricCurve; + +/** Parametric Curve */ +typedef struct { + icUInt16Number funcType; /* Function Type */ + /* 0 = gamma only */ + icUInt16Number pad; /* Padding for byte alignment */ + icS15Fixed16Number gamma; /* xgamma */ + icS15Fixed16Number a; /* a */ + icS15Fixed16Number b; /* b */ + icS15Fixed16Number c; /* c */ + icS15Fixed16Number d; /* d */ + icS15Fixed16Number e; /* e */ + icS15Fixed16Number f; /* f */ +} icParametricCurveFull; + +/** Data */ +typedef struct { + icUInt32Number dataFlag; /* 0 = ascii, 1 = binary */ + icInt8Number data[icAny]; /* Data, size determined from tag */ +} icData; + +/** lut16 */ +typedef struct { + icUInt8Number inputChan; /* Number of input channels */ + icUInt8Number outputChan; /* Number of output channels */ + icUInt8Number clutPoints; /* Number of clutTable grid points */ + icInt8Number pad; /* Padding for byte alignment */ + icS15Fixed16Number e00; /* e00 in the 3 * 3 */ + icS15Fixed16Number e01; /* e01 in the 3 * 3 */ + icS15Fixed16Number e02; /* e02 in the 3 * 3 */ + icS15Fixed16Number e10; /* e10 in the 3 * 3 */ + icS15Fixed16Number e11; /* e11 in the 3 * 3 */ + icS15Fixed16Number e12; /* e12 in the 3 * 3 */ + icS15Fixed16Number e20; /* e20 in the 3 * 3 */ + icS15Fixed16Number e21; /* e21 in the 3 * 3 */ + icS15Fixed16Number e22; /* e22 in the 3 * 3 */ + icUInt16Number inputEnt; /* Number of input table entries */ + icUInt16Number outputEnt; /* Number of output table entries */ + icUInt16Number data[icAny]; /* Data follows see spec for size */ + /** + * Data that follows is of this form + * + * icUInt16Number inputTable[inputChan][icAny]; * The input table + * icUInt16Number clutTable[icAny]; * The clut table + * icUInt16Number outputTable[outputChan][icAny]; * The output table + */ +} icLut16; + +/** lut8, input & output tables are always 256 bytes in length */ +typedef struct { + icUInt8Number inputChan; /* Number of input channels */ + icUInt8Number outputChan; /* Number of output channels */ + icUInt8Number clutPoints; /* Number of clutTable grid points */ + icInt8Number pad; + icS15Fixed16Number e00; /* e00 in the 3 * 3 */ + icS15Fixed16Number e01; /* e01 in the 3 * 3 */ + icS15Fixed16Number e02; /* e02 in the 3 * 3 */ + icS15Fixed16Number e10; /* e10 in the 3 * 3 */ + icS15Fixed16Number e11; /* e11 in the 3 * 3 */ + icS15Fixed16Number e12; /* e12 in the 3 * 3 */ + icS15Fixed16Number e20; /* e20 in the 3 * 3 */ + icS15Fixed16Number e21; /* e21 in the 3 * 3 */ + icS15Fixed16Number e22; /* e22 in the 3 * 3 */ + icUInt8Number data[icAny]; /* Data follows see spec for size */ + /** + * Data that follows is of this form + * + * icUInt8Number inputTable[inputChan][256]; * The input table + * icUInt8Number clutTable[icAny]; * The clut table + * icUInt8Number outputTable[outputChan][256]; * The output table + */ +} icLut8; + +/** icLutAToB */ +typedef struct { + icUInt8Number gridPoints[16]; /* Number of grid points in each dimension. */ + icUInt8Number prec; /* Precision of data elements in bytes. */ + icUInt8Number pad1; + icUInt8Number pad2; + icUInt8Number pad3; + /*icUInt8Number data[icAny]; Data follows see spec for size */ +} icCLutStruct; + +/** icLutAtoB */ +typedef struct { + icUInt8Number inputChan; /* Number of input channels */ + icUInt8Number outputChan; /* Number of output channels */ + icUInt8Number pad1; + icUInt8Number pad2; + icUInt32Number offsetB; /* Offset to first "B" curve */ + icUInt32Number offsetMat; /* Offset to matrix */ + icUInt32Number offsetM; /* Offset to first "M" curve */ + icUInt32Number offsetC; /* Offset to CLUT */ + icUInt32Number offsetA; /* Offset to first "A" curve */ + /*icUInt8Number data[icAny]; Data follows see spec for size */ +} icLutAtoB; + +/** icLutBtoA */ +typedef struct { + icUInt8Number inputChan; /* Number of input channels */ + icUInt8Number outputChan; /* Number of output channels */ + icUInt8Number pad1; + icUInt8Number pad2; + icUInt32Number offsetB; /* Offset to first "B" curve */ + icUInt32Number offsetMat; /* Offset to matrix */ + icUInt32Number offsetM; /* Offset to first "M" curve */ + icUInt32Number offsetC; /* Offset to CLUT */ + icUInt32Number offsetA; /* Offset to first "A" curve */ + /*icUInt8Number data[icAny]; Data follows see spec for size */ +} icLutBtoA; + +/** Measurement Data */ +typedef struct { + icStandardObserver stdObserver; /* Standard observer */ + icXYZNumber backing; /* XYZ for backing material */ + icMeasurementGeometry geometry; /* Measurement geometry */ + icMeasurementFlare flare; /* Measurement flare */ + icIlluminant illuminant; /* Illuminant */ +} icMeasurement; + +/** + * Named color + */ + +/** Entry format for each named color */ +typedef struct { + icUInt8Number rootName[32]; /* Root name for first color */ + icUInt16Number pcsCoords[3]; /* PCS coordinates of color (only Lab or XYZ allowed)*/ + icUInt16Number deviceCoords[icAny]; /* Device coordinates of color */ +} icNamedColor2Entry; + +/** + * icNamedColor2 takes the place of icNamedColor + */ +typedef struct { + icUInt32Number vendorFlag; /* Bottom 16 bits for IC use */ + icUInt32Number count; /* Count of named colors */ + icUInt32Number nDeviceCoords; /* Number of device coordinates */ + icInt8Number prefix[32]; /* Prefix for each color name */ + icInt8Number suffix[32]; /* Suffix for each color name */ + icInt8Number data[icAny]; /* Named color data follows */ + /** + * Data that follows is of this form + * + * icInt8Number root1[32]; * Root name for first color + * icUInt16Number pcsCoords1[icAny]; * PCS coordinates of first color + * icUInt16Number deviceCoords1[icAny]; * Device coordinates of first color + * icInt8Number root2[32]; * Root name for second color + * icUInt16Number pcsCoords2[icAny]; * PCS coordinates of first color + * icUInt16Number deviceCoords2[icAny]; * Device coordinates of first color + * : + * : + * + * Alternatively written if byte packing is assumed with no padding between + * structures then data can take the following form + * + * icNamedColor2Entry entry0; // Entry for first color + * icNamedColor2Entry entry1; // Entry for second color + * : + * : + * In either case repeat for name and PCS and device color coordinates up to (count-1) + * + * NOTES: + * PCS and device space can be determined from the header. + * + * PCS coordinates are icUInt16 numbers and are described in Annex A of + * the ICC spec. Only 16 bit L*a*b* and XYZ are allowed. The number of + * coordinates is consistent with the headers PCS. + * + * Device coordinates are icUInt16 numbers where 0x0000 represents + * the minimum value and 0xFFFF represents the maximum value. + * If the nDeviceCoords value is 0 this field is not given. + */ +} icNamedColor2; + +/** Profile sequence structure */ +typedef struct { + icSignature deviceMfg; /* Device Manufacturer */ + icSignature deviceModel; /* Decvice Model */ + icUInt64Number attributes; /* Device attributes */ + icTechnologySignature technology; /* Technology signature */ + icInt8Number data[icAny]; /* Descriptions text follows */ + /** + * Data that follows is of this form, this is an icInt8Number + * to avoid problems with a compiler generating bad code as + * these arrays are variable in length. + * + * icTextDescription deviceMfgDesc; * Manufacturer text + * icTextDescription modelDesc; * Model text + */ +} icDescStruct; + +/** Profile sequence description */ +typedef struct { + icUInt32Number count; /* Number of descriptions */ + icUInt8Number data[icAny]; /* Array of description struct */ +} icProfileSequenceDesc; + +/** textDescription */ +typedef struct { + icUInt32Number count; /* Description length */ + icInt8Number data[icAny]; /* Descriptions follow */ + /** + * Data that follows is of this form + * + * icInt8Number desc[count] * NULL terminated ascii string + * icUInt32Number ucLangCode; * UniCode language code + * icUInt32Number ucCount; * UniCode description length + * icInt16Number ucDesc[ucCount];* The UniCode description + * icUInt16Number scCode; * ScriptCode code + * icUInt8Number scCount; * ScriptCode count + * icInt8Number scDesc[67]; * ScriptCode Description + */ +} icTextDescription; + +/** Screening Data */ +typedef struct { + icS15Fixed16Number frequency; /* Frequency */ + icS15Fixed16Number angle; /* Screen angle */ + icSpotShape spotShape; /* Spot Shape encodings below */ +} icScreeningData; + +/** screening */ +typedef struct { + icUInt32Number screeningFlag; /* Screening flag */ + icUInt32Number channels; /* Number of channels */ + icScreeningData data[icAny]; /* Array of screening data */ +} icScreening; + +/** Text Data */ +typedef struct { + icInt8Number data[icAny]; /* Variable array of characters */ +} icText; + +/** Structure describing either a UCR or BG curve */ +typedef struct { + icUInt32Number count; /* Curve length */ + icUInt16Number curve[icAny]; /* The array of curve values */ +} icUcrBgCurve; + +/** Under color removal, black generation */ +typedef struct { + icInt8Number data[icAny]; /* The Ucr BG data */ + /** + * Data that follows is of this form, this is a icInt8Number + * to avoid problems with a compiler generating bad code as + * these arrays are variable in length. + * + * icUcrBgCurve ucr; * Ucr curve + * icUcrBgCurve bg; * Bg curve + * icInt8Number string; * UcrBg description + */ +} icUcrBg; + +/** viewingConditionsType */ +typedef struct { + icXYZNumber illuminant; /* In candelas per metre sq'd */ + icXYZNumber surround; /* In candelas per metre sq'd */ + icIlluminant stdIluminant; /* See icIlluminant defines */ +} icViewingCondition; + +/** CrdInfo type */ +typedef struct { + icUInt32Number count; /* Char count includes NULL */ + icInt8Number desc[icAny]; /* Null terminated string */ +} icCrdInfo; + +/** ColorantOrder type */ +typedef struct { + icUInt32Number count; /* Count of colorants */ + icUInt8Number data[icAny]; /* One-based number of the + colorant to be printed first, + second... */ +} icColorantOrder; + +/** ColorantTable Entry */ +typedef struct { + icInt8Number name[32]; /* First colorant name */ + icUInt16Number data[3]; /* 16 bit PCS Lab value for first */ +} icColorantTableEntry; + +/** ColorantTable */ +typedef struct { + icUInt32Number count; /* Count of colorants */ + icColorantTableEntry entry[icAny]; /* N colorant entries */ +} icColorantTable; + +/*------------------------------------------------------------------------*/ + +/** + * Tag Type definitions + */ + + +/** The base part of each tag */ +typedef struct { + icTagTypeSignature sig; /* Signature */ + icInt8Number reserved[4]; /* Reserved, set to 0 */ +} icTagBase; + +/** curveType */ +typedef struct { + icTagBase base; /* Signature, "curv" */ + icCurve curve; /* The curve data */ +} icCurveType; + +/** ParametricCurveType */ +typedef struct { + icTagBase base; /* Signature, "para" */ + icParametricCurve curve; /* The Parametric curve data*/ +} icParametricCurveType; + +/** ParametricCurveFullType */ +typedef struct { + icTagBase base; /* Signature, "para" */ + icParametricCurveFull curve; /* The Parametric curve data*/ +} icParametricCurveFullType; + +/** dataType */ +typedef struct { + icTagBase base; /* Signature, "data" */ + icData data; /* The data structure */ +} icDataType; + +/** dateTimeType */ +typedef struct { + icTagBase base; /* Signature, "dtim" */ + icDateTimeNumber date; /* The date */ +} icDateTimeType; + +/** lut16Type */ +typedef struct { + icTagBase base; /* Signature, "mft2" */ + icLut16 lut; /* Lut16 data */ +} icLut16Type; + +/** lut8Type, input & output tables are always 256 bytes in length */ +typedef struct { + icTagBase base; /* Signature, "mft1" */ + icLut8 lut; /* Lut8 data */ +} icLut8Type; + +/** lutAtoBType new format */ +typedef struct { + icTagBase base; /* Signature, "mAB " */ + icLutAtoB lut; /* icLutAtoB data */ +} icLutAtoBType; + +/** lutBtoAType new format */ +typedef struct { + icTagBase base; /* Signature, "mBA " */ + icLutBtoA lut; /* icLutBtoA data */ +} icLutBtoAType; + +/** Measurement Type */ +typedef struct { + icTagBase base; /* Signature, "meas" */ + icMeasurement measurement; /* Measurement data */ +} icMeasurementType; + +/** + * Named color type + */ + +/** icNamedColor2Type, replaces icNamedColorType */ +typedef struct { + icTagBase base; /* Signature, "ncl2" */ + icNamedColor2 ncolor; /* Named color data */ +} icNamedColor2Type; + +/** Profile sequence description type */ +typedef struct { + icTagBase base; /* Signature, "pseq" */ + icProfileSequenceDesc desc; /* The seq description */ +} icProfileSequenceDescType; + +/** textDescriptionType */ +typedef struct { + icTagBase base; /* Signature, "desc" */ + icTextDescription desc; /* The description */ +} icTextDescriptionType; + +/** s15Fixed16Type */ +typedef struct { + icTagBase base; /* Signature, "sf32" */ + icS15Fixed16Array data; /* Array of values */ +} icS15Fixed16ArrayType; + +/** screeningType */ +typedef struct { + icTagBase base; /* Signature, "scrn" */ + icScreening screen; /* Screening structure */ +} icScreeningType; + +/** sigType */ +typedef struct { + icTagBase base; /* Signature, "sig" */ + icSignature signature; /* The signature data */ +} icSignatureType; + +/** textType */ +typedef struct { + icTagBase base; /* Signature, "text" */ + icText data; /* Variable array of characters */ +} icTextType; + +/** u16Fixed16Type */ +typedef struct { + icTagBase base; /* Signature, "uf32" */ + icU16Fixed16Array data; /* Variable array of values */ +} icU16Fixed16ArrayType; + +/** Under color removal, black generation type */ +typedef struct { + icTagBase base; /* Signature, "bfd " */ + icUcrBg data; /* ucrBg structure */ +} icUcrBgType; + +/** uInt16Type */ +typedef struct { + icTagBase base; /* Signature, "ui16" */ + icUInt16Array data; /* Variable array of values */ +} icUInt16ArrayType; + +/** uInt32Type */ +typedef struct { + icTagBase base; /* Signature, "ui32" */ + icUInt32Array data; /* Variable array of values */ +} icUInt32ArrayType; + +/** uInt64Type */ +typedef struct { + icTagBase base; /* Signature, "ui64" */ + icUInt64Array data; /* Variable array of values */ +} icUInt64ArrayType; + +/** uInt8Type */ +typedef struct { + icTagBase base; /* Signature, "ui08" */ + icUInt8Array data; /* Variable array of values */ +} icUInt8ArrayType; + +/** viewingConditionsType */ +typedef struct { + icTagBase base; /* Signature, "view" */ + icViewingCondition view; /* Viewing conditions */ +} icViewingConditionType; + +/** XYZ Type */ +typedef struct { + icTagBase base; /* Signature, "XYZ" */ + icXYZArray data; /* Variable array of XYZ numbers */ +} icXYZType; + +/** + * CRDInfoType where [0] is the CRD product name count and string and + * [1] -[5] are the rendering intents 0-4 counts and strings + */ +typedef struct { + icTagBase base; /* Signature, "crdi" */ + icCrdInfo info; /* 5 sets of counts & strings */ +}icCrdInfoType; + /* icCrdInfo productName; PS product count/string */ + /* icCrdInfo CRDName0; CRD name for intent 0 */ + /* icCrdInfo CRDName1; CRD name for intent 1 */ + /* icCrdInfo CRDName2; CRD name for intent 2 */ + /* icCrdInfo CRDName3; CRD name for intent 3 */ + +/** ColorantOrderType type */ +typedef struct { + icTagBase base; /* Signature, "clro" */ + icColorantOrder order; /* ColorantOrder */ +}icColorantOrderType; + +/** ColorantTableType type */ +typedef struct { + icTagBase base; /* Signature, "clrt" */ + icColorantTable table; /* ColorantTable */ +}icColorantTableType; + +/** ChromaticAdaptation type */ +typedef struct { + icTagBase base; /* Signature, "chad" */ + icS15Fixed16Number matrix[9]; /* ChromaticAdaptation Matrix */ +}icChromaticAdaptationType; + +/** MultiLocalizedUnicodeEntry type */ +typedef struct { + icUInt16Number languageCode; /* name language code ISO-639 */ + icUInt16Number countryCode; /* name country code ISO-3166 */ + icUInt32Number len; /* string length in bytes */ + icUInt32Number off; /* offset in bytes from start of tag */ +}icMultiLocalizedUnicodeEntry; + +/** MultiLocalizedUnicode type */ +typedef struct { + icTagBase base; /* Signature, "mluc" */ + icUInt32Number count; /* Count of name records */ + icUInt32Number size; /* name record size */ +}icMultiLocalizedUnicodeType; + +/*------------------------------------------------------------------------*/ + +/** +* Lists of tags, tags, profile header and profile structure + */ + +/** A tag */ +typedef struct { + icTagSignature sig; /* The tag signature */ + icUInt32Number offset; /* Start of tag relative to + * start of header, Spec + * Clause 5 */ + icUInt32Number size; /* Size in bytes */ +} icTag; + +/** A Structure that may be used independently for a list of tags */ +typedef struct { + icUInt32Number count; /* Number of tags in the profile */ + icTag tags[icAny]; /* Variable array of tags */ +} icTagList; + +/** Profile ID */ +typedef union { + icUInt8Number ID8[16]; + icUInt16Number ID16[8]; + icUInt32Number ID32[4]; +} icProfileID; + +/** The Profile header */ +typedef struct { + icUInt32Number size; /* Profile size in bytes */ + icSignature cmmId; /* CMM for this profile */ + icUInt32Number version; /* Format version number */ + icProfileClassSignature deviceClass; /* Type of profile */ + icColorSpaceSignature colorSpace; /* Color space of data */ + icColorSpaceSignature pcs; /* PCS, XYZ or Lab only */ + icDateTimeNumber date; /* Date profile was created */ + icSignature magic; /* icMagicNumber */ + icPlatformSignature platform; /* Primary Platform */ + icUInt32Number flags; /* Various bit settings */ + icSignature manufacturer; /* Device manufacturer */ + icUInt32Number model; /* Device model number */ + icUInt64Number attributes; /* Device attributes */ + icUInt32Number renderingIntent;/* Rendering intent */ + icXYZNumber illuminant; /* Profile illuminant */ + icSignature creator; /* Profile creator */ + icProfileID profileID; /* Profile ID using RFC 1321 MD5 128bit fingerprinting */ + icInt8Number reserved[28]; /* Reserved for future use */ +} icHeader; + +/** + * A profile, + * we can't use icTagList here because its not at the end of the structure + */ +typedef struct { + icHeader header; /* The header */ + icTagList tagList; /* with tagList */ + /* Original: + icHeader header; The header + icUInt32Number count; Number of tags in the profile + icInt8Number data[icAny]; The tagTable and tagData */ +/* + * Data that follows is of the form + * + * icTag tagTable[icAny]; * The tag table + * icInt8Number tagData[icAny]; * The tag data + */ +} icProfile; + +/*------------------------------------------------------------------------*/ +/* Obsolete entries */ + +/* icNamedColor was replaced with icNamedColor2 * +typedef struct { + icUInt32Number vendorFlag; / Bottom 16 bits for IC use * + icUInt32Number count; / Count of named colors * + icInt8Number data[icAny]; / Named color data follows * + * + * Data that follows is of this form + * + * icInt8Number prefix[icAny]; * Prefix for the color name, max = 32 + * icInt8Number suffix[icAny]; * Suffix for the color name, max = 32 + * icInt8Number root1[icAny]; * Root name for first color, max = 32 + * icInt8Number coords1[icAny]; * Color coordinates of first color + * icInt8Number root2[icAny]; * Root name for first color, max = 32 + * icInt8Number coords2[icAny]; * Color coordinates of first color + * : + * : + * Repeat for root name and color coordinates up to (count-1) + * +} icNamedColor; */ + +/* icNamedColorType was replaced by icNamedColor2Type * +typedef struct { + icTagBase base; / Signature, "ncol" * + icNamedColor ncolor; / Named color data * +} icNamedColorType; */ + +#endif /* icPROFILEHEADER_H */ + + + + diff --git a/library/src/main/cpp/icc/md5.cpp b/library/src/main/cpp/icc/md5.cpp new file mode 100644 index 00000000..e5998c7f --- /dev/null +++ b/library/src/main/cpp/icc/md5.cpp @@ -0,0 +1,291 @@ +/** @file + +md5.cpp - RSA Data Security, Inc., MD5 message-digest algorithm + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include "md5.h" +#include + +static void MD5Transform (UINT4 [4], unsigned char [64]); +static void Encode (unsigned char *, UINT4 *, unsigned int); +static void Decode (UINT4 *, unsigned char *, unsigned int); + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/** ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/** MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void ICCPROFLIB_API icMD5Init (MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/** MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void ICCPROFLIB_API icMD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy((POINTER)&context->buffer[index], (POINTER)&input[i],inputLen-i); +} + +/** MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void ICCPROFLIB_API icMD5Final (unsigned char* digest, MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + icMD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + icMD5Update (context, bits, 8); + + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + memset((POINTER)context, 0, sizeof (*context)); +} + +/** MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (UINT4 state[4], unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + memset((POINTER)x, 0, sizeof (x)); +} + +/** Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/** Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + diff --git a/library/src/main/cpp/icc/md5.h b/library/src/main/cpp/icc/md5.h new file mode 100644 index 00000000..4f0284af --- /dev/null +++ b/library/src/main/cpp/icc/md5.h @@ -0,0 +1,61 @@ + +/** @file + +md5.H - header file for md5.cpp + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* --------------------------------------------------------------------- +January 2011 +- Modified names to avoid possible conflicts - Max Derhak +- Added IccProfLibConf.h include to use ICCPROFLIB_API with functions +- Changed typedef of UINT4 to use ICCUINT64 + +August 2012 +- Change typedef of UINT4 to use ICCUINT32 (oops!) +------------------------------------------------------------------------ */ + +#include "IccProfLibConf.h" + + +/** POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/** UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/** UINT4 defines a four byte word */ +typedef ICCUINT32 UINT4; + + +/** MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void ICCPROFLIB_API icMD5Init (MD5_CTX *); +void ICCPROFLIB_API icMD5Update (MD5_CTX *, unsigned char *, unsigned int); +void ICCPROFLIB_API icMD5Final (unsigned char* , MD5_CTX *); + diff --git a/library/src/main/cpp/jbig2/CMakeLists.txt b/library/src/main/cpp/jbig2/CMakeLists.txt new file mode 100644 index 00000000..2da44228 --- /dev/null +++ b/library/src/main/cpp/jbig2/CMakeLists.txt @@ -0,0 +1,44 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +set(TARGET jbig2Use) +set(SRC_DIR src) + +include_directories(include) + +#add_library(jpeg SHARED IMPORTED) +#set_target_properties(jpeg PROPERTIES IMPORTED_LOCATION +# ${CMAKE_CURRENT_SOURCE_DIR}/../../../../libs/${ANDROID_ABI}/libjpeg.so) + + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +aux_source_directory(${SRC_DIR} DIR_LIB_SOURCE) + +add_library(${TARGET} SHARED ${DIR_LIB_SOURCE} Jbig2JNI.cpp) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +target_link_libraries(${TARGET} log android) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +#if(${ANDROID_ABI} STREQUAL x86 OR ${ANDROID_ABI} STREQUAL x86_64) +#target_link_libraries(${TARGET} opencv_imgproc opencv_core ippiw ippicv ittnotify tbb cpufeatures) +#else() +#target_link_libraries(${TARGET}) +#endif() + diff --git a/library/src/main/cpp/jbig2/Jbig2JNI.cpp b/library/src/main/cpp/jbig2/Jbig2JNI.cpp new file mode 100644 index 00000000..2bd69fdb --- /dev/null +++ b/library/src/main/cpp/jbig2/Jbig2JNI.cpp @@ -0,0 +1,321 @@ +// +// Created by 钟元杰 on 2022/10/28. +// + +#include +#include +#include +#include +#include +#include +#include + +#include "jbig2.h" +#include "jbig2_priv.h" +#include "jbig2_image.h" +//#include "jbig2_image_rw.h" + +#include +#define TAG "JBIG_TEST" +#define pri_debug(format, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s:%d]" format, "XSOOY", __LINE__, ##args) + + +#define ALIGNMENT 16 +#define KBYTE 1024 +#define MBYTE (1024 * KBYTE) + +//typedef struct { +// jbig2dec_mode mode; +// int verbose, hash, embedded; +// SHA1_CTX *hash_ctx; +// char *output_filename; +// jbig2dec_format output_format; +// size_t memory_limit; +//} jbig2dec_params_t; + +typedef struct { + int verbose; + char *last_message; + Jbig2Severity severity; + char *type; + long repeats; +} jbig2dec_error_callback_state_t; + +typedef struct { + Jbig2Allocator super; + Jbig2Ctx *ctx; + size_t memory_limit; + size_t memory_used; + size_t memory_peak; +} jbig2dec_allocator_t; + +unsigned char* ConvertJByteaArrayToChars(JNIEnv *env, jbyteArray bytearray) +{ + unsigned char *chars = nullptr; + jbyte *bytes; + bytes = env->GetByteArrayElements(bytearray, 0); + int chars_len = env->GetArrayLength(bytearray); + chars = (unsigned char *)malloc(chars_len+1); + memset(chars,0,chars_len + 1); + memcpy(chars, bytes, chars_len); + chars[chars_len] = 0; + + env->ReleaseByteArrayElements(bytearray, bytes, 0); + return chars; +} + +jbyteArray ConvertCharsToJByteaArray(JNIEnv *env, unsigned char *buff,int size) +{ + jbyteArray arr = env->NewByteArray(size); + env->SetByteArrayRegion(arr, 0, size, (jbyte*)buff); + return arr; +} + +static void *jbig2dec_reached_limit(jbig2dec_allocator_t *allocator, size_t oldsize, size_t size) +{ + size_t limit_mb = allocator->memory_limit / MBYTE; + size_t used_mb = allocator->memory_used / MBYTE; + size_t oldsize_mb = oldsize / MBYTE; + size_t size_mb = size / MBYTE; + + if (oldsize == 0) + jbig2_error(allocator->ctx, JBIG2_SEVERITY_FATAL, -1, "memory: limit reached: limit: %zu (%zu Mbyte) used: %zu (%zu Mbyte) allocation: %zu (%zu Mbyte)", + allocator->memory_limit, limit_mb, + allocator->memory_used, used_mb, + size, size_mb); + else + jbig2_error(allocator->ctx, JBIG2_SEVERITY_FATAL, -1, "memory: limit reached: limit: %zu (%zu Mbyte) used: %zu (%zu Mbyte) reallocation: %zu (%zu Mbyte) -> %zu (%zu Mbyte)", + allocator->memory_limit, limit_mb, + allocator->memory_used, used_mb, + oldsize, oldsize_mb, + size, size_mb); + + return NULL; +} + +static void jbig2dec_peak(jbig2dec_allocator_t *allocator) +{ + size_t limit_mb = allocator->memory_limit / MBYTE; + size_t peak_mb = allocator->memory_peak / MBYTE; + size_t used_mb = allocator->memory_used / MBYTE; + + if (allocator->ctx == NULL) + return; + if (used_mb <= peak_mb) + return; + + allocator->memory_peak = allocator->memory_used; + + jbig2_error(allocator->ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "memory: limit: %lu %sbyte used: %lu %sbyte, peak: %lu %sbyte", + limit_mb > 0 ? limit_mb : allocator->memory_limit, limit_mb > 0 ? "M" : "", + used_mb > 0 ? used_mb : allocator->memory_used, used_mb > 0 ? "M" : "", + peak_mb > 0 ? peak_mb : allocator->memory_peak, peak_mb > 0 ? "M" : ""); +} + +static void *jbig2dec_alloc(Jbig2Allocator *allocator_, size_t size) +{ + jbig2dec_allocator_t *allocator = (jbig2dec_allocator_t *) allocator_; + void *ptr; + + if (size == 0) + return NULL; + if (size > SIZE_MAX - ALIGNMENT) + return NULL; + + if (size + ALIGNMENT > allocator->memory_limit - allocator->memory_used) + return jbig2dec_reached_limit(allocator, 0, size + ALIGNMENT); + + ptr = malloc(size + ALIGNMENT); + if (ptr == NULL) + return NULL; + memcpy(ptr, &size, sizeof(size)); + allocator->memory_used += size + ALIGNMENT; + + jbig2dec_peak(allocator); + + return (unsigned char *) ptr + ALIGNMENT; +} + +static void jbig2dec_free(Jbig2Allocator *allocator_, void *p) +{ + jbig2dec_allocator_t *allocator = (jbig2dec_allocator_t *) allocator_; + size_t size; + + if (p == NULL) + return; + + memcpy(&size, (unsigned char *) p - ALIGNMENT, sizeof(size)); + allocator->memory_used -= size + ALIGNMENT; + free((unsigned char *) p - ALIGNMENT); +} + + +static void *jbig2dec_realloc(Jbig2Allocator *allocator_, void *p, size_t size) +{ + jbig2dec_allocator_t *allocator = (jbig2dec_allocator_t *) allocator_; + unsigned char *oldp; + size_t oldsize; + + if (p == NULL) + return jbig2dec_alloc(allocator_, size); + if (p < (void *) ALIGNMENT) + return NULL; + + if (size == 0) { + jbig2dec_free(allocator_, p); + return NULL; + } + if (size > SIZE_MAX - ALIGNMENT) + return NULL; + + oldp = (unsigned char *) p - ALIGNMENT; + memcpy(&oldsize, oldp, sizeof(oldsize)); + + if (size + ALIGNMENT > allocator->memory_limit - allocator->memory_used + oldsize + ALIGNMENT) + return jbig2dec_reached_limit(allocator, oldsize + ALIGNMENT, size + ALIGNMENT); + + p = realloc(oldp, size + ALIGNMENT); + if (p == NULL) + return NULL; + + allocator->memory_used -= oldsize + ALIGNMENT; + memcpy(p, &size, sizeof(size)); + allocator->memory_used += size + ALIGNMENT; + + jbig2dec_peak(allocator); + + return (unsigned char *) p + ALIGNMENT; +} + +static void error_callback(void *error_callback_data, const char *message, Jbig2Severity severity, uint32_t seg_idx) +{ + pri_debug("error_callback"); + jbig2dec_error_callback_state_t *state = (jbig2dec_error_callback_state_t *) error_callback_data; + char *type; +// int ret; + + switch (severity) { + case JBIG2_SEVERITY_DEBUG: + if (state->verbose < 3) + return; + type = "DEBUG"; + break; + case JBIG2_SEVERITY_INFO: + if (state->verbose < 2) + return; + type = "info"; + break; + case JBIG2_SEVERITY_WARNING: + if (state->verbose < 1) + return; + type = "WARNING"; + break; + case JBIG2_SEVERITY_FATAL: + type = "FATAL ERROR"; + break; + default: + type = "unknown message"; + break; + } + + if (state->last_message != NULL +// && !strcmp(message, state->last_message) + && state->severity == severity && state->type == type) { + state->repeats++; + if (state->repeats % 1000000 == 0) { + if (state->type!= nullptr) + pri_debug("jbig2dec %s last message repeated %ld times so far\n", state->type, state->repeats); + else + pri_debug("jbig2dec last message repeated %ld times so far\n", state->repeats); +// ret = fprintf(stderr, "jbig2dec %s last message repeated %ld times so far\n", state->type, state->repeats); +// if (ret < 0) +// goto printerror; + } + } else { + if (state->repeats > 1) { +// pri_debug("error_callback222 %s",state->type); +// pri_debug("jbig2dec %s last message repeated %ld times\n", state->type, state->repeats); + pri_debug("jbig2dec last message repeated %ld times\n", state->repeats); +// ret = fprintf(stderr, "jbig2dec %s last message repeated %ld times\n", state->type, state->repeats); +// if (ret < 0) +// goto printerror; + } + + if (seg_idx == JBIG2_UNKNOWN_SEGMENT_NUMBER){ + pri_debug("jbig2dec %s %s\n", type, message); + } +// ret = fprintf(stderr, "jbig2dec %s %s\n", type, message); + else { + pri_debug("jbig2dec %s %s (segment 0x%08x)\n", type, message, seg_idx); + } + +// ret = fprintf(stderr, "jbig2dec %s %s (segment 0x%08x)\n", type, message, seg_idx); +// if (ret < 0) +// goto printerror; + + state->repeats = 0; + state->severity = severity; + state->type = type; +// free(state->last_message); + state->last_message = NULL; + + if (message) { + state->last_message = strdup(message); + if (state->last_message == NULL) { + pri_debug("jbig2dec WARNING could not duplicate message\n"); + } + } + } + +} + +extern "C" +JNIEXPORT jbyteArray JNICALL Java_com_xsooy_jbig2_Jbig2Utils_converData(JNIEnv *env, jobject thiz, jbyteArray data) { + + pri_debug("开始解析图片"); + unsigned char *pmsg = ConvertJByteaArrayToChars(env,data); + int chars_len = env->GetArrayLength(data); + + Jbig2Image *image; + +// jbig2dec_params_t params; + jbig2dec_error_callback_state_t error_callback_state; + Jbig2Ctx *ctx = NULL; + jbig2dec_allocator_t allocator_; + jbig2dec_allocator_t *allocator = &allocator_; + + allocator->super.alloc = jbig2dec_alloc; + allocator->super.free = jbig2dec_free; + allocator->super.realloc = jbig2dec_realloc; + allocator->ctx = NULL; + allocator->memory_limit = 1024*1024*100; + allocator->memory_used = 0; + allocator->memory_peak = 0; + + ctx = jbig2_ctx_new((Jbig2Allocator *) allocator, (Jbig2Options) JBIG2_OPTIONS_EMBEDDED, NULL, error_callback, &error_callback_state); + pri_debug("error callback address11=== 0x%x", ctx); + jbig2_data_in(ctx, pmsg, chars_len); + + int code = jbig2_complete_page(ctx); + + if (code>=0 && ctx->max_page_index>0) { + image = jbig2_page_out(ctx); + if (image!=NULL) { +// pri_debug("4444_111 %d,%d",image->width,image->height); +// pri_debug("4444_111 %d",image->stride); + jbyteArray result = ConvertCharsToJByteaArray(env,image->data,(int)(image->stride*image->height)); + jbig2_release_page(ctx, image); + return result; + } else { + pri_debug("没有图片???"); + } + } + return nullptr; +// while ((image = jbig2_page_out(ctx)) != NULL) { +// result = ConvertCharsToJByteaArray(env,image->data,image->width*image->height); +// jbig2_release_page(ctx, image); +// } + +// jbyteArray result = ConvertCharsToJByteaArray(env,raw_image,width*height*depth); +// return result; +} diff --git a/library/src/main/cpp/jbig2/include/memento.h b/library/src/main/cpp/jbig2/include/memento.h new file mode 100644 index 00000000..ca28b55b --- /dev/null +++ b/library/src/main/cpp/jbig2/include/memento.h @@ -0,0 +1,331 @@ +/* Copyright (C) 2009-2021 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com + or contact Artifex Software, Inc., 1305 Grant Avenue - Suite 200, + Novato, CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* Memento: A library to aid debugging of memory leaks/heap corruption. + * + * Usage (with C): + * First, build your project with MEMENTO defined, and include this + * header file wherever you use malloc, realloc or free. + * This header file will use macros to point malloc, realloc and free to + * point to Memento_malloc, Memento_realloc, Memento_free. + * + * Run your program, and all mallocs/frees/reallocs should be redirected + * through here. When the program exits, you will get a list of all the + * leaked blocks, together with some helpful statistics. You can get the + * same list of allocated blocks at any point during program execution by + * calling Memento_listBlocks(); + * + * Every call to malloc/free/realloc counts as an 'allocation event'. + * On each event Memento increments a counter. Every block is tagged with + * the current counter on allocation. Every so often during program + * execution, the heap is checked for consistency. By default this happens + * after 1024 events, then after 2048 events, then after 4096 events, etc. + * This can be changed at runtime by using Memento_setParanoia(int level). + * 0 turns off such checking, 1 sets checking to happen on every event, + * any positive number n sets checking to happen once every n events, + * and any negative number n sets checking to happen after -n events, then + * after -2n events etc. + * + * The default paranoia level is therefore -1024. + * + * Memento keeps blocks around for a while after they have been freed, and + * checks them as part of these heap checks to see if they have been + * written to (or are freed twice etc). + * + * A given heap block can be checked for consistency (it's 'pre' and + * 'post' guard blocks are checked to see if they have been written to) + * by calling Memento_checkBlock(void *blockAddress); + * + * A check of all the memory can be triggered by calling Memento_check(); + * (or Memento_checkAllMemory(); if you'd like it to be quieter). + * + * A good place to breakpoint is Memento_breakpoint, as this will then + * trigger your debugger if an error is detected. This is done + * automatically for debug windows builds. + * + * If a block is found to be corrupt, information will be printed to the + * console, including the address of the block, the size of the block, + * the type of corruption, the number of the block and the event on which + * it last passed a check for correctness. + * + * If you rerun, and call Memento_paranoidAt(int event); with this number + * the code will wait until it reaches that event and then start + * checking the heap after every allocation event. Assuming it is a + * deterministic failure, you should then find out where in your program + * the error is occurring (between event x-1 and event x). + * + * Then you can rerun the program again, and call + * Memento_breakAt(int event); and the program will call + * Memento_Breakpoint() when event x is reached, enabling you to step + * through. + * + * Memento_find(address) will tell you what block (if any) the given + * address is in. + * + * An example: + * Suppose we have a gs invocation that crashes with memory corruption. + * * Build with -DMEMENTO. + * * In your debugger put a breakpoint on Memento_breakpoint. + * * Run the program. It will stop in Memento_inited. + * * Execute Memento_setParanoia(1); (In VS use Ctrl-Alt-Q). (Note #1) + * * Continue execution. + * * It will detect the memory corruption on the next allocation event + * after it happens, and stop in Memento_breakpoint. The console should + * show something like: + * + * Freed blocks: + * 0x172e610(size=288,num=1415) index 256 (0x172e710) onwards corrupted + * Block last checked OK at allocation 1457. Now 1458. + * + * * This means that the block became corrupted between allocation 1457 + * and 1458 - so if we rerun and stop the program at 1457, we can then + * step through, possibly with a data breakpoint at 0x172e710 and see + * when it occurs. + * * So restart the program from the beginning. When we stop after + * initialisation execute Memento_breakAt(1457); (and maybe + * Memento_setParanoia(1), or Memento_setParanoidAt(1457)) + * * Continue execution until we hit Memento_breakpoint. + * * Now you can step through and watch the memory corruption happen. + * + * Note #1: Using Memento_setParanoia(1) can cause your program to run + * very slowly. You may instead choose to use Memento_setParanoia(100) + * (or some other figure). This will only exhaustively check memory on + * every 100th allocation event. This trades speed for the size of the + * average allocation event range in which detection of memory corruption + * occurs. You may (for example) choose to run once checking every 100 + * allocations and discover that the corruption happens between events + * X and X+100. You can then rerun using Memento_paranoidAt(X), and + * it'll only start exhaustively checking when it reaches X. + * + * More than one memory allocator? + * + * If you have more than one memory allocator in the system (like for + * instance the ghostscript chunk allocator, that builds on top of the + * standard malloc and returns chunks itself), then there are some things + * to note: + * + * * If the secondary allocator gets its underlying blocks from calling + * malloc, then those will be checked by Memento, but 'subblocks' that + * are returned to the secondary allocator will not. There is currently + * no way to fix this other than trying to bypass the secondary + * allocator. One way I have found to do this with the chunk allocator + * is to tweak its idea of a 'large block' so that it puts every + * allocation in its own chunk. Clearly this negates the point of having + * a secondary allocator, and is therefore not recommended for general + * use. + * + * * Again, if the secondary allocator gets its underlying blocks from + * calling malloc (and hence Memento) leak detection should still work + * (but whole blocks will be detected rather than subblocks). + * + * * If on every allocation attempt the secondary allocator calls into + * Memento_failThisEvent(), and fails the allocation if it returns true + * then more useful features can be used; firstly memory squeezing will + * work, and secondly, Memento will have a "finer grained" paranoia + * available to it. + * + * Usage with C++: + * + * Memento has some experimental code in it to trap new/delete (and + * new[]/delete[] if required) calls. + * + * In order for this to work, either: + * + * 1) Build memento.c with the c++ compiler. + * + * or + * + * 2) Build memento.c as normal with the C compiler, then from any + * one of your .cpp files, do: + * + * #define MEMENTO_CPP_EXTRAS_ONLY + * #include "memento.c" + * + * In the case where MEMENTO is not defined, this will not do anything. + * + * Both Windows and GCC provide separate new[] and delete[] operators + * for arrays. Apparently some systems do not. If this is the case for + * your system, define MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS. + * + * "libbacktrace.so failed to load" + * + * In order to give nice backtraces on unix, Memento will try to use + * a libbacktrace dynamic library. If it can't find it, you'll see + * that warning, and your backtraces won't include file/line information. + * + * To fix this you'll need to build your own libbacktrace. Don't worry + * it's really easy: + * git clone git://github.com/ianlancetaylor/libbacktrace + * cd libbacktrace + * ./configure + * make + * + * This leaves the build .so as .libs/libbacktrace.so + * + * Memento will look for this on LD_LIBRARY_PATH, or in /opt/lib/, + * or in /lib/, or in /usr/lib/, or in /usr/local/lib/. I recommend + * using /opt/lib/ as this won't conflict with anything that you + * get via a package manager like apt. + * + * sudo mkdir /opt + * sudo mkdir /opt/lib + * sudo cp .libs/libbacktrace.so /opt/lib/ + */ + +#ifndef MEMENTO_H + +#include + +#define MEMENTO_H + +#ifndef MEMENTO_UNDERLYING_MALLOC +#define MEMENTO_UNDERLYING_MALLOC malloc +#endif +#ifndef MEMENTO_UNDERLYING_FREE +#define MEMENTO_UNDERLYING_FREE free +#endif +#ifndef MEMENTO_UNDERLYING_REALLOC +#define MEMENTO_UNDERLYING_REALLOC realloc +#endif +#ifndef MEMENTO_UNDERLYING_CALLOC +#define MEMENTO_UNDERLYING_CALLOC calloc +#endif + +#ifndef MEMENTO_MAXALIGN +#define MEMENTO_MAXALIGN (sizeof(int)) +#endif + +#define MEMENTO_PREFILL 0xa6 +#define MEMENTO_POSTFILL 0xa7 +#define MEMENTO_ALLOCFILL 0xa8 +#define MEMENTO_FREEFILL 0xa9 + +#define MEMENTO_FREELIST_MAX 0x2000000 + +int Memento_checkBlock(void *); +int Memento_checkAllMemory(void); +int Memento_check(void); + +int Memento_setParanoia(int); +int Memento_paranoidAt(int); +int Memento_breakAt(int); +void Memento_breakOnFree(void *a); +void Memento_breakOnRealloc(void *a); +int Memento_getBlockNum(void *); +int Memento_find(void *a); +void Memento_breakpoint(void); +int Memento_failAt(int); +int Memento_failThisEvent(void); +void Memento_listBlocks(void); +void Memento_listNewBlocks(void); +size_t Memento_setMax(size_t); +void Memento_stats(void); +void *Memento_label(void *, const char *); +void Memento_tick(void); + +void *Memento_malloc(size_t s); +void *Memento_realloc(void *, size_t s); +void Memento_free(void *); +void *Memento_calloc(size_t, size_t); + +void Memento_info(void *addr); +void Memento_listBlockInfo(void); +void *Memento_takeByteRef(void *blk); +void *Memento_dropByteRef(void *blk); +void *Memento_takeShortRef(void *blk); +void *Memento_dropShortRef(void *blk); +void *Memento_takeIntRef(void *blk); +void *Memento_dropIntRef(void *blk); +void *Memento_takeRef(void *blk); +void *Memento_dropRef(void *blk); +void *Memento_adjustRef(void *blk, int adjust); +void *Memento_reference(void *blk); + +int Memento_checkPointerOrNull(void *blk); +int Memento_checkBytePointerOrNull(void *blk); +int Memento_checkShortPointerOrNull(void *blk); +int Memento_checkIntPointerOrNull(void *blk); + +void Memento_startLeaking(void); +void Memento_stopLeaking(void); + +int Memento_sequence(void); + +int Memento_squeezing(void); + +void Memento_fin(void); + +void Memento_bt(void); + +#ifdef MEMENTO + +#ifndef COMPILING_MEMENTO_C +#define malloc Memento_malloc +#define free Memento_free +#define realloc Memento_realloc +#define calloc Memento_calloc +#endif + +#else + +#define Memento_malloc MEMENTO_UNDERLYING_MALLOC +#define Memento_free MEMENTO_UNDERLYING_FREE +#define Memento_realloc MEMENTO_UNDERLYING_REALLOC +#define Memento_calloc MEMENTO_UNDERLYING_CALLOC + +#define Memento_checkBlock(A) 0 +#define Memento_checkAllMemory() 0 +#define Memento_check() 0 +#define Memento_setParanoia(A) 0 +#define Memento_paranoidAt(A) 0 +#define Memento_breakAt(A) 0 +#define Memento_breakOnFree(A) 0 +#define Memento_breakOnRealloc(A) 0 +#define Memento_getBlockNum(A) 0 +#define Memento_find(A) 0 +#define Memento_breakpoint() do {} while (0) +#define Memento_failAt(A) 0 +#define Memento_failThisEvent() 0 +#define Memento_listBlocks() do {} while (0) +#define Memento_listNewBlocks() do {} while (0) +#define Memento_setMax(A) 0 +#define Memento_stats() do {} while (0) +#define Memento_label(A,B) (A) +#define Memento_info(A) do {} while (0) +#define Memento_listBlockInfo() do {} while (0) +#define Memento_takeByteRef(A) (A) +#define Memento_dropByteRef(A) (A) +#define Memento_takeShortRef(A) (A) +#define Memento_dropShortRef(A) (A) +#define Memento_takeIntRef(A) (A) +#define Memento_dropIntRef(A) (A) +#define Memento_takeRef(A) (A) +#define Memento_dropRef(A) (A) +#define Memento_adjustRef(A,V) (A) +#define Memento_reference(A) (A) +#define Memento_checkPointerOrNull(A) 0 +#define Memento_checkBytePointerOrNull(A) 0 +#define Memento_checkShortPointerOrNull(A) 0 +#define Memento_checkIntPointerOrNull(A) 0 + +#define Memento_tick() do {} while (0) +#define Memento_startLeaking() do {} while (0) +#define Memento_stopLeaking() do {} while (0) +#define Memento_fin() do {} while (0) +#define Memento_bt() do {} while (0) +#define Memento_sequence() (0) +#define Memento_squeezing() (0) + +#endif /* MEMENTO */ + +#endif /* MEMENTO_H */ diff --git a/library/src/main/cpp/jbig2/include/os_types.h b/library/src/main/cpp/jbig2/include/os_types.h new file mode 100644 index 00000000..ef7ffa5d --- /dev/null +++ b/library/src/main/cpp/jbig2/include/os_types.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2001-2021 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* + jbig2dec +*/ + +/* + indirection layer for build and platform-specific definitions + + in general, this header should ensure that the stdint types are + available, and that any optional compile flags are defined if + the build system doesn't pass them directly. +*/ + +#ifndef _JBIG2_OS_TYPES_H +#define _JBIG2_OS_TYPES_H + +#if defined(HAVE_CONFIG_H) +# include "config_types.h" +#elif defined(_WIN32) +# include "config_win32.h" +#elif defined (STD_INT_USE_SYS_TYPES_H) +# include +#elif defined (STD_INT_USE_INTTYPES_H) +# include +#elif defined (STD_INT_USE_SYS_INTTYPES_H) +# include +#elif defined (STD_INT_USE_SYS_INT_TYPES_H) +# include +#else +#include +#endif + +#endif /* _JBIG2_OS_TYPES_H */ diff --git a/library/src/main/cpp/jbig2/include/sha1.h b/library/src/main/cpp/jbig2/include/sha1.h new file mode 100644 index 00000000..afeeb42c --- /dev/null +++ b/library/src/main/cpp/jbig2/include/sha1.h @@ -0,0 +1,28 @@ +/* public api for steve reid's public domain SHA-1 implementation */ +/* this file is in the public domain */ + +#ifndef __SHA1_H +#define __SHA1_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[64]; +} SHA1_CTX; + +#define SHA1_DIGEST_SIZE 20 + +void SHA1_Init(SHA1_CTX *context); +void SHA1_Update(SHA1_CTX *context, const uint8_t *data, const size_t len); +void SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE]); + +#ifdef __cplusplus +} +#endif + +#endif /* __SHA1_H */ diff --git a/library/src/main/cpp/jbig2/src/memcmp.c b/library/src/main/cpp/jbig2/src/memcmp.c new file mode 100644 index 00000000..9da72dbf --- /dev/null +++ b/library/src/main/cpp/jbig2/src/memcmp.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2001-2021 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* + jbig2dec +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/* replacement for broken memcmp() */ + +/* + * compares two byte strings 'a' and 'b', both assumed to be 'len' bytes long + * returns zero if the two strings are identical, otherwise returns -1 or 1 + * depending on the relative magnitude of the first differing elements, + * considered as unsigned chars + */ + +int +memcmp(const void *b1, const void *b2, size_t len) +{ + unsigned char *a, *b; + size_t i; + + a = (unsigned char *)b1; + b = (unsigned char *)b2; + for (i = 0; i < len; i++) { + if (*a != *b) { + /* strings differ */ + return (*a < *b) ? -1 : 1; + } + a++; + b++; + } + + /* strings match */ + return 0; +} diff --git a/library/src/main/cpp/jbig2/src/memento.c b/library/src/main/cpp/jbig2/src/memento.c new file mode 100644 index 00000000..46e6602a --- /dev/null +++ b/library/src/main/cpp/jbig2/src/memento.c @@ -0,0 +1,3129 @@ +/* Copyright (C) 2009-2021 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com + or contact Artifex Software, Inc., 1305 Grant Avenue - Suite 200, + Novato, CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* Inspired by Fortify by Simon P Bullen. */ + +/* Set the following if you're only looking for leaks, not memory overwrites + * to speed the operation */ +/* #define MEMENTO_LEAKONLY */ + +/* Set the following to keep extra details about the history of blocks */ +#define MEMENTO_DETAILS + +/* Don't keep blocks around if they'd mean losing more than a quarter of + * the freelist. */ +#define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4) + +#define COMPILING_MEMENTO_C + +/* SHUT UP, MSVC. I KNOW WHAT I AM DOING. */ +#define _CRT_SECURE_NO_WARNINGS + +/* We have some GS specific tweaks; more for the GS build environment than + * anything else. */ +/* #define MEMENTO_GS_HACKS */ + +#ifdef MEMENTO_GS_HACKS +/* For GS we include malloc_.h. Anyone else would just include memento.h */ +#include "malloc_.h" +#include "memory_.h" +int atexit(void (*)(void)); +#else +#include "memento.h" +#include +#endif +#ifndef _MSC_VER +#include +#include +#include +#endif + +#include +#include +#include + +#ifdef __ANDROID__ +#define MEMENTO_ANDROID +#include +#endif + +/* Hacks to portably print large sizes */ +#ifdef _MSC_VER +#define FMTZ "%llu" +#define FMTZ_CAST _int64 +#define FMTP "0x%p" +#else +#define FMTZ "%zu" +#define FMTZ_CAST size_t +#define FMTP "%p" +#endif + +#define UB(x) ((intptr_t)((x) & 0xFF)) +#define B2I(x) (UB(x) | (UB(x)<<8) | (UB(x)<<16) | (UB(x)<<24)) +#define B2P(x) ((void *)(B2I(x) | ((B2I(x)<<16)<<16))) +#define MEMENTO_PREFILL_UBYTE ((unsigned char)(MEMENTO_PREFILL)) +#define MEMENTO_PREFILL_USHORT (((unsigned short)MEMENTO_PREFILL_UBYTE) | (((unsigned short)MEMENTO_PREFILL_UBYTE)<<8)) +#define MEMENTO_PREFILL_UINT (((unsigned int)MEMENTO_PREFILL_USHORT) | (((unsigned int)MEMENTO_PREFILL_USHORT)<<16)) +#define MEMENTO_PREFILL_PTR (void *)(((uintptr_t)MEMENTO_PREFILL_UINT) | ((((uintptr_t)MEMENTO_PREFILL_UINT)<<16)<<16)) +#define MEMENTO_POSTFILL_UBYTE ((unsigned char)(MEMENTO_POSTFILL)) +#define MEMENTO_POSTFILL_USHORT (((unsigned short)MEMENTO_POSTFILL_UBYTE) | (((unsigned short)MEMENTO_POSTFILL_UBYTE)<<8)) +#define MEMENTO_POSTFILL_UINT (((unsigned int)MEMENTO_POSTFILL_USHORT) | (((unsigned int)MEMENTO_POSTFILL_USHORT)<<16)) +#define MEMENTO_POSTFILL_PTR (void *)(((uintptr_t)MEMENTO_POSTFILL_UINT) | ((((uintptr_t)MEMENTO_POSTFILL_UINT)<<16)<<16)) +#define MEMENTO_ALLOCFILL_UBYTE ((unsigned char)(MEMENTO_ALLOCFILL)) +#define MEMENTO_ALLOCFILL_USHORT (((unsigned short)MEMENTO_ALLOCFILL_UBYTE) | (((unsigned short)MEMENTO_ALLOCFILL_UBYTE)<<8)) +#define MEMENTO_ALLOCFILL_UINT (((unsigned int)MEMENTO_ALLOCFILL_USHORT) | (((unsigned int)MEMENTO_ALLOCFILL_USHORT)<<16)) +#define MEMENTO_ALLOCFILL_PTR (void *)(((uintptr_t)MEMENTO_ALLOCFILL_UINT) | ((((uintptr_t)MEMENTO_ALLOCFILL_UINT)<<16)<<16)) +#define MEMENTO_FREEFILL_UBYTE ((unsigned char)(MEMENTO_FREEFILL)) +#define MEMENTO_FREEFILL_USHORT (((unsigned short)MEMENTO_FREEFILL_UBYTE) | (((unsigned short)MEMENTO_FREEFILL_UBYTE)<<8)) +#define MEMENTO_FREEFILL_UINT (((unsigned int)MEMENTO_FREEFILL_USHORT) | (((unsigned int)MEMENTO_FREEFILL_USHORT)<<16)) +#define MEMENTO_FREEFILL_PTR (void *)(((uintptr_t)MEMENTO_FREEFILL_UINT) | ((((uintptr_t)MEMENTO_FREEFILL_UINT)<<16)<<16)) + +#ifdef MEMENTO + +#ifndef MEMENTO_CPP_EXTRAS_ONLY + +#ifdef MEMENTO_ANDROID +#include + +static char log_buffer[4096]; +static int log_fill = 0; + +static char log_buffer2[4096]; + +static int +android_fprintf(FILE *file, const char *fmt, ...) +{ + va_list args; + char *p, *q; + + va_start(args, fmt); + vsnprintf(log_buffer2, sizeof(log_buffer2)-1, fmt, args); + va_end(args); + + /* Ensure we are always null terminated */ + log_buffer2[sizeof(log_buffer2)-1] = 0; + + p = log_buffer2; + q = p; + do + { + /* Find the end of the string, or the next \n */ + while (*p && *p != '\n') + p++; + + /* We need to output from q to p. Limit ourselves to what + * will fit in the existing */ + if (p - q >= sizeof(log_buffer)-1 - log_fill) + p = q + sizeof(log_buffer)-1 - log_fill; + + memcpy(&log_buffer[log_fill], q, p-q); + log_fill += p-q; + if (*p == '\n') + { + log_buffer[log_fill] = 0; + __android_log_print(ANDROID_LOG_ERROR, "memento", "%s", log_buffer); + usleep(1); + log_fill = 0; + p++; /* Skip over the \n */ + } + else if (log_fill >= sizeof(log_buffer)-1) + { + log_buffer[sizeof(log_buffer2)-1] = 0; + __android_log_print(ANDROID_LOG_ERROR, "memento", "%s", log_buffer); + usleep(1); + log_fill = 0; + } + q = p; + } + while (*p); + + return 0; +} + +#define fprintf android_fprintf +#define MEMENTO_STACKTRACE_METHOD 3 +#endif + +/* _WIN64 defined implies _WIN32 will be */ +#ifdef _WIN32 +#include + +static int +windows_fprintf(FILE *file, const char *fmt, ...) +{ + va_list args; + char text[4096]; + int ret; + + va_start(args, fmt); + ret = vfprintf(file, fmt, args); + va_end(args); + + va_start(args, fmt); + vsnprintf(text, 4096, fmt, args); + OutputDebugStringA(text); + va_end(args); + + return ret; +} + +#define fprintf windows_fprintf +#endif + +#ifndef MEMENTO_STACKTRACE_METHOD +#ifdef __GNUC__ +#define MEMENTO_STACKTRACE_METHOD 1 +#endif +#ifdef _WIN32 +#define MEMENTO_STACKTRACE_METHOD 2 +#endif +#endif + +#if defined(__linux__) +#define MEMENTO_HAS_FORK +#elif defined(__APPLE__) && defined(__MACH__) +#define MEMENTO_HAS_FORK +#endif + +/* Define the underlying allocators, just in case */ +void *MEMENTO_UNDERLYING_MALLOC(size_t); +void MEMENTO_UNDERLYING_FREE(void *); +void *MEMENTO_UNDERLYING_REALLOC(void *,size_t); +void *MEMENTO_UNDERLYING_CALLOC(size_t,size_t); + +/* And some other standard functions we use. We don't include the header + * files, just in case they pull in unexpected others. */ +int atoi(const char *); +char *getenv(const char *); + +/* How far to search for pointers in each block when calculating nestings */ +/* mupdf needs at least 34000ish (sizeof(fz_shade))/ */ +#define MEMENTO_PTRSEARCH 65536 + +#ifndef MEMENTO_MAXPATTERN +#define MEMENTO_MAXPATTERN 0 +#endif + +#ifdef MEMENTO_GS_HACKS +#include "valgrind.h" +#else +#ifdef HAVE_VALGRIND +#include "valgrind/memcheck.h" +#else +#define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1) +#define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1) +#define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1) +#endif +#endif + +enum { + Memento_PreSize = 16, + Memento_PostSize = 16 +}; + +/* Some compile time checks */ +typedef struct +{ + char MEMENTO_PRESIZE_MUST_BE_A_MULTIPLE_OF_4[Memento_PreSize & 3 ? -1 : 1]; + char MEMENTO_POSTSIZE_MUST_BE_A_MULTIPLE_OF_4[Memento_PostSize & 3 ? -1 : 1]; + char MEMENTO_POSTSIZE_MUST_BE_AT_LEAST_4[Memento_PostSize >= 4 ? 1 : -1]; + char MEMENTO_PRESIZE_MUST_BE_AT_LEAST_4[Memento_PreSize >= 4 ? 1 : -1]; +} MEMENTO_SANITY_CHECK_STRUCT; + +#define MEMENTO_UINT32 unsigned int +#define MEMENTO_UINT16 unsigned short + +#define MEMENTO_PREFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_PREFILL | (MEMENTO_PREFILL <<8) | (MEMENTO_PREFILL <<16) |(MEMENTO_PREFILL <<24))) +#define MEMENTO_POSTFILL_UINT16 ((MEMENTO_UINT16)(MEMENTO_POSTFILL | (MEMENTO_POSTFILL<<8))) +#define MEMENTO_POSTFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_POSTFILL | (MEMENTO_POSTFILL<<8) | (MEMENTO_POSTFILL<<16) |(MEMENTO_POSTFILL<<24))) +#define MEMENTO_FREEFILL_UINT16 ((MEMENTO_UINT16)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8))) +#define MEMENTO_FREEFILL_UINT32 ((MEMENTO_UINT32)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL<<8) | (MEMENTO_FREEFILL<<16) |(MEMENTO_FREEFILL<<24))) + +enum { + Memento_Flag_OldBlock = 1, + Memento_Flag_HasParent = 2, + Memento_Flag_BreakOnFree = 4, + Memento_Flag_BreakOnRealloc = 8, + Memento_Flag_Freed = 16, + Memento_Flag_KnownLeak = 32, + Memento_Flag_Reported = 64 +}; + +enum { + Memento_EventType_malloc = 0, + Memento_EventType_calloc = 1, + Memento_EventType_realloc = 2, + Memento_EventType_free = 3, + Memento_EventType_new = 4, + Memento_EventType_delete = 5, + Memento_EventType_newArray = 6, + Memento_EventType_deleteArray = 7, + Memento_EventType_takeRef = 8, + Memento_EventType_dropRef = 9, + Memento_EventType_reference = 10 +}; + +static const char *eventType[] = +{ + "malloc", + "calloc", + "realloc", + "free", + "new", + "delete", + "new[]", + "delete[]", + "takeRef", + "dropRef", + "reference" +}; + +/* When we list leaked blocks at the end of execution, we search for pointers + * between blocks in order to be able to give a nice nested view. + * Unfortunately, if you have are running your own allocator (such as + * postscript's chunk allocator) you can often find that the header of the + * block always contains pointers to next or previous blocks. This tends to + * mean the nesting displayed is "uninteresting" at best :) + * + * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that + * indicates how many bytes to skip over at the start of the chunk. + * This may cause us to miss true nestings, but such is life... + */ +#ifndef MEMENTO_SEARCH_SKIP +#ifdef MEMENTO_GS_HACKS +#define MEMENTO_SEARCH_SKIP (2*sizeof(void *)) +#else +#define MEMENTO_SEARCH_SKIP 0 +#endif +#endif + +#define MEMENTO_CHILD_MAGIC ((Memento_BlkHeader *)('M' | ('3' << 8) | ('m' << 16) | ('3' << 24))) +#define MEMENTO_SIBLING_MAGIC ((Memento_BlkHeader *)('n' | ('t' << 8) | ('0' << 16) | ('!' << 24))) + +#ifdef MEMENTO_DETAILS +typedef struct Memento_BlkDetails Memento_BlkDetails; + +struct Memento_BlkDetails +{ + Memento_BlkDetails *next; + char type; + char count; + int sequence; + void *stack[1]; +}; +#endif /* MEMENTO_DETAILS */ + +typedef struct Memento_BlkHeader Memento_BlkHeader; + +struct Memento_BlkHeader +{ + size_t rawsize; + int sequence; + int lastCheckedOK; + int flags; + Memento_BlkHeader *next; + Memento_BlkHeader *prev; /* Reused as 'parent' when printing nested list */ + + const char *label; + + /* Entries for nesting display calculations. Set to magic + * values at all other time. */ + Memento_BlkHeader *child; + Memento_BlkHeader *sibling; + +#ifdef MEMENTO_DETAILS + Memento_BlkDetails *details; + Memento_BlkDetails **details_tail; +#endif + + char preblk[Memento_PreSize]; +}; + +/* In future this could (should) be a smarter data structure, like, say, + * splay trees. For now, we use a list. + */ +typedef struct Memento_Blocks +{ + Memento_BlkHeader *head; + Memento_BlkHeader *tail; +} Memento_Blocks; + +/* What sort of Mutex should we use? */ +#ifdef MEMENTO_LOCKLESS +typedef int Memento_mutex; + +static void Memento_initMutex(Memento_mutex *m) +{ + (void)m; +} + +#define MEMENTO_DO_LOCK() do { } while (0) +#define MEMENTO_DO_UNLOCK() do { } while (0) + +#else +#if defined(_WIN32) || defined(_WIN64) +/* Windows */ +typedef CRITICAL_SECTION Memento_mutex; + +static void Memento_initMutex(Memento_mutex *m) +{ + InitializeCriticalSection(m); +} + +#define MEMENTO_DO_LOCK() \ + EnterCriticalSection(&memento.mutex) +#define MEMENTO_DO_UNLOCK() \ + LeaveCriticalSection(&memento.mutex) + +#else +#include +typedef pthread_mutex_t Memento_mutex; + +static void Memento_initMutex(Memento_mutex *m) +{ + pthread_mutex_init(m, NULL); +} + +#define MEMENTO_DO_LOCK() \ + pthread_mutex_lock(&memento.mutex) +#define MEMENTO_DO_UNLOCK() \ + pthread_mutex_unlock(&memento.mutex) + +#endif +#endif + +/* And our global structure */ +static struct { + int inited; + Memento_Blocks used; + Memento_Blocks free; + size_t freeListSize; + int sequence; + int paranoia; + int paranoidAt; + int countdown; + int lastChecked; + int breakAt; + int failAt; + int failing; + int nextFailAt; + int squeezeAt; + int squeezing; + int segv; + int pattern; + int nextPattern; + int patternBit; + int leaking; + size_t maxMemory; + size_t alloc; + size_t peakAlloc; + size_t totalAlloc; + size_t numMallocs; + size_t numFrees; + size_t numReallocs; + Memento_mutex mutex; +} memento; + +#define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize) + +/* Round up size S to the next multiple of N (where N is a power of 2) */ +#define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1)) + +#define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN) + +#define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1]) +#define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1])) +#define MEMBLK_POSTPTR(B) \ + (&((unsigned char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)]) + +enum +{ + SkipStackBackTraceLevels = 4 +}; + +#if defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 1 +extern size_t backtrace(void **, int); +extern void backtrace_symbols_fd(void **, size_t, int); +extern char **backtrace_symbols(void **, size_t); + +#define MEMENTO_BACKTRACE_MAX 256 +static void (*print_stack_value)(void *address); + +/* Libbacktrace gubbins - relies on us having libdl to load the .so */ +#ifdef HAVE_LIBDL +#include + +typedef void (*backtrace_error_callback) (void *data, const char *msg, int errnum); + +typedef struct backtrace_state *(*backtrace_create_state_type)( + const char *filename, int threaded, + backtrace_error_callback error_callback, void *data); + +typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, + const char *filename, int lineno, + const char *function); + +typedef int (*backtrace_pcinfo_type)(struct backtrace_state *state, + uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, + void *data); + +typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, + const char *symname, + uintptr_t symval, + uintptr_t symsize); + +typedef int (*backtrace_syminfo_type)(struct backtrace_state *state, + uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, + void *data); + +static backtrace_syminfo_type backtrace_syminfo; +static backtrace_create_state_type backtrace_create_state; +static backtrace_pcinfo_type backtrace_pcinfo; +static struct backtrace_state *my_backtrace_state; +static void *libbt; +static char backtrace_exe[4096]; +static void *current_addr; + +static void error2_cb(void *data, const char *msg, int errnum) +{ +} + +static void syminfo_cb(void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize) +{ + if (sizeof(void *) == 4) + fprintf(stderr, " 0x%08lx %s\n", pc, symname?symname:"?"); + else + fprintf(stderr, " 0x%016lx %s\n", pc, symname?symname:"?"); +} + +static void error_cb(void *data, const char *msg, int errnum) +{ + backtrace_syminfo(my_backtrace_state, + (uintptr_t)current_addr, + syminfo_cb, + error2_cb, + NULL); +} + +static int full_cb(void *data, uintptr_t pc, const char *fname, int line, const char *fn) +{ + if (sizeof(void *) == 4) + fprintf(stderr, " 0x%08lx %s(%s:%d)\n", pc, fn?fn:"?", fname?fname:"?", line); + else + fprintf(stderr, " 0x%016lx %s(%s:%d)\n", pc, fn?fn:"?", fname?fname:"?", line); + return 0; +} + +static void print_stack_libbt(void *addr) +{ + current_addr = addr; + backtrace_pcinfo(my_backtrace_state, + (uintptr_t)addr, + full_cb, + error_cb, + NULL); +} + +static void print_stack_libbt_failed(void *addr) +{ + char **strings; +#if 0 + /* Let's use a hack from Julian Smith to call gdb to extract the information */ + /* Disabled for now, as I can't make this work. */ + static char command[1024]; + int e; + static int gdb_invocation_failed = 0; + + if (gdb_invocation_failed == 0) + { + snprintf(command, sizeof(command), + //"gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null", + "gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null| egrep -v '(Thread debugging using)|(Using host libthread_db library)|(A debugging session is active)|(will be detached)|(Quit anyway)|(No such file or directory)|(^0x)|(^$)'", + getpid(), addr); + printf("%s\n", command); + e = system(command); + if (e == 0) + return; /* That'll do! */ + gdb_invocation_failed = 1; /* If it's failed once, it'll probably keep failing. */ + } +#endif + + /* We couldn't even get gdb! Make do. */ + strings = backtrace_symbols(&addr, 1); + + if (strings == NULL || strings[0] == NULL) + { + if (sizeof(void *) == 4) + fprintf(stderr, " [0x%08lx]\n", (uintptr_t)addr); + else + fprintf(stderr, " [0x%016lx]\n", (uintptr_t)addr); + } + else + { + fprintf(stderr, " %s\n", strings[0]); + } + (free)(strings); +} + +static int init_libbt(void) +{ + static int libbt_inited = 0; + + if (libbt_inited) + return 0; + libbt_inited = 1; + + libbt = dlopen("libbacktrace.so", RTLD_LAZY); + if (libbt == NULL) + libbt = dlopen("/opt/lib/libbacktrace.so", RTLD_LAZY); + if (libbt == NULL) + libbt = dlopen("/lib/libbacktrace.so", RTLD_LAZY); + if (libbt == NULL) + libbt = dlopen("/usr/lib/libbacktrace.so", RTLD_LAZY); + if (libbt == NULL) + libbt = dlopen("/usr/local/lib/libbacktrace.so", RTLD_LAZY); + if (libbt == NULL) + goto fail; + + backtrace_create_state = dlsym(libbt, "backtrace_create_state"); + backtrace_syminfo = dlsym(libbt, "backtrace_syminfo"); + backtrace_pcinfo = dlsym(libbt, "backtrace_pcinfo"); + + if (backtrace_create_state == NULL || + backtrace_syminfo == NULL || + backtrace_pcinfo == NULL) + { + goto fail; + } + + my_backtrace_state = backtrace_create_state(backtrace_exe, + 1 /*BACKTRACE_SUPPORTS_THREADS*/, + error_cb, + NULL); + if (my_backtrace_state == NULL) + goto fail; + + print_stack_value = print_stack_libbt; + + return 1; + + fail: + fprintf(stderr, + "MEMENTO: libbacktrace.so failed to load; backtraces will be sparse.\n" + "MEMENTO: See memento.h for how to rectify this.\n"); + libbt = NULL; + backtrace_create_state = NULL; + backtrace_syminfo = NULL; + print_stack_value = print_stack_libbt_failed; + return 0; +} +#endif + +static void print_stack_default(void *addr) +{ + char **strings = backtrace_symbols(&addr, 1); + + if (strings == NULL || strings[0] == NULL) + { + fprintf(stderr, " ["FMTP"]\n", addr); + } +#ifdef HAVE_LIBDL + else if (strchr(strings[0], ':') == NULL) + { + /* Probably a "path [address]" format string */ + char *s = strchr(strings[0], ' '); + + if (s != strings[0]) + { + memcpy(backtrace_exe, strings[0], s - strings[0]); + backtrace_exe[s-strings[0]] = 0; + init_libbt(); + print_stack_value(addr); + } + } +#endif + else + { + fprintf(stderr, " %s\n", strings[0]); + } + free(strings); +} + +static void Memento_initStacktracer(void) +{ + print_stack_value = print_stack_default; +} + +static int Memento_getStacktrace(void **stack, int *skip) +{ + size_t num; + + num = backtrace(&stack[0], MEMENTO_BACKTRACE_MAX); + + *skip = SkipStackBackTraceLevels; + if (num <= SkipStackBackTraceLevels) + return 0; + return (int)(num-SkipStackBackTraceLevels); +} + +static void Memento_showStacktrace(void **stack, int numberOfFrames) +{ + int i; + + for (i = 0; i < numberOfFrames; i++) + { + print_stack_value(stack[i]); + } +} +#elif defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 2 +#include + +/* We use DbgHelp.dll rather than DbgHelp.lib. This avoids us needing + * extra link time complications, and enables us to fall back gracefully + * if the DLL cannot be found. + * + * To achieve this we have our own potted versions of the required types + * inline here. + */ +#ifdef _WIN64 +typedef DWORD64 DWORD_NATIVESIZED; +#else +typedef DWORD DWORD_NATIVESIZED; +#endif + +#define MEMENTO_BACKTRACE_MAX 64 + +typedef USHORT (__stdcall *My_CaptureStackBackTraceType)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG); + +typedef struct MY_IMAGEHLP_LINE { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PCHAR FileName; + DWORD_NATIVESIZED Address; +} MY_IMAGEHLP_LINE, *MY_PIMAGEHLP_LINE; + +typedef BOOL (__stdcall *My_SymGetLineFromAddrType)(HANDLE hProcess, DWORD_NATIVESIZED dwAddr, PDWORD pdwDisplacement, MY_PIMAGEHLP_LINE Line); + +typedef struct MY_SYMBOL_INFO { + ULONG SizeOfStruct; + ULONG TypeIndex; // Type Index of symbol + ULONG64 Reserved[2]; + ULONG info; + ULONG Size; + ULONG64 ModBase; // Base Address of module containing this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification + ULONG NameLen; // Actual length of name + ULONG MaxNameLen; + CHAR Name[1]; // Name of symbol +} MY_SYMBOL_INFO, *MY_PSYMBOL_INFO; + +typedef BOOL (__stdcall *My_SymFromAddrType)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, MY_PSYMBOL_INFO Symbol); +typedef BOOL (__stdcall *My_SymInitializeType)(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess); + +static My_CaptureStackBackTraceType Memento_CaptureStackBackTrace; +static My_SymGetLineFromAddrType Memento_SymGetLineFromAddr; +static My_SymFromAddrType Memento_SymFromAddr; +static My_SymInitializeType Memento_SymInitialize; +static HANDLE Memento_process; + +static void Memento_initStacktracer(void) +{ + HMODULE mod = LoadLibrary("kernel32.dll"); + + if (mod == NULL) + return; + Memento_CaptureStackBackTrace = (My_CaptureStackBackTraceType)(GetProcAddress(mod, "RtlCaptureStackBackTrace")); + if (Memento_CaptureStackBackTrace == NULL) + return; + mod = LoadLibrary("Dbghelp.dll"); + if (mod == NULL) { + Memento_CaptureStackBackTrace = NULL; + return; + } + Memento_SymGetLineFromAddr = + (My_SymGetLineFromAddrType)(GetProcAddress(mod, +#ifdef _WIN64 + "SymGetLineFromAddr64" +#else + "SymGetLineFromAddr" +#endif + )); + if (Memento_SymGetLineFromAddr == NULL) { + Memento_CaptureStackBackTrace = NULL; + return; + } + Memento_SymFromAddr = (My_SymFromAddrType)(GetProcAddress(mod, "SymFromAddr")); + if (Memento_SymFromAddr == NULL) { + Memento_CaptureStackBackTrace = NULL; + return; + } + Memento_SymInitialize = (My_SymInitializeType)(GetProcAddress(mod, "SymInitialize")); + if (Memento_SymInitialize == NULL) { + Memento_CaptureStackBackTrace = NULL; + return; + } + Memento_process = GetCurrentProcess(); + Memento_SymInitialize(Memento_process, NULL, TRUE); +} + +static int Memento_getStacktrace(void **stack, int *skip) +{ + if (Memento_CaptureStackBackTrace == NULL) + return 0; + + *skip = 0; + /* Limit us to 63 levels due to windows bug */ + return Memento_CaptureStackBackTrace(SkipStackBackTraceLevels, 63-SkipStackBackTraceLevels, stack, NULL); +} + +static void Memento_showStacktrace(void **stack, int numberOfFrames) +{ + MY_IMAGEHLP_LINE line; + int i; + char symbol_buffer[sizeof(MY_SYMBOL_INFO) + 1024 + 1]; + MY_SYMBOL_INFO *symbol = (MY_SYMBOL_INFO *)symbol_buffer; + + symbol->MaxNameLen = 1024; + symbol->SizeOfStruct = sizeof(MY_SYMBOL_INFO); + line.SizeOfStruct = sizeof(MY_IMAGEHLP_LINE); + for (i = 0; i < numberOfFrames; i++) + { + DWORD64 dwDisplacement64; + DWORD dwDisplacement; + Memento_SymFromAddr(Memento_process, (DWORD64)(stack[i]), &dwDisplacement64, symbol); + Memento_SymGetLineFromAddr(Memento_process, (DWORD_NATIVESIZED)(stack[i]), &dwDisplacement, &line); + fprintf(stderr, " %s in %s:%d\n", symbol->Name, line.FileName, line.LineNumber); + } +} +#elif defined(MEMENTO_STACKTRACE_METHOD) && MEMENTO_STACKTRACE_METHOD == 3 + +#include +#include + +/* From cxxabi.h */ +extern char* __cxa_demangle(const char* mangled_name, + char* output_buffer, + size_t* length, + int* status); + +static void Memento_initStacktracer(void) +{ +} + +#define MEMENTO_BACKTRACE_MAX 256 + +typedef struct +{ + int count; + void **addr; +} my_unwind_details; + +static _Unwind_Reason_Code unwind_populate_callback(struct _Unwind_Context *context, + void *arg) +{ + my_unwind_details *uw = (my_unwind_details *)arg; + int count = uw->count; + + if (count >= MEMENTO_BACKTRACE_MAX) + return _URC_END_OF_STACK; + + uw->addr[count] = (void *)_Unwind_GetIP(context); + uw->count++; + + return _URC_NO_REASON; +} + +static int Memento_getStacktrace(void **stack, int *skip) +{ + my_unwind_details uw = { 0, stack }; + + *skip = 0; + + /* Collect the backtrace. Deliberately only unwind once, + * and avoid using malloc etc until this completes just + * in case. */ + _Unwind_Backtrace(unwind_populate_callback, &uw); + if (uw.count <= SkipStackBackTraceLevels) + return 0; + + *skip = SkipStackBackTraceLevels; + return uw.count-SkipStackBackTraceLevels; +} + +static void Memento_showStacktrace(void **stack, int numberOfFrames) +{ + int i; + + for (i = 0; i < numberOfFrames; i++) + { + Dl_info info; + if (dladdr(stack[i], &info)) + { + int status = 0; + const char *sym = info.dli_sname ? info.dli_sname : ""; + char *demangled = __cxa_demangle(sym, NULL, 0, &status); + int offset = stack[i] - info.dli_saddr; + fprintf(stderr, " ["FMTP"]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset); + free(demangled); + } + else + { + fprintf(stderr, " ["FMTP"]\n", stack[i]); + } + } +} + +#else +static void Memento_initStacktracer(void) +{ +} + +static int Memento_getStacktrace(void **stack, int *skip) +{ + *skip = 0; + return 0; +} + +static void Memento_showStacktrace(void **stack, int numberOfFrames) +{ +} +#endif /* MEMENTO_STACKTRACE_METHOD */ + +#ifdef MEMENTO_DETAILS +static void Memento_storeDetails(Memento_BlkHeader *head, int type) +{ + void *stack[MEMENTO_BACKTRACE_MAX]; + Memento_BlkDetails *details; + int count; + int skip; + + if (head == NULL) + return; + +#ifdef MEMENTO_STACKTRACE_METHOD + count = Memento_getStacktrace(stack, &skip); +#else + skip = 0; + count = 0; +#endif + + details = MEMENTO_UNDERLYING_MALLOC(sizeof(*details) + (count-1) * sizeof(void *)); + if (details == NULL) + return; + + if (count) + memcpy(&details->stack, &stack[skip], count * sizeof(void *)); + + details->type = type; + details->count = count; + details->sequence = memento.sequence; + details->next = NULL; + VALGRIND_MAKE_MEM_DEFINED(&head->details_tail, sizeof(head->details_tail)); + *head->details_tail = details; + head->details_tail = &details->next; + VALGRIND_MAKE_MEM_NOACCESS(&head->details_tail, sizeof(head->details_tail)); +} +#endif + +void (Memento_bt)(void) +{ +#ifdef MEMENTO_STACKTRACE_METHOD + void *stack[MEMENTO_BACKTRACE_MAX]; + int count; + int skip; + + count = Memento_getStacktrace(stack, &skip); + Memento_showStacktrace(&stack[skip-2], count-skip+2); +#endif +} + +static void Memento_bt_internal(int skip2) +{ +#ifdef MEMENTO_STACKTRACE_METHOD + void *stack[MEMENTO_BACKTRACE_MAX]; + int count; + int skip; + + count = Memento_getStacktrace(stack, &skip); + Memento_showStacktrace(&stack[skip+skip2], count-skip-skip2); +#endif +} + +static int Memento_checkAllMemoryLocked(void); + +void Memento_breakpoint(void) +{ + /* A handy externally visible function for breakpointing */ +#if 0 /* Enable this to force automatic breakpointing */ +#ifndef NDEBUG +#ifdef _MSC_VER + __asm int 3; +#endif +#endif +#endif +} + +static void Memento_init(void); + +#define MEMENTO_LOCK() \ +do { if (!memento.inited) Memento_init(); MEMENTO_DO_LOCK(); } while (0) + +#define MEMENTO_UNLOCK() \ +do { MEMENTO_DO_UNLOCK(); } while (0) + +/* Do this as a macro to prevent another level in the callstack, + * which is annoying while stepping. */ +#define Memento_breakpointLocked() \ +do { MEMENTO_UNLOCK(); Memento_breakpoint(); MEMENTO_LOCK(); } while (0) + +static void Memento_addBlockHead(Memento_Blocks *blks, + Memento_BlkHeader *b, + int type) +{ + if (blks->tail == NULL) + blks->tail = b; + b->next = blks->head; + b->prev = NULL; + if (blks->head) + { + VALGRIND_MAKE_MEM_DEFINED(&blks->head->prev, sizeof(blks->head->prev)); + blks->head->prev = b; + VALGRIND_MAKE_MEM_NOACCESS(&blks->head->prev, sizeof(blks->head->prev)); + } + blks->head = b; +#ifndef MEMENTO_LEAKONLY + memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); + memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); +#endif + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); + if (type == 0) { /* malloc */ + VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); + } else if (type == 1) { /* free */ + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); + } + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); +} + +static void Memento_addBlockTail(Memento_Blocks *blks, + Memento_BlkHeader *b, + int type) +{ + VALGRIND_MAKE_MEM_DEFINED(&blks->tail, sizeof(Memento_BlkHeader *)); + if (blks->head == NULL) + blks->head = b; + b->prev = blks->tail; + b->next = NULL; + if (blks->tail) { + VALGRIND_MAKE_MEM_DEFINED(&blks->tail->next, sizeof(blks->tail->next)); + blks->tail->next = b; + VALGRIND_MAKE_MEM_NOACCESS(&blks->tail->next, sizeof(blks->tail->next)); + } + blks->tail = b; +#ifndef MEMENTO_LEAKONLY + memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); + memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); +#endif + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); + if (type == 0) { /* malloc */ + VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); + } else if (type == 1) { /* free */ + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); + } + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + VALGRIND_MAKE_MEM_NOACCESS(&blks->tail, sizeof(Memento_BlkHeader *)); +} + +typedef struct BlkCheckData { + int found; + int preCorrupt; + int postCorrupt; + int freeCorrupt; + size_t index; +} BlkCheckData; + +#ifndef MEMENTO_LEAKONLY +static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg) +{ + int i; + MEMENTO_UINT32 *ip; + unsigned char *p; + BlkCheckData *data = (BlkCheckData *)arg; + + ip = (MEMENTO_UINT32 *)(void *)(b->preblk); + i = Memento_PreSize>>2; + do { + if (*ip++ != MEMENTO_PREFILL_UINT32) + goto pre_corrupt; + } while (--i); + if (0) { +pre_corrupt: + data->preCorrupt = 1; + } + /* Postfill may not be aligned, so have to be slower */ + p = MEMBLK_POSTPTR(b); + i = Memento_PostSize-4; + if ((intptr_t)p & 1) + { + if (*p++ != MEMENTO_POSTFILL) + goto post_corrupt; + i--; + } + if ((intptr_t)p & 2) + { + if (*(MEMENTO_UINT16 *)p != MEMENTO_POSTFILL_UINT16) + goto post_corrupt; + p += 2; + i -= 2; + } + do { + if (*(MEMENTO_UINT32 *)p != MEMENTO_POSTFILL_UINT32) + goto post_corrupt; + p += 4; + i -= 4; + } while (i >= 0); + if (i & 2) + { + if (*(MEMENTO_UINT16 *)p != MEMENTO_POSTFILL_UINT16) + goto post_corrupt; + p += 2; + } + if (i & 1) + { + if (*p != MEMENTO_POSTFILL) + goto post_corrupt; + } + if (0) { +post_corrupt: + data->postCorrupt = 1; + } + if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) { + b->lastCheckedOK = memento.sequence; + } + data->found |= 1; + return 0; +} + +static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg) +{ + size_t i; + unsigned char *p; + BlkCheckData *data = (BlkCheckData *)arg; + + p = MEMBLK_TOBLK(b); /* p will always be aligned */ + i = b->rawsize; + /* Attempt to speed this up by checking an (aligned) int at a time */ + if (i >= 4) { + i -= 4; + do { + if (*(MEMENTO_UINT32 *)p != MEMENTO_FREEFILL_UINT32) + goto mismatch4; + p += 4; + i -= 4; + } while (i > 0); + i += 4; + } + if (i & 2) { + if (*(MEMENTO_UINT16 *)p != MEMENTO_FREEFILL_UINT16) + goto mismatch; + p += 2; + i -= 2; + } + if (0) { +mismatch4: + i += 4; + } +mismatch: + while (i) { + if (*p++ != (unsigned char)MEMENTO_FREEFILL) + break; + i--; + } + if (i) { + data->freeCorrupt = 1; + data->index = b->rawsize-i; + } + return Memento_Internal_checkAllocedBlock(b, arg); +} +#endif /* MEMENTO_LEAKONLY */ + +static void Memento_removeBlock(Memento_Blocks *blks, + Memento_BlkHeader *b) +{ + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); + if (b->next) { + VALGRIND_MAKE_MEM_DEFINED(&b->next->prev, sizeof(b->next->prev)); + b->next->prev = b->prev; + VALGRIND_MAKE_MEM_NOACCESS(&b->next->prev, sizeof(b->next->prev)); + } + if (b->prev) { + VALGRIND_MAKE_MEM_DEFINED(&b->prev->next, sizeof(b->prev->next)); + b->prev->next = b->next; + VALGRIND_MAKE_MEM_NOACCESS(&b->prev->next, sizeof(b->prev->next)); + } + if (blks->tail == b) + blks->tail = b->prev; + if (blks->head == b) + blks->head = b->next; +} + +static void free_block(Memento_BlkHeader *head) +{ +#ifdef MEMENTO_DETAILS + Memento_BlkDetails *details = head->details; + + while (details) + { + Memento_BlkDetails *next = details->next; + MEMENTO_UNDERLYING_FREE(details); + details = next; + } +#endif + MEMENTO_UNDERLYING_FREE(head); +} + +static int Memento_Internal_makeSpace(size_t space) +{ + /* If too big, it can never go on the freelist */ + if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK) + return 0; + /* Pretend we added it on. */ + memento.freeListSize += space; + /* Ditch blocks until it fits within our limit */ + while (memento.freeListSize > MEMENTO_FREELIST_MAX) { + Memento_BlkHeader *head = memento.free.head; + VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); + memento.free.head = head->next; + memento.freeListSize -= MEMBLK_SIZE(head->rawsize); + free_block(head); + } + /* Make sure we haven't just completely emptied the free list */ + /* (This should never happen, but belt and braces... */ + if (memento.free.head == NULL) + memento.free.tail = NULL; + return 1; +} + +static int Memento_appBlocks(Memento_Blocks *blks, + int (*app)(Memento_BlkHeader *, + void *), + void *arg) +{ + Memento_BlkHeader *head = blks->head; + Memento_BlkHeader *next; + int result; + while (head) { + VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); + VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), + head->rawsize + Memento_PostSize); + result = app(head, arg); + next = head->next; + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); + VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); + if (result) + return result; + head = next; + } + return 0; +} + +#ifndef MEMENTO_LEAKONLY +/* Distrustful - check the block is a real one */ +static int Memento_appBlockUser(Memento_Blocks *blks, + int (*app)(Memento_BlkHeader *, + void *), + void *arg, + Memento_BlkHeader *b) +{ + Memento_BlkHeader *head = blks->head; + Memento_BlkHeader *next; + int result; + while (head && head != b) { + VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); + next = head->next; + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); + head = next; + } + if (head == b) { + VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); + VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), + head->rawsize + Memento_PostSize); + result = app(head, arg); + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); + VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); + return result; + } + return 0; +} + +static int Memento_appBlock(Memento_Blocks *blks, + int (*app)(Memento_BlkHeader *, + void *), + void *arg, + Memento_BlkHeader *b) +{ + int result; + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); + VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(b), + b->rawsize + Memento_PostSize); + result = app(b, arg); + VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + return result; +} +#endif /* MEMENTO_LEAKONLY */ + +static int showBlock(Memento_BlkHeader *b, int space) +{ + int seq; + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); + fprintf(stderr, FMTP":(size=" FMTZ ",num=%d)", + MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence); + if (b->label) + fprintf(stderr, "%c(%s)", space, b->label); + if (b->flags & Memento_Flag_KnownLeak) + fprintf(stderr, "(Known Leak)"); + seq = b->sequence; + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + return seq; +} + +static void blockDisplay(Memento_BlkHeader *b, int n) +{ + n++; + while (n > 40) + { + fprintf(stderr, "*"); + n -= 40; + } + while(n > 0) + { + int i = n; + if (i > 32) + i = 32; + n -= i; + fprintf(stderr, "%s", &" "[32-i]); + } + showBlock(b, '\t'); + fprintf(stderr, "\n"); +} + +static int Memento_listBlock(Memento_BlkHeader *b, + void *arg) +{ + size_t *counts = (size_t *)arg; + blockDisplay(b, 0); + counts[0]++; + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); + counts[1]+= b->rawsize; + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + return 0; +} + +static void doNestedDisplay(Memento_BlkHeader *b, + int depth) +{ + /* Try and avoid recursion if we can help it */ + do { + Memento_BlkHeader *c = NULL; + blockDisplay(b, depth); + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); + if (b->sibling) { + c = b->child; + b = b->sibling; + } else { + b = b->child; + depth++; + } + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + if (c) + doNestedDisplay(c, depth+1); + } while (b); +} + +static int ptrcmp(const void *a_, const void *b_) +{ + const char **a = (const char **)a_; + const char **b = (const char **)b_; + return (int)(*a-*b); +} + +static +int Memento_listBlocksNested(void) +{ + int count, i; + size_t size; + Memento_BlkHeader *b, *prev; + void **blocks, *minptr, *maxptr; + intptr_t mask; + + /* Count the blocks */ + count = 0; + size = 0; + for (b = memento.used.head; b; b = b->next) { + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(*b)); + size += b->rawsize; + count++; + } + + /* Make our block list */ + blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count); + if (blocks == NULL) + return 1; + + /* Populate our block list */ + b = memento.used.head; + minptr = maxptr = MEMBLK_TOBLK(b); + mask = (intptr_t)minptr; + for (i = 0; b; b = b->next, i++) { + void *p = MEMBLK_TOBLK(b); + mask &= (intptr_t)p; + if (p < minptr) + minptr = p; + if (p > maxptr) + maxptr = p; + blocks[i] = p; + b->flags &= ~Memento_Flag_HasParent; + b->child = NULL; + b->sibling = NULL; + b->prev = NULL; /* parent */ + } + qsort(blocks, count, sizeof(void *), ptrcmp); + + /* Now, calculate tree */ + for (b = memento.used.head; b; b = b->next) { + char *p = MEMBLK_TOBLK(b); + int end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH); + for (i = MEMENTO_SEARCH_SKIP; i < end; i += sizeof(void *)) { + void *q = *(void **)(&p[i]); + void **r; + + /* Do trivial checks on pointer */ + if ((mask & (intptr_t)q) != mask || q < minptr || q > maxptr) + continue; + + /* Search for pointer */ + r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp); + if (r) { + /* Found child */ + Memento_BlkHeader *child = MEMBLK_FROMBLK(*r); + Memento_BlkHeader *parent; + + /* We're assuming tree structure, not graph - ignore second + * and subsequent pointers. */ + if (child->prev != NULL) /* parent */ + continue; + if (child->flags & Memento_Flag_HasParent) + continue; + + /* Not interested in pointers to ourself! */ + if (child == b) + continue; + + /* We're also assuming acyclicness here. If this is one of + * our parents, ignore it. */ + parent = b->prev; /* parent */ + while (parent != NULL && parent != child) + parent = parent->prev; /* parent */ + if (parent == child) + continue; + + child->sibling = b->child; + b->child = child; + child->prev = b; /* parent */ + child->flags |= Memento_Flag_HasParent; + } + } + } + + /* Now display with nesting */ + for (b = memento.used.head; b; b = b->next) { + if ((b->flags & Memento_Flag_HasParent) == 0) + doNestedDisplay(b, 0); + } + fprintf(stderr, " Total number of blocks = %d\n", count); + fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)size); + + MEMENTO_UNDERLYING_FREE(blocks); + + /* Now put the blocks back for valgrind, and restore the prev + * and magic values. */ + prev = NULL; + for (b = memento.used.head; b;) { + Memento_BlkHeader *next = b->next; + b->prev = prev; + b->child = MEMENTO_CHILD_MAGIC; + b->sibling = MEMENTO_SIBLING_MAGIC; + prev = b; + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(*b)); + b = next; + } + + return 0; +} + +void Memento_listBlocks(void) +{ + MEMENTO_LOCK(); + fprintf(stderr, "Allocated blocks:\n"); + if (Memento_listBlocksNested()) + { + size_t counts[2]; + counts[0] = 0; + counts[1] = 0; + Memento_appBlocks(&memento.used, Memento_listBlock, &counts[0]); + fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)counts[0]); + fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)counts[1]); + } + MEMENTO_UNLOCK(); +} + +static int Memento_listNewBlock(Memento_BlkHeader *b, + void *arg) +{ + if (b->flags & Memento_Flag_OldBlock) + return 0; + b->flags |= Memento_Flag_OldBlock; + return Memento_listBlock(b, arg); +} + +void Memento_listNewBlocks(void) +{ + size_t counts[2]; + MEMENTO_LOCK(); + counts[0] = 0; + counts[1] = 0; + fprintf(stderr, "Blocks allocated and still extant since last list:\n"); + Memento_appBlocks(&memento.used, Memento_listNewBlock, &counts[0]); + fprintf(stderr, " Total number of blocks = "FMTZ"\n", (FMTZ_CAST)counts[0]); + fprintf(stderr, " Total size of blocks = "FMTZ"\n", (FMTZ_CAST)counts[1]); + MEMENTO_UNLOCK(); +} + +static void Memento_endStats(void) +{ + fprintf(stderr, "Total memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.totalAlloc); + fprintf(stderr, "Peak memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.peakAlloc); + fprintf(stderr, FMTZ" mallocs, "FMTZ" frees, "FMTZ" reallocs\n", (FMTZ_CAST)memento.numMallocs, + (FMTZ_CAST)memento.numFrees, (FMTZ_CAST)memento.numReallocs); + fprintf(stderr, "Average allocation size "FMTZ" bytes\n", (FMTZ_CAST) + (memento.numMallocs != 0 ? memento.totalAlloc/memento.numMallocs: 0)); +} + +void Memento_stats(void) +{ + MEMENTO_LOCK(); + fprintf(stderr, "Current memory malloced = "FMTZ" bytes\n", (FMTZ_CAST)memento.alloc); + Memento_endStats(); + MEMENTO_UNLOCK(); +} + +#ifdef MEMENTO_DETAILS +static int showInfo(Memento_BlkHeader *b, void *arg) +{ + Memento_BlkDetails *details; + + fprintf(stderr, FMTP":(size="FMTZ",num=%d)", + MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence); + if (b->label) + fprintf(stderr, " (%s)", b->label); + fprintf(stderr, "\nEvents:\n"); + + details = b->details; + while (details) + { + fprintf(stderr, " Event %d (%s)\n", details->sequence, eventType[(int)details->type]); + Memento_showStacktrace(details->stack, details->count); + details = details->next; + } + return 0; +} +#endif + +void Memento_listBlockInfo(void) +{ +#ifdef MEMENTO_DETAILS + MEMENTO_LOCK(); + fprintf(stderr, "Details of allocated blocks:\n"); + Memento_appBlocks(&memento.used, showInfo, NULL); + MEMENTO_UNLOCK(); +#endif +} + +static int Memento_nonLeakBlocksLeaked(void) +{ + Memento_BlkHeader *blk = memento.used.head; + while (blk) + { + Memento_BlkHeader *next; + int leaked; + VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk)); + leaked = ((blk->flags & Memento_Flag_KnownLeak) == 0); + next = blk->next; + VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk)); + if (leaked) + return 1; + blk = next; + } + return 0; +} + +void Memento_fin(void) +{ + Memento_checkAllMemory(); + if (!memento.segv) + { + Memento_endStats(); + if (Memento_nonLeakBlocksLeaked()) { + Memento_listBlocks(); +#ifdef MEMENTO_DETAILS + fprintf(stderr, "\n"); + Memento_listBlockInfo(); +#endif + Memento_breakpoint(); + } + } + if (memento.squeezing) { + if (memento.pattern == 0) + fprintf(stderr, "Memory squeezing @ %d complete%s\n", memento.squeezeAt, memento.segv ? " (with SEGV)" : ""); + else + fprintf(stderr, "Memory squeezing @ %d (%d) complete%s\n", memento.squeezeAt, memento.pattern, memento.segv ? " (with SEGV)" : ""); + } else if (memento.segv) { + fprintf(stderr, "Memento completed (with SEGV)\n"); + } + if (memento.failing) + { + fprintf(stderr, "MEMENTO_FAILAT=%d\n", memento.failAt); + fprintf(stderr, "MEMENTO_PATTERN=%d\n", memento.pattern); + } + if (memento.nextFailAt != 0) + { + fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", memento.nextFailAt); + fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", memento.nextPattern); + } +} + +static void Memento_init(void) +{ + char *env; + memset(&memento, 0, sizeof(memento)); + memento.inited = 1; + memento.used.head = NULL; + memento.used.tail = NULL; + memento.free.head = NULL; + memento.free.tail = NULL; + memento.sequence = 0; + memento.countdown = 1024; + + env = getenv("MEMENTO_FAILAT"); + memento.failAt = (env ? atoi(env) : 0); + + env = getenv("MEMENTO_BREAKAT"); + memento.breakAt = (env ? atoi(env) : 0); + + env = getenv("MEMENTO_PARANOIA"); + memento.paranoia = (env ? atoi(env) : 0); + if (memento.paranoia == 0) + memento.paranoia = -1024; + + env = getenv("MEMENTO_PARANOIDAT"); + memento.paranoidAt = (env ? atoi(env) : 0); + + env = getenv("MEMENTO_SQUEEZEAT"); + memento.squeezeAt = (env ? atoi(env) : 0); + + env = getenv("MEMENTO_PATTERN"); + memento.pattern = (env ? atoi(env) : 0); + + env = getenv("MEMENTO_MAXMEMORY"); + memento.maxMemory = (env ? atoi(env) : 0); + + atexit(Memento_fin); + + Memento_initMutex(&memento.mutex); + + Memento_initStacktracer(); + + Memento_breakpoint(); +} + +typedef struct findBlkData { + void *addr; + Memento_BlkHeader *blk; + int flags; +} findBlkData; + +static int Memento_containsAddr(Memento_BlkHeader *b, + void *arg) +{ + findBlkData *data = (findBlkData *)arg; + char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize]; + if ((MEMBLK_TOBLK(b) <= data->addr) && + ((void *)blkend > data->addr)) { + data->blk = b; + data->flags = 1; + return 1; + } + if (((void *)b <= data->addr) && + (MEMBLK_TOBLK(b) > data->addr)) { + data->blk = b; + data->flags = 2; + return 1; + } + if (((void *)blkend <= data->addr) && + ((void *)(blkend + Memento_PostSize) > data->addr)) { + data->blk = b; + data->flags = 3; + return 1; + } + return 0; +} + +void Memento_info(void *addr) +{ +#ifdef MEMENTO_DETAILS + findBlkData data; + + MEMENTO_LOCK(); + data.addr = addr; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.used, Memento_containsAddr, &data); + if (data.blk != NULL) + showInfo(data.blk, NULL); + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.free, Memento_containsAddr, &data); + if (data.blk != NULL) + showInfo(data.blk, NULL); + MEMENTO_UNLOCK(); +#else + printf("Memento not compiled with details support\n"); +#endif +} + +#ifdef MEMENTO_HAS_FORK +#include +#include +#include +#ifdef MEMENTO_STACKTRACE_METHOD +#if MEMENTO_STACKTRACE_METHOD == 1 +#include +#endif +#endif + +/* FIXME: Find some portable way of getting this */ +/* MacOSX has 10240, Ubuntu seems to have 256 */ +#ifndef OPEN_MAX +#define OPEN_MAX 10240 +#endif + +/* stashed_map[j] = i means that file descriptor i-1 was duplicated to j */ +int stashed_map[OPEN_MAX]; + +static void Memento_signal(int sig) +{ + (void)sig; + fprintf(stderr, "SEGV at:\n"); + memento.segv = 1; + Memento_bt_internal(0); + + exit(1); +} + +static int squeeze(void) +{ + pid_t pid; + int i, status; + + if (memento.patternBit < 0) + return 1; + if (memento.squeezing && memento.patternBit >= MEMENTO_MAXPATTERN) + return 1; + + if (memento.patternBit == 0) + memento.squeezeAt = memento.sequence; + + if (!memento.squeezing) { + fprintf(stderr, "Memory squeezing @ %d\n", memento.squeezeAt); + } else + fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", memento.squeezeAt, memento.pattern, memento.patternBit); + + /* When we fork below, the child is going to snaffle all our file pointers + * and potentially corrupt them. Let's make copies of all of them before + * we fork, so we can restore them when we restart. */ + for (i = 0; i < OPEN_MAX; i++) { + if (stashed_map[i] == 0) { + int j = dup(i); + stashed_map[j] = i+1; + } + } + + fprintf(stderr, "Failing at:\n"); + Memento_bt_internal(2); + pid = fork(); + if (pid == 0) { + /* Child */ + signal(SIGSEGV, Memento_signal); + /* In the child, we always fail the next allocation. */ + if (memento.patternBit == 0) { + memento.patternBit = 1; + } else + memento.patternBit <<= 1; + memento.squeezing = 1; + return 1; + } + + /* In the parent if we hit another allocation, pass it (and record the + * fact we passed it in the pattern. */ + memento.pattern |= memento.patternBit; + memento.patternBit <<= 1; + + /* Wait for pid to finish, with a timeout. */ + { + struct timespec tm = { 0, 10 * 1000 * 1000 }; /* 10ms = 100th sec */ + int timeout = 30 * 1000 * 1000; /* time out in microseconds! */ + while (waitpid(pid, &status, WNOHANG) == 0) { + nanosleep(&tm, NULL); + timeout -= (tm.tv_nsec/1000); + tm.tv_nsec *= 2; + if (tm.tv_nsec > 999999999) + tm.tv_nsec = 999999999; + if (timeout <= 0) { + char text[32]; + fprintf(stderr, "Child is taking a long time to die. Killing it.\n"); + sprintf(text, "kill %d", pid); + system(text); + break; + } + } + } + + if (status != 0) { + fprintf(stderr, "Child status=%d\n", status); + } + + /* Put the files back */ + for (i = 0; i < OPEN_MAX; i++) { + if (stashed_map[i] != 0) { + dup2(i, stashed_map[i]-1); + close(i); + stashed_map[i] = 0; + } + } + + return 0; +} +#else +#include + +static void Memento_signal(int sig) +{ + (void)sig; + memento.segv = 1; + /* If we just return from this function the SEGV will be unhandled, and + * we'll launch into whatever JIT debugging system the OS provides. At + * least fprintf(stderr, something useful first. If MEMENTO_NOJIT is set, then + * just exit to avoid the JIT (and get the usual atexit handling). */ + if (getenv("MEMENTO_NOJIT")) + exit(1); + else + Memento_fin(); +} + +static int squeeze(void) +{ + fprintf(stderr, "Memento memory squeezing disabled as no fork!\n"); + return 0; +} +#endif + +static void Memento_startFailing(void) +{ + if (!memento.failing) { + fprintf(stderr, "Starting to fail...\n"); + Memento_bt(); + fflush(stderr); + memento.failing = 1; + memento.failAt = memento.sequence; + memento.nextFailAt = memento.sequence+1; + memento.pattern = 0; + memento.patternBit = 0; + signal(SIGSEGV, Memento_signal); + signal(SIGABRT, Memento_signal); + Memento_breakpointLocked(); + } +} + +static int Memento_event(void) +{ + memento.sequence++; + if ((memento.sequence >= memento.paranoidAt) && (memento.paranoidAt != 0)) { + memento.paranoia = 1; + memento.countdown = 1; + } + if (--memento.countdown == 0) { + Memento_checkAllMemoryLocked(); + if (memento.paranoia > 0) + memento.countdown = memento.paranoia; + else + { + memento.countdown = -memento.paranoia; + if (memento.paranoia > INT_MIN/2) + memento.paranoia *= 2; + } + } + + if (memento.sequence == memento.breakAt) { + fprintf(stderr, "Breaking at event %d\n", memento.breakAt); + return 1; + } + return 0; +} + +int Memento_sequence(void) +{ + return memento.sequence; +} + +int Memento_breakAt(int event) +{ + MEMENTO_LOCK(); + memento.breakAt = event; + MEMENTO_UNLOCK(); + return event; +} + +static void *safe_find_block(void *ptr) +{ + Memento_BlkHeader *block; + int valid; + + if (ptr == NULL) + return NULL; + + block = MEMBLK_FROMBLK(ptr); + /* Sometimes wrapping allocators can mean Memento_label + * is called with a value within the block, rather than + * at the start of the block. If we detect this, find it + * the slow way. */ + VALGRIND_MAKE_MEM_DEFINED(&block->child, sizeof(block->child)); + VALGRIND_MAKE_MEM_DEFINED(&block->sibling, sizeof(block->sibling)); + valid = (block->child == MEMENTO_CHILD_MAGIC && + block->sibling == MEMENTO_SIBLING_MAGIC); + VALGRIND_MAKE_MEM_NOACCESS(&block->child, sizeof(block->child)); + VALGRIND_MAKE_MEM_NOACCESS(&block->sibling, sizeof(block->sibling)); + if (!valid) + { + findBlkData data; + + data.addr = ptr; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.used, Memento_containsAddr, &data); + if (data.blk == NULL) + return NULL; + block = data.blk; + } + return block; +} + +void *Memento_label(void *ptr, const char *label) +{ + Memento_BlkHeader *block; + + if (ptr == NULL) + return NULL; + MEMENTO_LOCK(); + block = safe_find_block(ptr); + if (block != NULL) + { + VALGRIND_MAKE_MEM_DEFINED(&block->label, sizeof(block->label)); + block->label = label; + VALGRIND_MAKE_MEM_NOACCESS(&block->label, sizeof(block->label)); + } + MEMENTO_UNLOCK(); + return ptr; +} + +void Memento_tick(void) +{ + MEMENTO_LOCK(); + if (Memento_event()) Memento_breakpointLocked(); + MEMENTO_UNLOCK(); +} + +static int Memento_failThisEventLocked(void) +{ + int failThisOne; + + if (Memento_event()) Memento_breakpointLocked(); + + if ((memento.sequence >= memento.failAt) && (memento.failAt != 0)) + Memento_startFailing(); + if ((memento.sequence >= memento.squeezeAt) && (memento.squeezeAt != 0)) { + return squeeze(); + } + + if (!memento.failing) + return 0; + failThisOne = ((memento.patternBit & memento.pattern) == 0); + /* If we are failing, and we've reached the end of the pattern and we've + * still got bits available in the pattern word, and we haven't already + * set a nextPattern, then extend the pattern. */ + if (memento.failing && + ((~(memento.patternBit-1) & memento.pattern) == 0) && + (memento.patternBit != 0) && + memento.nextPattern == 0) + { + /* We'll fail this one, and set the 'next' one to pass it. */ + memento.nextFailAt = memento.failAt; + memento.nextPattern = memento.pattern | memento.patternBit; + } + memento.patternBit = (memento.patternBit ? memento.patternBit << 1 : 1); + + return failThisOne; +} + +int Memento_failThisEvent(void) +{ + int ret; + + if (!memento.inited) + Memento_init(); + + MEMENTO_LOCK(); + ret = Memento_failThisEventLocked(); + MEMENTO_UNLOCK(); + return ret; +} + +static void *do_malloc(size_t s, int eventType) +{ + Memento_BlkHeader *memblk; + size_t smem = MEMBLK_SIZE(s); + + if (Memento_failThisEventLocked()) + return NULL; + + if (s == 0) + return NULL; + + memento.numMallocs++; + + if (memento.maxMemory != 0 && memento.alloc + s > memento.maxMemory) + return NULL; + + memblk = MEMENTO_UNDERLYING_MALLOC(smem); + if (memblk == NULL) + return NULL; + + memento.alloc += s; + memento.totalAlloc += s; + if (memento.peakAlloc < memento.alloc) + memento.peakAlloc = memento.alloc; +#ifndef MEMENTO_LEAKONLY + memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s); +#endif + memblk->rawsize = s; + memblk->sequence = memento.sequence; + memblk->lastCheckedOK = memblk->sequence; + memblk->flags = 0; + memblk->label = 0; + memblk->child = MEMENTO_CHILD_MAGIC; + memblk->sibling = MEMENTO_SIBLING_MAGIC; +#ifdef MEMENTO_DETAILS + memblk->details = NULL; + memblk->details_tail = &memblk->details; + Memento_storeDetails(memblk, Memento_EventType_malloc); +#endif /* MEMENTO_DETAILS */ + Memento_addBlockHead(&memento.used, memblk, 0); + + if (memento.leaking > 0) + memblk->flags |= Memento_Flag_KnownLeak; + + return MEMBLK_TOBLK(memblk); +} + +void *Memento_malloc(size_t s) +{ + void *ret; + + if (!memento.inited) + Memento_init(); + + MEMENTO_LOCK(); + ret = do_malloc(s, Memento_EventType_malloc); + MEMENTO_UNLOCK(); + return ret; +} + +void *Memento_calloc(size_t n, size_t s) +{ + void *block; + + if (!memento.inited) + Memento_init(); + + MEMENTO_LOCK(); + block = do_malloc(n*s, Memento_EventType_calloc); + if (block) + memset(block, 0, n*s); + MEMENTO_UNLOCK(); + return block; +} + +static void do_reference(Memento_BlkHeader *blk, int event) +{ +#ifdef MEMENTO_DETAILS + Memento_storeDetails(blk, event); +#endif /* MEMENTO_DETAILS */ +} + +int Memento_checkPointerOrNull(void *blk) +{ + if (blk == NULL) + return 0; + if (blk == MEMENTO_PREFILL_PTR) + fprintf(stderr, "Prefill value found as pointer - buffer underrun?\n"); + else if (blk == MEMENTO_POSTFILL_PTR) + fprintf(stderr, "Postfill value found as pointer - buffer overrun?\n"); + else if (blk == MEMENTO_ALLOCFILL_PTR) + fprintf(stderr, "Allocfill value found as pointer - use of uninitialised value?\n"); + else if (blk == MEMENTO_FREEFILL_PTR) + fprintf(stderr, "Allocfill value found as pointer - use after free?\n"); + else + return 0; +#ifdef MEMENTO_DETAILS + fprintf(stderr, "Current backtrace:\n"); + Memento_bt(); + fprintf(stderr, "History:\n"); + Memento_info(blk); +#endif + return 1; +} + +int Memento_checkBytePointerOrNull(void *blk) +{ + unsigned char i; + if (blk == NULL) + return 0; + Memento_checkPointerOrNull(blk); + + i = *(unsigned int *)blk; + + if (i == MEMENTO_PREFILL_UBYTE) + fprintf(stderr, "Prefill value found - buffer underrun?\n"); + else if (i == MEMENTO_POSTFILL_UBYTE) + fprintf(stderr, "Postfill value found - buffer overrun?\n"); + else if (i == MEMENTO_ALLOCFILL_UBYTE) + fprintf(stderr, "Allocfill value found - use of uninitialised value?\n"); + else if (i == MEMENTO_FREEFILL_UBYTE) + fprintf(stderr, "Allocfill value found - use after free?\n"); + else + return 0; +#ifdef MEMENTO_DETAILS + fprintf(stderr, "Current backtrace:\n"); + Memento_bt(); + fprintf(stderr, "History:\n"); + Memento_info(blk); +#endif + Memento_breakpoint(); + return 1; +} + +int Memento_checkShortPointerOrNull(void *blk) +{ + unsigned short i; + if (blk == NULL) + return 0; + Memento_checkPointerOrNull(blk); + + i = *(unsigned short *)blk; + + if (i == MEMENTO_PREFILL_USHORT) + fprintf(stderr, "Prefill value found - buffer underrun?\n"); + else if (i == MEMENTO_POSTFILL_USHORT) + fprintf(stderr, "Postfill value found - buffer overrun?\n"); + else if (i == MEMENTO_ALLOCFILL_USHORT) + fprintf(stderr, "Allocfill value found - use of uninitialised value?\n"); + else if (i == MEMENTO_FREEFILL_USHORT) + fprintf(stderr, "Allocfill value found - use after free?\n"); + else + return 0; +#ifdef MEMENTO_DETAILS + fprintf(stderr, "Current backtrace:\n"); + Memento_bt(); + fprintf(stderr, "History:\n"); + Memento_info(blk); +#endif + Memento_breakpoint(); + return 1; +} + +int Memento_checkIntPointerOrNull(void *blk) +{ + unsigned int i; + if (blk == NULL) + return 0; + Memento_checkPointerOrNull(blk); + + i = *(unsigned int *)blk; + + if (i == MEMENTO_PREFILL_UINT) + fprintf(stderr, "Prefill value found - buffer underrun?\n"); + else if (i == MEMENTO_POSTFILL_UINT) + fprintf(stderr, "Postfill value found - buffer overrun?\n"); + else if (i == MEMENTO_ALLOCFILL_UINT) + fprintf(stderr, "Allocfill value found - use of uninitialised value?\n"); + else if (i == MEMENTO_FREEFILL_UINT) + fprintf(stderr, "Allocfill value found - use after free?\n"); + else + return 0; +#ifdef MEMENTO_DETAILS + fprintf(stderr, "Current backtrace:\n"); + Memento_bt(); + fprintf(stderr, "History:\n"); + Memento_info(blk); +#endif + Memento_breakpoint(); + return 1; +} + +static void *do_takeRef(void *blk) +{ + MEMENTO_LOCK(); + do_reference(safe_find_block(blk), Memento_EventType_takeRef); + MEMENTO_UNLOCK(); + return blk; +} + +void *Memento_takeByteRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + (void)Memento_checkBytePointerOrNull(blk); + + return do_takeRef(blk); +} + +void *Memento_takeShortRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + (void)Memento_checkShortPointerOrNull(blk); + + return do_takeRef(blk); +} + +void *Memento_takeIntRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + (void)Memento_checkIntPointerOrNull(blk); + + return do_takeRef(blk); +} + +void *Memento_takeRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + return do_takeRef(blk); +} + +static void *do_dropRef(void *blk) +{ + MEMENTO_LOCK(); + do_reference(safe_find_block(blk), Memento_EventType_dropRef); + MEMENTO_UNLOCK(); + return blk; +} + +void *Memento_dropByteRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + Memento_checkBytePointerOrNull(blk); + + return do_dropRef(blk); +} + +void *Memento_dropShortRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + Memento_checkShortPointerOrNull(blk); + + return do_dropRef(blk); +} + +void *Memento_dropIntRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + Memento_checkIntPointerOrNull(blk); + + return do_dropRef(blk); +} + +void *Memento_dropRef(void *blk) +{ + if (!memento.inited) + Memento_init(); + + if (Memento_event()) Memento_breakpoint(); + + if (!blk) + return NULL; + + return do_dropRef(blk); +} + +void *Memento_adjustRef(void *blk, int adjust) +{ + if (Memento_event()) Memento_breakpoint(); + + if (blk == NULL) + return NULL; + + while (adjust > 0) + { + do_takeRef(blk); + adjust--; + } + while (adjust < 0) + { + do_dropRef(blk); + adjust++; + } + + return blk; + } + +void *Memento_reference(void *blk) +{ + if (!blk) + return NULL; + + if (!memento.inited) + Memento_init(); + + MEMENTO_LOCK(); + do_reference(safe_find_block(blk), Memento_EventType_reference); + MEMENTO_UNLOCK(); + return blk; +} + +/* Treat blocks from the user with suspicion, and check them the slow + * but safe way. */ +static int checkBlockUser(Memento_BlkHeader *memblk, const char *action) +{ +#ifndef MEMENTO_LEAKONLY + BlkCheckData data; + + memset(&data, 0, sizeof(data)); + Memento_appBlockUser(&memento.used, Memento_Internal_checkAllocedBlock, + &data, memblk); + if (!data.found) { + /* Failure! */ + fprintf(stderr, "Attempt to %s block ", action); + showBlock(memblk, 32); + fprintf(stderr, "\n"); + Memento_breakpointLocked(); + return 1; + } else if (data.preCorrupt || data.postCorrupt) { + fprintf(stderr, "Block "); + showBlock(memblk, ' '); + fprintf(stderr, " found to be corrupted on %s!\n", action); + if (data.preCorrupt) { + fprintf(stderr, "Preguard corrupted\n"); + } + if (data.postCorrupt) { + fprintf(stderr, "Postguard corrupted\n"); + } + fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", + memblk->lastCheckedOK, memento.sequence); + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; + Memento_breakpointLocked(); + } + return 1; + } +#endif + return 0; +} + +static int checkBlock(Memento_BlkHeader *memblk, const char *action) +{ +#ifndef MEMENTO_LEAKONLY + BlkCheckData data; +#endif + + if (memblk->child != MEMENTO_CHILD_MAGIC || + memblk->sibling != MEMENTO_SIBLING_MAGIC) + { + /* Failure! */ + fprintf(stderr, "Attempt to %s invalid block ", action); + showBlock(memblk, 32); + fprintf(stderr, "\n"); + Memento_breakpointLocked(); + return 1; + } + +#ifndef MEMENTO_LEAKONLY + memset(&data, 0, sizeof(data)); + Memento_appBlock(&memento.used, Memento_Internal_checkAllocedBlock, + &data, memblk); + if (!data.found) { + /* Failure! */ + fprintf(stderr, "Attempt to %s block ", action); + showBlock(memblk, 32); + fprintf(stderr, "\n"); + Memento_breakpointLocked(); + return 1; + } else if (data.preCorrupt || data.postCorrupt) { + fprintf(stderr, "Block "); + showBlock(memblk, ' '); + fprintf(stderr, " found to be corrupted on %s!\n", action); + if (data.preCorrupt) { + fprintf(stderr, "Preguard corrupted\n"); + } + if (data.postCorrupt) { + fprintf(stderr, "Postguard corrupted\n"); + } + fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", + memblk->lastCheckedOK, memento.sequence); + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; + Memento_breakpointLocked(); + } + return 1; + } +#endif + return 0; +} + +static void do_free(void *blk, int eventType) +{ + Memento_BlkHeader *memblk; + + if (Memento_event()) Memento_breakpointLocked(); + + if (blk == NULL) + return; + + memblk = MEMBLK_FROMBLK(blk); + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + if (checkBlock(memblk, "free")) + return; + +#ifdef MEMENTO_DETAILS + Memento_storeDetails(memblk, Memento_EventType_free); +#endif + + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + if (memblk->flags & Memento_Flag_BreakOnFree) + Memento_breakpointLocked(); + + memento.alloc -= memblk->rawsize; + memento.numFrees++; + + Memento_removeBlock(&memento.used, memblk); + + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) { + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk), + memblk->rawsize + Memento_PostSize); +#ifndef MEMENTO_LEAKONLY + memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize); +#endif + memblk->flags |= Memento_Flag_Freed; + Memento_addBlockTail(&memento.free, memblk, 1); + } else { + free_block(memblk); + } +} + +void Memento_free(void *blk) +{ + if (!memento.inited) + Memento_init(); + + MEMENTO_LOCK(); + do_free(blk, Memento_EventType_free); + MEMENTO_UNLOCK(); +} + +static void *do_realloc(void *blk, size_t newsize, int type) +{ + Memento_BlkHeader *memblk, *newmemblk; + size_t newsizemem; + int flags; + + if (Memento_failThisEventLocked()) + return NULL; + + memblk = MEMBLK_FROMBLK(blk); + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + if (checkBlock(memblk, "realloc")) + return NULL; + +#ifdef MEMENTO_DETAILS + Memento_storeDetails(memblk, type); +#endif + + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + if (memblk->flags & Memento_Flag_BreakOnRealloc) + Memento_breakpointLocked(); + + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + if (memento.maxMemory != 0 && memento.alloc - memblk->rawsize + newsize > memento.maxMemory) + return NULL; + + newsizemem = MEMBLK_SIZE(newsize); + Memento_removeBlock(&memento.used, memblk); + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); + flags = memblk->flags; + newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem); + if (newmemblk == NULL) + { + Memento_addBlockHead(&memento.used, memblk, 2); + return NULL; + } + memento.numReallocs++; + memento.totalAlloc += newsize; + memento.alloc -= newmemblk->rawsize; + memento.alloc += newsize; + if (memento.peakAlloc < memento.alloc) + memento.peakAlloc = memento.alloc; + newmemblk->flags = flags; +#ifndef MEMENTO_LEAKONLY + if (newmemblk->rawsize < newsize) { + char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk))+newmemblk->rawsize; + VALGRIND_MAKE_MEM_DEFINED(newbytes, newsize - newmemblk->rawsize); + memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize); + VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize); + } +#endif + newmemblk->rawsize = newsize; +#ifndef MEMENTO_LEAKONLY + VALGRIND_MAKE_MEM_DEFINED(newmemblk->preblk, Memento_PreSize); + memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize); + VALGRIND_MAKE_MEM_UNDEFINED(newmemblk->preblk, Memento_PreSize); + VALGRIND_MAKE_MEM_DEFINED(MEMBLK_POSTPTR(newmemblk), Memento_PostSize); + memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize); + VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_POSTPTR(newmemblk), Memento_PostSize); +#endif + Memento_addBlockHead(&memento.used, newmemblk, 2); + return MEMBLK_TOBLK(newmemblk); +} + +void *Memento_realloc(void *blk, size_t newsize) +{ + void *ret; + + if (!memento.inited) + Memento_init(); + + if (blk == NULL) + { + MEMENTO_LOCK(); + ret = do_malloc(newsize, Memento_EventType_realloc); + MEMENTO_UNLOCK(); + return ret; + } + if (newsize == 0) { + MEMENTO_LOCK(); + do_free(blk, Memento_EventType_realloc); + MEMENTO_UNLOCK(); + return NULL; + } + + MEMENTO_LOCK(); + ret = do_realloc(blk, newsize, Memento_EventType_realloc); + MEMENTO_UNLOCK(); + return ret; +} + +int Memento_checkBlock(void *blk) +{ + Memento_BlkHeader *memblk; + int ret; + + if (blk == NULL) + return 0; + + MEMENTO_LOCK(); + memblk = MEMBLK_FROMBLK(blk); + ret = checkBlockUser(memblk, "check"); + MEMENTO_UNLOCK(); + return ret; +} + +#ifndef MEMENTO_LEAKONLY +static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg) +{ + BlkCheckData *data = (BlkCheckData *)arg; + + Memento_Internal_checkAllocedBlock(memblk, data); + if (data->preCorrupt || data->postCorrupt) { + if ((data->found & 2) == 0) { + fprintf(stderr, "Allocated blocks:\n"); + data->found |= 2; + } + fprintf(stderr, " Block "); + showBlock(memblk, ' '); + if (data->preCorrupt) { + fprintf(stderr, " Preguard "); + } + if (data->postCorrupt) { + fprintf(stderr, "%s Postguard ", + (data->preCorrupt ? "&" : "")); + } + fprintf(stderr, "corrupted.\n " + "Block last checked OK at allocation %d. Now %d.\n", + memblk->lastCheckedOK, memento.sequence); + data->preCorrupt = 0; + data->postCorrupt = 0; + data->freeCorrupt = 0; + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; + Memento_breakpointLocked(); + } + } + else + memblk->lastCheckedOK = memento.sequence; + return 0; +} + +static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg) +{ + BlkCheckData *data = (BlkCheckData *)arg; + + Memento_Internal_checkFreedBlock(memblk, data); + if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) { + if ((data->found & 4) == 0) { + fprintf(stderr, "Freed blocks:\n"); + data->found |= 4; + } + fprintf(stderr, " "); + showBlock(memblk, ' '); + if (data->freeCorrupt) { + fprintf(stderr, " index %d (address "FMTP") onwards", (int)data->index, + &((char *)MEMBLK_TOBLK(memblk))[data->index]); + if (data->preCorrupt) { + fprintf(stderr, "+ preguard"); + } + if (data->postCorrupt) { + fprintf(stderr, "+ postguard"); + } + } else { + if (data->preCorrupt) { + fprintf(stderr, " preguard"); + } + if (data->postCorrupt) { + fprintf(stderr, "%s Postguard", + (data->preCorrupt ? "+" : "")); + } + } + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(Memento_BlkHeader)); + fprintf(stderr, " corrupted.\n" + " Block last checked OK at allocation %d. Now %d.\n", + memblk->lastCheckedOK, memento.sequence); + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; + Memento_breakpointLocked(); + } + VALGRIND_MAKE_MEM_NOACCESS(memblk, sizeof(Memento_BlkHeader)); + data->preCorrupt = 0; + data->postCorrupt = 0; + data->freeCorrupt = 0; + } + else + memblk->lastCheckedOK = memento.sequence; + return 0; +} +#endif /* MEMENTO_LEAKONLY */ + +static int Memento_checkAllMemoryLocked(void) +{ +#ifndef MEMENTO_LEAKONLY + BlkCheckData data; + + memset(&data, 0, sizeof(data)); + Memento_appBlocks(&memento.used, Memento_Internal_checkAllAlloced, &data); + Memento_appBlocks(&memento.free, Memento_Internal_checkAllFreed, &data); + return data.found; +#else + return 0; +#endif +} + +int Memento_checkAllMemory(void) +{ +#ifndef MEMENTO_LEAKONLY + int ret; + + MEMENTO_LOCK(); + ret = Memento_checkAllMemoryLocked(); + MEMENTO_UNLOCK(); + if (ret & 6) { + Memento_breakpoint(); + return 1; + } + return 0; +#endif +} + +int Memento_setParanoia(int i) +{ + memento.paranoia = i; + if (memento.paranoia > 0) + memento.countdown = memento.paranoia; + else + memento.countdown = -memento.paranoia; + return i; +} + +int Memento_paranoidAt(int i) +{ + memento.paranoidAt = i; + return i; +} + +int Memento_getBlockNum(void *b) +{ + Memento_BlkHeader *memblk; + if (b == NULL) + return 0; + memblk = MEMBLK_FROMBLK(b); + return (memblk->sequence); +} + +int Memento_check(void) +{ + int result; + + fprintf(stderr, "Checking memory\n"); + result = Memento_checkAllMemory(); + fprintf(stderr, "Memory checked!\n"); + return result; +} + +int Memento_find(void *a) +{ + findBlkData data; + int s; + + MEMENTO_LOCK(); + data.addr = a; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.used, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Address "FMTP" is in %sallocated block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + s = showBlock(data.blk, ' '); + fprintf(stderr, "\n"); + MEMENTO_UNLOCK(); + return s; + } + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.free, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Address "FMTP" is in %sfreed block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + s = showBlock(data.blk, ' '); + fprintf(stderr, "\n"); + MEMENTO_UNLOCK(); + return s; + } + MEMENTO_UNLOCK(); + return 0; +} + +void Memento_breakOnFree(void *a) +{ + findBlkData data; + + MEMENTO_LOCK(); + data.addr = a; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.used, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, ") is freed\n"); + VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader)); + data.blk->flags |= Memento_Flag_BreakOnFree; + VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader)); + MEMENTO_UNLOCK(); + return; + } + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.free, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Can't stop on free; address "FMTP" is in %sfreed block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, "\n"); + MEMENTO_UNLOCK(); + return; + } + fprintf(stderr, "Can't stop on free; address "FMTP" is not in a known block.\n", a); + MEMENTO_UNLOCK(); +} + +void Memento_breakOnRealloc(void *a) +{ + findBlkData data; + + MEMENTO_LOCK(); + data.addr = a; + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.used, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, ") is freed (or realloced)\n"); + VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader)); + data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc; + VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader)); + MEMENTO_UNLOCK(); + return; + } + data.blk = NULL; + data.flags = 0; + Memento_appBlocks(&memento.free, Memento_containsAddr, &data); + if (data.blk != NULL) { + fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is in %sfreed block ", + data.addr, + (data.flags == 1 ? "" : (data.flags == 2 ? + "preguard of " : "postguard of "))); + showBlock(data.blk, ' '); + fprintf(stderr, "\n"); + MEMENTO_UNLOCK(); + return; + } + fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is not in a known block.\n", a); + MEMENTO_UNLOCK(); +} + +int Memento_failAt(int i) +{ + memento.failAt = i; + if ((memento.sequence > memento.failAt) && + (memento.failing != 0)) + Memento_startFailing(); + return i; +} + +size_t Memento_setMax(size_t max) +{ + memento.maxMemory = max; + return max; +} + +void Memento_startLeaking(void) +{ + memento.leaking++; +} + +void Memento_stopLeaking(void) +{ + memento.leaking--; +} + +int Memento_squeezing(void) +{ + return memento.squeezing; +} + +#endif /* MEMENTO_CPP_EXTRAS_ONLY */ + +#ifdef __cplusplus +/* Dumb overrides for the new and delete operators */ + +void *operator new(size_t size) +{ + void *ret; + + if (!memento.inited) + Memento_init(); + + if (size == 0) + size = 1; + MEMENTO_LOCK(); + ret = do_malloc(size, Memento_EventType_new); + MEMENTO_UNLOCK(); + return ret; +} + +void operator delete(void *pointer) +{ + if (!pointer) + return; + + MEMENTO_LOCK(); + do_free(pointer, Memento_EventType_delete); + MEMENTO_UNLOCK(); +} + +/* Some C++ systems (apparently) don't provide new[] or delete[] + * operators. Provide a way to cope with this */ +#ifndef MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS +void *operator new[](size_t size) +{ + void *ret; + if (!memento.inited) + Memento_init(); + + if (size == 0) + size = 1; + MEMENTO_LOCK(); + ret = do_malloc(size, Memento_EventType_newArray); + MEMENTO_UNLOCK(); + return ret; +} + +void operator delete[](void *pointer) +{ + MEMENTO_LOCK(); + do_free(pointer, Memento_EventType_deleteArray); + MEMENTO_UNLOCK(); +} +#endif /* MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS */ +#endif /* __cplusplus */ + +#else + +/* Just in case anyone has left some debugging code in... */ +void (Memento_breakpoint)(void) +{ +} + +int (Memento_checkBlock)(void *b) +{ + return 0; +} + +int (Memento_checkAllMemory)(void) +{ + return 0; +} + +int (Memento_check)(void) +{ + return 0; +} + +int (Memento_setParanoia)(int i) +{ + return 0; +} + +int (Memento_paranoidAt)(int i) +{ + return 0; +} + +int (Memento_breakAt)(int i) +{ + return 0; +} + +int (Memento_getBlockNum)(void *i) +{ + return 0; +} + +int (Memento_find)(void *a) +{ + return 0; +} + +int (Memento_failAt)(int i) +{ + return 0; +} + +void (Memento_breakOnFree)(void *a) +{ +} + +void (Memento_breakOnRealloc)(void *a) +{ +} + +void *(Memento_takeRef)(void *a) +{ + return a; +} + +void *(Memento_dropRef)(void *a) +{ + return a; +} + +void *(Memento_adjustRef)(void *a, int adjust) +{ + return a; +} + +void *(Memento_reference)(void *a) +{ + return a; +} + +#undef Memento_malloc +#undef Memento_free +#undef Memento_realloc +#undef Memento_calloc + +void *Memento_malloc(size_t size) +{ + return MEMENTO_UNDERLYING_MALLOC(size); +} + +void Memento_free(void *b) +{ + MEMENTO_UNDERLYING_FREE(b); +} + +void *Memento_realloc(void *b, size_t s) +{ + return MEMENTO_UNDERLYING_REALLOC(b, s); +} + +void *Memento_calloc(size_t n, size_t s) +{ + return MEMENTO_UNDERLYING_CALLOC(n, s); +} + +void (Memento_listBlocks)(void) +{ +} + +void (Memento_listNewBlocks)(void) +{ +} + +size_t (Memento_setMax)(size_t max) +{ + return 0; +} + +void (Memento_stats)(void) +{ +} + +void *(Memento_label)(void *ptr, const char *label) +{ + return ptr; +} + +void (Memento_info)(void *addr) +{ +} + +void (Memento_listBlockInfo)(void) +{ +} + +void (Memento_startLeaking)(void) +{ +} + +void (Memento_stopLeaking)(void) +{ +} + +int (Memento_squeezing)(void) +{ + return 0; +} + +#endif diff --git a/library/src/main/cpp/jbig2/src/sha1.c b/library/src/main/cpp/jbig2/src/sha1.c new file mode 100644 index 00000000..1c691cc0 --- /dev/null +++ b/library/src/main/cpp/jbig2/src/sha1.c @@ -0,0 +1,376 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 07/2002 +By Ralph Giles +Still 100% public domain +modified for use with stdint types, autoconf +code cleanup, removed attribution comments +switched SHA1Final() argument order for consistency +use SHA1_ prefix for public api +move public api to sha1.h +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define SHA1HANDSOFF */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "os_types.h" +#include "sha1.h" + +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +/* FIXME: can we do this in an endian-proof way? */ +#ifdef WORDS_BIGENDIAN +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +#ifdef VERBOSE /* SAK */ +void +SHAPrintContext(SHA1_CTX *context, char *msg) +{ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, context->count[0], context->count[1], context->state[0], context->state[1], context->state[2], context->state[3], context->state[4]); +} +#endif /* VERBOSE */ + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +void +SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e; + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16 *block; + +#ifdef SHA1HANDSOFF + static uint8_t workspace[64]; + + block = (CHAR64LONG16 *) workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + +/* SHA1Init - Initialize new context */ +void +SHA1_Init(SHA1_CTX *context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +/* Run your data through this. */ +void +SHA1_Update(SHA1_CTX *context, const uint8_t *data, const size_t len) +{ + size_t i, j; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + SHA1_Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + j = 0; + } else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); + +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + +/* Add padding and return the message digest. */ +void +SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE]) +{ + uint32_t i; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ + } + SHA1_Update(context, (uint8_t *) "\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (uint8_t *) "\0", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = (uint8_t) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); /* SWR */ + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} + +/*************************************************************/ + +#if 0 +int +main(int argc, char **argv) +{ + int i, j; + SHA1_CTX context; + unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384]; + FILE *file; + + if (argc > 2) { + puts("Public domain SHA-1 implementation - by Steve Reid "); + puts("Modified for 16 bit environments 7/98 - by James H. Brown "); /* JHB */ + puts("Produces the SHA-1 hash of a file, or stdin if no file is specified."); + return (0); + } + if (argc < 2) { + file = stdin; + } else { + if (!(file = fopen(argv[1], "rb"))) { + fputs("Unable to open file.", stderr); + return (-1); + } + } + SHA1_Init(&context); + while (!feof(file)) { /* note: what if ferror(file) */ + i = fread(buffer, 1, 16384, file); + SHA1_Update(&context, buffer, i); + } + SHA1_Final(&context, digest); + fclose(file); + for (i = 0; i < SHA1_DIGEST_SIZE / 4; i++) { + for (j = 0; j < 4; j++) { + printf("%02X", digest[i * 4 + j]); + } + putchar(' '); + } + putchar('\n'); + return (0); /* JHB */ +} +#endif + +/* self test */ + +#ifdef TEST + +static char *test_data[] = { + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "A million repetitions of 'a'" +}; +static char *test_results[] = { + "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", + "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", + "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F" +}; + +void +digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output) +{ + int i, j; + char *c = output; + + for (i = 0; i < SHA1_DIGEST_SIZE / 4; i++) { + for (j = 0; j < 4; j++) { + sprintf(c, "%02X", digest[i * 4 + j]); + c += 2; + } + sprintf(c, " "); + c += 1; + } + *(c - 1) = '\0'; +} + +int +main(int argc, char **argv) +{ + int k; + SHA1_CTX context; + uint8_t digest[20]; + char output[80]; + + fprintf(stdout, "verifying SHA-1 implementation... "); + + for (k = 0; k < 2; k++) { + SHA1_Init(&context); + SHA1_Update(&context, (uint8_t *) test_data[k], strlen(test_data[k])); + SHA1_Final(&context, digest); + digest_to_hex(digest, output); + + if (strcmp(output, test_results[k])) { + fprintf(stdout, "FAIL\n"); + fprintf(stderr, "* hash of \"%s\" incorrect:\n", test_data[k]); + fprintf(stderr, "\t%s returned\n", output); + fprintf(stderr, "\t%s is correct\n", test_results[k]); + return (1); + } + } + /* million 'a' vector we feed separately */ + SHA1_Init(&context); + for (k = 0; k < 1000000; k++) + SHA1_Update(&context, (uint8_t *) "a", 1); + SHA1_Final(&context, digest); + digest_to_hex(digest, output); + if (strcmp(output, test_results[2])) { + fprintf(stdout, "FAIL\n"); + fprintf(stderr, "* hash of \"%s\" incorrect:\n", test_data[2]); + fprintf(stderr, "\t%s returned\n", output); + fprintf(stderr, "\t%s is correct\n", test_results[2]); + return (1); + } + + /* success */ + fprintf(stdout, "ok\n"); + return (0); +} +#endif /* TEST */ diff --git a/library/src/main/cpp/jpeg/CMakeLists.txt b/library/src/main/cpp/jpeg/CMakeLists.txt new file mode 100644 index 00000000..956121b4 --- /dev/null +++ b/library/src/main/cpp/jpeg/CMakeLists.txt @@ -0,0 +1,44 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +set(TARGET jpegUse) +set(SRC_DIR src) + +include_directories(include) + +#add_library(jpeg SHARED IMPORTED) +#set_target_properties(jpeg PROPERTIES IMPORTED_LOCATION +# ${CMAKE_CURRENT_SOURCE_DIR}/../../../../libs/${ANDROID_ABI}/libjpeg.so) + + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +aux_source_directory(${SRC_DIR} DIR_LIB_SOURCE) + +add_library(${TARGET} SHARED ${DIR_LIB_SOURCE} JpegJNI.cpp) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +target_link_libraries(${TARGET} log android) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +#if(${ANDROID_ABI} STREQUAL x86 OR ${ANDROID_ABI} STREQUAL x86_64) +#target_link_libraries(${TARGET} opencv_imgproc opencv_core ippiw ippicv ittnotify tbb cpufeatures) +#else() +#target_link_libraries(${TARGET}) +#endif() + diff --git a/library/src/main/cpp/jpeg/JpegJNI.cpp b/library/src/main/cpp/jpeg/JpegJNI.cpp new file mode 100644 index 00000000..e15c7c8b --- /dev/null +++ b/library/src/main/cpp/jpeg/JpegJNI.cpp @@ -0,0 +1,144 @@ +// +// Created by 钟元杰 on 2022/9/19. +// + +//#include "include/IccDemo.h" + +#include +//#include +#include +#include +#include +#include +#include +#include + +#include "jpeglib.h" +#include "jpegint.h" + +//#define TAG "Jpeg_ceshi" +//#define pri_debug(format, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s:%d]" format, "XSOOY", __LINE__, ##args) + + +extern "C"{ +unsigned char* ConvertJByteaArrayToChars(JNIEnv *env, jbyteArray bytearray) +{ + + unsigned char *chars = nullptr; + jbyte *bytes; + bytes = env->GetByteArrayElements(bytearray, 0); + int chars_len = env->GetArrayLength(bytearray); + chars = new unsigned char[chars_len + 1]; + memset(chars,0,chars_len + 1); + memcpy(chars, bytes, chars_len); + chars[chars_len] = 0; + + env->ReleaseByteArrayElements(bytearray, bytes, 0); + return chars; +} + +jbyteArray ConvertCharsToJByteaArray(JNIEnv *env, unsigned char *buff,int size) +{ + jbyteArray arr = env->NewByteArray(size); + env->SetByteArrayRegion(arr, 0, size, (jbyte*)buff); + return arr; +} + +JNIEXPORT jbyteArray JNICALL Java_com_xsooy_jpeg_JpegUtils_converData(JNIEnv *env, jobject thiz, jbyteArray data) { + unsigned char *pmsg = ConvertJByteaArrayToChars(env,data); + int chars_len = env->GetArrayLength(data); + + struct jpeg_decompress_struct cinfo; + + jpeg_create_decompress(&cinfo); + + struct jpeg_error_mgr mjerr; + cinfo.err = jpeg_std_error(&mjerr); + + jpeg_mem_src(&cinfo, pmsg, chars_len); + + jpeg_read_header(&cinfo,TRUE); + + jpeg_start_decompress(&cinfo); + + unsigned int width = cinfo.output_width; + unsigned int height = cinfo.output_height; + unsigned short depth = cinfo.output_components; //get from libjpeg. 1 for gray, 3 for color. + + +// pri_debug("cinfo.jpeg_color_space:%d",cinfo.quantize_colors); +// pri_debug("cinfo.out_color_space:%d",cinfo.out_color_space); +// pri_debug("cinfo.out_color_space:%s",cinfo.colormap[0]); + + JSAMPROW row_pointer[1]; + unsigned long location = 0; + unsigned char * raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components ); + row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components ); + + + for (int y=0;yGetArrayLength(result)); + return result; +} + +JNIEXPORT void JNICALL Java_com_xsooy_jpeg_JpegUtils_converDataToArray(JNIEnv *env, jobject thiz, jbyteArray data,jbyteArray output) { + unsigned char *pmsg = ConvertJByteaArrayToChars(env,data); + int chars_len = env->GetArrayLength(data); + + struct jpeg_decompress_struct cinfo; + + jpeg_create_decompress(&cinfo); + + struct jpeg_error_mgr mjerr; + cinfo.err = jpeg_std_error(&mjerr); + + jpeg_mem_src(&cinfo, pmsg, chars_len); + + jpeg_read_header(&cinfo,TRUE); + + jpeg_start_decompress(&cinfo); + + unsigned int width = cinfo.output_width; + unsigned int height = cinfo.output_height; + unsigned short depth = cinfo.output_components; //get from libjpeg. 1 for gray, 3 for color. + +// pri_debug("cinfo.jpeg_color_space:%d",cinfo.quantize_colors); +// pri_debug("cinfo.out_color_space:%d",cinfo.out_color_space); +// pri_debug("cinfo.out_color_space:%s",cinfo.colormap[0]); + + JSAMPROW row_pointer[1]; + unsigned long location = 0; +// unsigned char * raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components ); +// unsigned char * raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.num_components ); + row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components); + + for (int y=0;ySetByteArrayRegion(output, width*depth*y, width*depth, (jbyte*)row_pointer[0]); +// for(int i=0; idct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_h_scaled_size * DCT_v_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_fdct_7x7 jFD7x7 +#define jpeg_fdct_6x6 jFD6x6 +#define jpeg_fdct_5x5 jFD5x5 +#define jpeg_fdct_4x4 jFD4x4 +#define jpeg_fdct_3x3 jFD3x3 +#define jpeg_fdct_2x2 jFD2x2 +#define jpeg_fdct_1x1 jFD1x1 +#define jpeg_fdct_9x9 jFD9x9 +#define jpeg_fdct_10x10 jFD10x10 +#define jpeg_fdct_11x11 jFD11x11 +#define jpeg_fdct_12x12 jFD12x12 +#define jpeg_fdct_13x13 jFD13x13 +#define jpeg_fdct_14x14 jFD14x14 +#define jpeg_fdct_15x15 jFD15x15 +#define jpeg_fdct_16x16 jFD16x16 +#define jpeg_fdct_16x8 jFD16x8 +#define jpeg_fdct_14x7 jFD14x7 +#define jpeg_fdct_12x6 jFD12x6 +#define jpeg_fdct_10x5 jFD10x5 +#define jpeg_fdct_8x4 jFD8x4 +#define jpeg_fdct_6x3 jFD6x3 +#define jpeg_fdct_4x2 jFD4x2 +#define jpeg_fdct_2x1 jFD2x1 +#define jpeg_fdct_8x16 jFD8x16 +#define jpeg_fdct_7x14 jFD7x14 +#define jpeg_fdct_6x12 jFD6x12 +#define jpeg_fdct_5x10 jFD5x10 +#define jpeg_fdct_4x8 jFD4x8 +#define jpeg_fdct_3x6 jFD3x6 +#define jpeg_fdct_2x4 jFD2x4 +#define jpeg_fdct_1x2 jFD1x2 +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_7x7 jRD7x7 +#define jpeg_idct_6x6 jRD6x6 +#define jpeg_idct_5x5 jRD5x5 +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_3x3 jRD3x3 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#define jpeg_idct_9x9 jRD9x9 +#define jpeg_idct_10x10 jRD10x10 +#define jpeg_idct_11x11 jRD11x11 +#define jpeg_idct_12x12 jRD12x12 +#define jpeg_idct_13x13 jRD13x13 +#define jpeg_idct_14x14 jRD14x14 +#define jpeg_idct_15x15 jRD15x15 +#define jpeg_idct_16x16 jRD16x16 +#define jpeg_idct_16x8 jRD16x8 +#define jpeg_idct_14x7 jRD14x7 +#define jpeg_idct_12x6 jRD12x6 +#define jpeg_idct_10x5 jRD10x5 +#define jpeg_idct_8x4 jRD8x4 +#define jpeg_idct_6x3 jRD6x3 +#define jpeg_idct_4x2 jRD4x2 +#define jpeg_idct_2x1 jRD2x1 +#define jpeg_idct_8x16 jRD8x16 +#define jpeg_idct_7x14 jRD7x14 +#define jpeg_idct_6x12 jRD6x12 +#define jpeg_idct_5x10 jRD5x10 +#define jpeg_idct_4x8 jRD4x8 +#define jpeg_idct_3x6 jRD3x8 +#define jpeg_idct_2x4 jRD2x4 +#define jpeg_idct_1x2 jRD1x2 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_ifast + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_float + JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_7x7 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_6x6 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_5x5 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_4x4 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_3x3 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_2x2 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_1x1 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_9x9 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_10x10 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_11x11 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_12x12 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_13x13 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_14x14 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_15x15 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_16x16 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_16x8 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_14x7 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_12x6 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_10x5 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_8x4 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_6x3 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_4x2 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_2x1 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_8x16 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_7x14 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_6x12 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_5x10 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_4x8 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_3x6 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_2x4 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); +EXTERN(void) jpeg_fdct_1x2 + JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_7x7 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_6x6 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_5x5 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_3x3 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_9x9 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_10x10 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_11x11 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_12x12 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_13x13 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_14x14 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_15x15 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_16x16 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_16x8 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_14x7 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_12x6 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_10x5 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_8x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_6x3 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_8x16 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_7x14 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_6x12 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_5x10 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x8 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_3x6 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/library/src/main/cpp/jpeg/include/jerror.h b/library/src/main/cpp/jpeg/include/jerror.h new file mode 100644 index 00000000..1cfb2b19 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jerror.h @@ -0,0 +1,304 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported") +JMESSAGE(JERR_BAD_DROP_SAMPLING, + "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (cinfo)->err->msg_parm.i[4] = (p5), \ + (cinfo)->err->msg_parm.i[5] = (p6), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/library/src/main/cpp/jpeg/include/jinclude.h b/library/src/main/cpp/jpeg/include/jinclude.h new file mode 100644 index 00000000..0a4f1514 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/library/src/main/cpp/jpeg/include/jmemsys.h b/library/src/main/cpp/jpeg/include/jmemsys.h new file mode 100644 index 00000000..6c3c6d34 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/library/src/main/cpp/jpeg/include/jmorecfg.h b/library/src/main/cpp/jpeg/include/jmorecfg.h new file mode 100644 index 00000000..6c085c36 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jmorecfg.h @@ -0,0 +1,369 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ +#ifndef _BASETSD_H /* MinGW is slightly different */ +#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ +typedef long INT32; +#endif +#endif +#endif +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifndef FAR +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/library/src/main/cpp/jpeg/include/jpegint.h b/library/src/main/cpp/jpeg/include/jpegint.h new file mode 100644 index 00000000..c0d5c142 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jpegint.h @@ -0,0 +1,426 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +typedef JMETHOD(void, forward_DCT_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); + +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* It is useful to allow each component to have a separate FDCT method. */ + forward_DCT_ptr forward_DCT[MAX_COMPONENTS]; +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_arith_encoder jIAEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_arith_decoder jIADecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jzero_far jZeroFar +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#define jpeg_natural_order7 jZAG7Table +#define jpeg_natural_order6 jZAG6Table +#define jpeg_natural_order5 jZAG5Table +#define jpeg_natural_order4 jZAG4Table +#define jpeg_natural_order3 jZAG3Table +#define jpeg_natural_order2 jZAG2Table +#define jpeg_aritab jAriTab +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines in jutils.c do it the hard way. + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case */ +#ifdef USE_FMEM +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#else +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +#define FMEMZERO(target,size) jzero_far(target, size) +#endif +#endif + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ +extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */ +extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */ +extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */ +extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */ +extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */ +extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */ + +/* Arithmetic coding probability estimation tables in jaricom.c */ +extern const INT32 jpeg_aritab[]; + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/library/src/main/cpp/jpeg/include/jpeglib.h b/library/src/main/cpp/jpeg/include/jpeglib.h new file mode 100644 index 00000000..c4e3cfa4 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jpeglib.h @@ -0,0 +1,1173 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2002-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + + +#include + +#define TAG "Jpeg_ceshi" +#define pri_debug(format, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s:%d]" format, "1234444", __LINE__, ##args) + + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +extern "C" { +#endif +#endif + +/* Version IDs for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 80". + */ + +#define JPEG_LIB_VERSION 80 /* Compatibility version 8.0 */ +#define JPEG_LIB_VERSION_MAJOR 8 +#define JPEG_LIB_VERSION_MINOR 4 + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples, + * reflecting any scaling we choose to apply during the DCT step. + * Values from 1 to 16 are supported. + * Note that different components may receive different DCT scalings. + */ + int DCT_h_scaled_size; + int DCT_v_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface); + * DCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_h_scaled_size/DCTSIZE) + * and similarly for height. + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + JDIMENSION jpeg_width; /* scaled JPEG image width */ + JDIMENSION jpeg_height; /* scaled JPEG image height */ + /* Dimensions of actual JPEG image that will be written to file, + * derived from input dimensions by scaling factors above. + * These fields are computed by jpeg_start_compress(). + * You can also use jpeg_calc_jpeg_dimensions() to determine these values + * in advance of calling jpeg_start_compress(). + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + int q_scale_factor[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined, + * and corresponding scale factors (percentage, initialized 100). + */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* These fields are derived from Se of first SOS marker. + */ + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array for entropy decode */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_mem_dest jMemDest +#define jpeg_mem_src jMemSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_default_qtables jDefQTables +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_calc_jpeg_dimensions jCjpegDimensions +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_core_output_dimensions jCoreDimensions +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Data source and destination managers: memory buffers. */ +EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, + unsigned char ** outbuffer, + unsigned long * outsize)); +EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, + unsigned char * inbuffer, + unsigned long insize)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Precalculate JPEG dimensions for current compression parameters. */ +EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.txt concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + +/* IvanDebug, 在Android系统中使用libjpeg,会出现tmpFile()函数无法创建临时文件的问题,导致无法解析jpeg图像,在这里增加接口供上层设置临时文件目录。*/ +static char ANSI_TEMP_FOLDER_PATH[512]; +EXTERN(void) jpeg_set_temp_folder JPP(( const char *tempFolderPath)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +} +#endif +#endif + +#endif /* JPEGLIB_H */ diff --git a/library/src/main/cpp/jpeg/include/jversion.h b/library/src/main/cpp/jpeg/include/jversion.h new file mode 100644 index 00000000..5d491510 --- /dev/null +++ b/library/src/main/cpp/jpeg/include/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "8d 15-Jan-2012" + +#define JCOPYRIGHT "Copyright (C) 2012, Thomas G. Lane, Guido Vollbeding" diff --git a/library/src/main/cpp/jpeg/src/jaricom.c b/library/src/main/cpp/jpeg/src/jaricom.c new file mode 100644 index 00000000..69006886 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jaricom.c @@ -0,0 +1,153 @@ +/* + * jaricom.c + * + * Developed 1997-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains probability estimation tables for common use in + * arithmetic entropy encoding and decoding routines. + * + * This data represents Table D.3 in the JPEG spec (D.2 in the draft), + * ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24 + * in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +/* The following #define specifies the packing of the four components + * into the compact INT32 representation. + * Note that this formula must match the actual arithmetic encoder + * and decoder implementation. The implementation has to be changed + * if this formula is changed. + * The current organization is leaned on Markus Kuhn's JBIG + * implementation (jbig_tab.c). + */ + +#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b) + +const INT32 jpeg_aritab[113+1] = { +/* + * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS + */ + V( 0, 0x5a1d, 1, 1, 1 ), + V( 1, 0x2586, 14, 2, 0 ), + V( 2, 0x1114, 16, 3, 0 ), + V( 3, 0x080b, 18, 4, 0 ), + V( 4, 0x03d8, 20, 5, 0 ), + V( 5, 0x01da, 23, 6, 0 ), + V( 6, 0x00e5, 25, 7, 0 ), + V( 7, 0x006f, 28, 8, 0 ), + V( 8, 0x0036, 30, 9, 0 ), + V( 9, 0x001a, 33, 10, 0 ), + V( 10, 0x000d, 35, 11, 0 ), + V( 11, 0x0006, 9, 12, 0 ), + V( 12, 0x0003, 10, 13, 0 ), + V( 13, 0x0001, 12, 13, 0 ), + V( 14, 0x5a7f, 15, 15, 1 ), + V( 15, 0x3f25, 36, 16, 0 ), + V( 16, 0x2cf2, 38, 17, 0 ), + V( 17, 0x207c, 39, 18, 0 ), + V( 18, 0x17b9, 40, 19, 0 ), + V( 19, 0x1182, 42, 20, 0 ), + V( 20, 0x0cef, 43, 21, 0 ), + V( 21, 0x09a1, 45, 22, 0 ), + V( 22, 0x072f, 46, 23, 0 ), + V( 23, 0x055c, 48, 24, 0 ), + V( 24, 0x0406, 49, 25, 0 ), + V( 25, 0x0303, 51, 26, 0 ), + V( 26, 0x0240, 52, 27, 0 ), + V( 27, 0x01b1, 54, 28, 0 ), + V( 28, 0x0144, 56, 29, 0 ), + V( 29, 0x00f5, 57, 30, 0 ), + V( 30, 0x00b7, 59, 31, 0 ), + V( 31, 0x008a, 60, 32, 0 ), + V( 32, 0x0068, 62, 33, 0 ), + V( 33, 0x004e, 63, 34, 0 ), + V( 34, 0x003b, 32, 35, 0 ), + V( 35, 0x002c, 33, 9, 0 ), + V( 36, 0x5ae1, 37, 37, 1 ), + V( 37, 0x484c, 64, 38, 0 ), + V( 38, 0x3a0d, 65, 39, 0 ), + V( 39, 0x2ef1, 67, 40, 0 ), + V( 40, 0x261f, 68, 41, 0 ), + V( 41, 0x1f33, 69, 42, 0 ), + V( 42, 0x19a8, 70, 43, 0 ), + V( 43, 0x1518, 72, 44, 0 ), + V( 44, 0x1177, 73, 45, 0 ), + V( 45, 0x0e74, 74, 46, 0 ), + V( 46, 0x0bfb, 75, 47, 0 ), + V( 47, 0x09f8, 77, 48, 0 ), + V( 48, 0x0861, 78, 49, 0 ), + V( 49, 0x0706, 79, 50, 0 ), + V( 50, 0x05cd, 48, 51, 0 ), + V( 51, 0x04de, 50, 52, 0 ), + V( 52, 0x040f, 50, 53, 0 ), + V( 53, 0x0363, 51, 54, 0 ), + V( 54, 0x02d4, 52, 55, 0 ), + V( 55, 0x025c, 53, 56, 0 ), + V( 56, 0x01f8, 54, 57, 0 ), + V( 57, 0x01a4, 55, 58, 0 ), + V( 58, 0x0160, 56, 59, 0 ), + V( 59, 0x0125, 57, 60, 0 ), + V( 60, 0x00f6, 58, 61, 0 ), + V( 61, 0x00cb, 59, 62, 0 ), + V( 62, 0x00ab, 61, 63, 0 ), + V( 63, 0x008f, 61, 32, 0 ), + V( 64, 0x5b12, 65, 65, 1 ), + V( 65, 0x4d04, 80, 66, 0 ), + V( 66, 0x412c, 81, 67, 0 ), + V( 67, 0x37d8, 82, 68, 0 ), + V( 68, 0x2fe8, 83, 69, 0 ), + V( 69, 0x293c, 84, 70, 0 ), + V( 70, 0x2379, 86, 71, 0 ), + V( 71, 0x1edf, 87, 72, 0 ), + V( 72, 0x1aa9, 87, 73, 0 ), + V( 73, 0x174e, 72, 74, 0 ), + V( 74, 0x1424, 72, 75, 0 ), + V( 75, 0x119c, 74, 76, 0 ), + V( 76, 0x0f6b, 74, 77, 0 ), + V( 77, 0x0d51, 75, 78, 0 ), + V( 78, 0x0bb6, 77, 79, 0 ), + V( 79, 0x0a40, 77, 48, 0 ), + V( 80, 0x5832, 80, 81, 1 ), + V( 81, 0x4d1c, 88, 82, 0 ), + V( 82, 0x438e, 89, 83, 0 ), + V( 83, 0x3bdd, 90, 84, 0 ), + V( 84, 0x34ee, 91, 85, 0 ), + V( 85, 0x2eae, 92, 86, 0 ), + V( 86, 0x299a, 93, 87, 0 ), + V( 87, 0x2516, 86, 71, 0 ), + V( 88, 0x5570, 88, 89, 1 ), + V( 89, 0x4ca9, 95, 90, 0 ), + V( 90, 0x44d9, 96, 91, 0 ), + V( 91, 0x3e22, 97, 92, 0 ), + V( 92, 0x3824, 99, 93, 0 ), + V( 93, 0x32b4, 99, 94, 0 ), + V( 94, 0x2e17, 93, 86, 0 ), + V( 95, 0x56a8, 95, 96, 1 ), + V( 96, 0x4f46, 101, 97, 0 ), + V( 97, 0x47e5, 102, 98, 0 ), + V( 98, 0x41cf, 103, 99, 0 ), + V( 99, 0x3c3d, 104, 100, 0 ), + V( 100, 0x375e, 99, 93, 0 ), + V( 101, 0x5231, 105, 102, 0 ), + V( 102, 0x4c0f, 106, 103, 0 ), + V( 103, 0x4639, 107, 104, 0 ), + V( 104, 0x415e, 103, 99, 0 ), + V( 105, 0x5627, 105, 106, 1 ), + V( 106, 0x50e7, 108, 107, 0 ), + V( 107, 0x4b85, 109, 103, 0 ), + V( 108, 0x5597, 110, 109, 0 ), + V( 109, 0x504f, 111, 107, 0 ), + V( 110, 0x5a10, 110, 111, 1 ), + V( 111, 0x5522, 112, 109, 0 ), + V( 112, 0x59eb, 112, 111, 1 ), +/* + * This last entry is used for fixed probability estimate of 0.5 + * as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851. + */ + V( 113, 0x5a1d, 113, 113, 0 ) +}; diff --git a/library/src/main/cpp/jpeg/src/jcapimin.c b/library/src/main/cpp/jpeg/src/jcapimin.c new file mode 100644 index 00000000..639ce86f --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcapimin.c @@ -0,0 +1,288 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2003-2010 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_compress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + cinfo->quant_tbl_ptrs[i] = NULL; + cinfo->q_scale_factor[i] = 100; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Must do it here for emit_dqt in case jpeg_write_tables is used */ + cinfo->block_size = DCTSIZE; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + + cinfo->script_space = NULL; + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL(void) +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL(void) +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL(void) +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL(void) +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); + + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); + write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ + while (datalen--) { + (*write_marker_byte) (cinfo, *dataptr); + dataptr++; + } +} + +/* Same, but piecemeal. */ + +GLOBAL(void) +jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); +} + +GLOBAL(void) +jpeg_write_m_byte (j_compress_ptr cinfo, int val) +{ + (*cinfo->marker->write_marker_byte) (cinfo, val); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL(void) +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* + * In library releases up through v6a, we called jpeg_abort() here to free + * any working memory allocated by the destination manager and marker + * writer. Some applications had a problem with that: they allocated space + * of their own from the library memory manager, and didn't want it to go + * away during write_tables. So now we do nothing. This will cause a + * memory leak if an app calls write_tables repeatedly without doing a full + * compression cycle or otherwise resetting the JPEG object. However, that + * seems less bad than unexpectedly freeing memory in the normal case. + * An app that prefers the old behavior can call jpeg_abort for itself after + * each call to jpeg_write_tables(). + */ +} diff --git a/library/src/main/cpp/jpeg/src/jcapistd.c b/library/src/main/cpp/jpeg/src/jcapistd.c new file mode 100644 index 00000000..c0320b1b --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcapistd.c @@ -0,0 +1,161 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL(void) +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL(JDIMENSION) +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->coef->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/library/src/main/cpp/jpeg/src/jcarith.c b/library/src/main/cpp/jpeg/src/jcarith.c new file mode 100644 index 00000000..033f6706 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcarith.c @@ -0,0 +1,937 @@ +/* + * jcarith.c + * + * Developed 1997-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains portable arithmetic entropy encoding routines for JPEG + * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81). + * + * Both sequential and progressive modes are supported in this single module. + * + * Suspension is not currently supported in this module. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Expanded entropy encoder object for arithmetic encoding. */ + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */ + INT32 a; /* A register, normalized size of coding interval */ + INT32 sc; /* counter for stacked 0xFF values which might overflow */ + INT32 zc; /* counter for pending 0x00 output values which might * + * be discarded at the end ("Pacman" termination) */ + int ct; /* bit shift counter, determines when next byte will be written */ + int buffer; /* buffer for most recent output byte != 0xFF */ + + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to statistics areas (these workspaces have image lifespan) */ + unsigned char * dc_stats[NUM_ARITH_TBLS]; + unsigned char * ac_stats[NUM_ARITH_TBLS]; + + /* Statistics bin for coding with fixed probability 0.5 */ + unsigned char fixed_bin[4]; +} arith_entropy_encoder; + +typedef arith_entropy_encoder * arith_entropy_ptr; + +/* The following two definitions specify the allocation chunk size + * for the statistics area. + * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least + * 49 statistics bins for DC, and 245 statistics bins for AC coding. + * + * We use a compact representation with 1 byte per statistics bin, + * thus the numbers directly represent byte sizes. + * This 1 byte per statistics bin contains the meaning of the MPS + * (more probable symbol) in the highest bit (mask 0x80), and the + * index into the probability estimation state machine table + * in the lower bits (mask 0x7F). + */ + +#define DC_STAT_BINS 64 +#define AC_STAT_BINS 256 + +/* NOTE: Uncomment the following #define if you want to use the + * given formula for calculating the AC conditioning parameter Kx + * for spectral selection progressive coding in section G.1.3.2 + * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4). + * Although the spec and P&M authors claim that this "has proven + * to give good results for 8 bit precision samples", I'm not + * convinced yet that this is really beneficial. + * Early tests gave only very marginal compression enhancements + * (a few - around 5 or so - bytes even for very large files), + * which would turn out rather negative if we'd suppress the + * DAC (Define Arithmetic Conditioning) marker segments for + * the default parameters in the future. + * Note that currently the marker writing module emits 12-byte + * DAC segments for a full-component scan in a color image. + * This is not worth worrying about IMHO. However, since the + * spec defines the default values to be used if the tables + * are omitted (unlike Huffman tables, which are required + * anyway), one might optimize this behaviour in the future, + * and then it would be disadvantageous to use custom tables if + * they don't provide sufficient gain to exceed the DAC size. + * + * On the other hand, I'd consider it as a reasonable result + * that the conditioning has no significant influence on the + * compression performance. This means that the basic + * statistical model is already rather stable. + * + * Thus, at the moment, we use the default conditioning values + * anyway, and do not use the custom formula. + * +#define CALCULATE_SPECTRAL_CONDITIONING + */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +LOCAL(void) +emit_byte (int val, j_compress_ptr cinfo) +/* Write next output byte; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *dest->next_output_byte++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); +} + + +/* + * Finish up at the end of an arithmetic-compressed scan. + */ + +METHODDEF(void) +finish_pass (j_compress_ptr cinfo) +{ + arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; + INT32 temp; + + /* Section D.1.8: Termination of encoding */ + + /* Find the e->c in the coding interval with the largest + * number of trailing zero bits */ + if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c) + e->c = temp + 0x8000L; + else + e->c = temp; + /* Send remaining bytes to output */ + e->c <<= e->ct; + if (e->c & 0xF8000000L) { + /* One final overflow has to be handled */ + if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer + 1, cinfo); + if (e->buffer + 1 == 0xFF) + emit_byte(0x00, cinfo); + } + e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */ + e->sc = 0; + } else { + if (e->buffer == 0) + ++e->zc; + else if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer, cinfo); + } + if (e->sc) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + do { + emit_byte(0xFF, cinfo); + emit_byte(0x00, cinfo); + } while (--e->sc); + } + } + /* Output final bytes only if they are not 0x00 */ + if (e->c & 0x7FFF800L) { + if (e->zc) /* output final pending zero bytes */ + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte((e->c >> 19) & 0xFF, cinfo); + if (((e->c >> 19) & 0xFF) == 0xFF) + emit_byte(0x00, cinfo); + if (e->c & 0x7F800L) { + emit_byte((e->c >> 11) & 0xFF, cinfo); + if (((e->c >> 11) & 0xFF) == 0xFF) + emit_byte(0x00, cinfo); + } + } +} + + +/* + * The core arithmetic encoding routine (common in JPEG and JBIG). + * This needs to go as fast as possible. + * Machine-dependent optimization facilities + * are not utilized in this portable implementation. + * However, this code should be fairly efficient and + * may be a good base for further optimizations anyway. + * + * Parameter 'val' to be encoded may be 0 or 1 (binary decision). + * + * Note: I've added full "Pacman" termination support to the + * byte output routines, which is equivalent to the optional + * Discard_final_zeros procedure (Figure D.15) in the spec. + * Thus, we always produce the shortest possible output + * stream compliant to the spec (no trailing zero bytes, + * except for FF stuffing). + * + * I've also introduced a new scheme for accessing + * the probability estimation state machine table, + * derived from Markus Kuhn's JBIG implementation. + */ + +LOCAL(void) +arith_encode (j_compress_ptr cinfo, unsigned char *st, int val) +{ + register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; + register unsigned char nl, nm; + register INT32 qe, temp; + register int sv; + + /* Fetch values from our compact representation of Table D.3(D.2): + * Qe values and probability estimation state machine + */ + sv = *st; + qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */ + nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */ + nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */ + + /* Encode & estimation procedures per sections D.1.4 & D.1.5 */ + e->a -= qe; + if (val != (sv >> 7)) { + /* Encode the less probable symbol */ + if (e->a >= qe) { + /* If the interval size (qe) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency, otherwise code the LPS + * as usual: */ + e->c += e->a; + e->a = qe; + } + *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ + } else { + /* Encode the more probable symbol */ + if (e->a >= 0x8000L) + return; /* A >= 0x8000 -> ready, no renormalization required */ + if (e->a < qe) { + /* If the interval size (qe) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency: */ + e->c += e->a; + e->a = qe; + } + *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ + } + + /* Renormalization & data output per section D.1.6 */ + do { + e->a <<= 1; + e->c <<= 1; + if (--e->ct == 0) { + /* Another byte is ready for output */ + temp = e->c >> 19; + if (temp > 0xFF) { + /* Handle overflow over all stacked 0xFF bytes */ + if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer + 1, cinfo); + if (e->buffer + 1 == 0xFF) + emit_byte(0x00, cinfo); + } + e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */ + e->sc = 0; + /* Note: The 3 spacer bits in the C register guarantee + * that the new buffer byte can't be 0xFF here + * (see page 160 in the P&M JPEG book). */ + e->buffer = temp & 0xFF; /* new output byte, might overflow later */ + } else if (temp == 0xFF) { + ++e->sc; /* stack 0xFF byte (which might overflow later) */ + } else { + /* Output all stacked 0xFF bytes, they will not overflow any more */ + if (e->buffer == 0) + ++e->zc; + else if (e->buffer >= 0) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + emit_byte(e->buffer, cinfo); + } + if (e->sc) { + if (e->zc) + do emit_byte(0x00, cinfo); + while (--e->zc); + do { + emit_byte(0xFF, cinfo); + emit_byte(0x00, cinfo); + } while (--e->sc); + } + e->buffer = temp & 0xFF; /* new output byte (can still overflow) */ + } + e->c &= 0x7FFFFL; + e->ct += 8; + } + } while (e->a < 0x8000L); +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(void) +emit_restart (j_compress_ptr cinfo, int restart_num) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci; + jpeg_component_info * compptr; + + finish_pass(cinfo); + + emit_byte(0xFF, cinfo); + emit_byte(JPEG_RST0 + restart_num, cinfo); + + /* Re-initialize statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); + /* Reset DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + /* AC needs no table when not present */ + if (cinfo->Se) { + MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); + } + } + + /* Reset arithmetic encoding variables */ + entropy->c = 0; + entropy->a = 0x10000L; + entropy->sc = 0; + entropy->zc = 0; + entropy->ct = 11; + entropy->buffer = -1; /* empty */ +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int blkn, ci, tbl; + int v, v2, m; + ISHIFT_TEMPS + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + m = IRIGHT_SHIFT((int) ((*block)[0]), cinfo->Al); + + /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */ + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.4: Encode_DC_DIFF */ + if ((v = m - entropy->last_dc_val[ci]) == 0) { + arith_encode(cinfo, st, 0); + entropy->dc_context[ci] = 0; /* zero diff category */ + } else { + entropy->last_dc_val[ci] = m; + arith_encode(cinfo, st, 1); + /* Figure F.6: Encoding nonzero value v */ + /* Figure F.7: Encoding the sign of v */ + if (v > 0) { + arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */ + st += 2; /* Table F.4: SP = S0 + 2 */ + entropy->dc_context[ci] = 4; /* small positive diff category */ + } else { + v = -v; + arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */ + st += 3; /* Table F.4: SN = S0 + 3 */ + entropy->dc_context[ci] = 8; /* small negative diff category */ + } + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + arith_encode(cinfo, st, 0); + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] += 8; /* large diff category */ + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int tbl, k, ke; + int v, v2, m; + const int * natural_order; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */ + + /* Establish EOB (end-of-block) index */ + for (ke = cinfo->Se; ke > 0; ke--) + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if ((v = (*block)[natural_order[ke]]) >= 0) { + if (v >>= cinfo->Al) break; + } else { + v = -v; + if (v >>= cinfo->Al) break; + } + + /* Figure F.5: Encode_AC_Coefficients */ + for (k = cinfo->Ss; k <= ke; k++) { + st = entropy->ac_stats[tbl] + 3 * (k - 1); + arith_encode(cinfo, st, 0); /* EOB decision */ + for (;;) { + if ((v = (*block)[natural_order[k]]) >= 0) { + if (v >>= cinfo->Al) { + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 0); + break; + } + } else { + v = -v; + if (v >>= cinfo->Al) { + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 1); + break; + } + } + arith_encode(cinfo, st + 1, 0); st += 3; k++; + } + st += 2; + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + if (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + } + arith_encode(cinfo, st, 0); + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + /* Encode EOB decision only if k <= cinfo->Se */ + if (k <= cinfo->Se) { + st = entropy->ac_stats[tbl] + 3 * (k - 1); + arith_encode(cinfo, st, 1); + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + unsigned char *st; + int Al, blkn; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + st = entropy->fixed_bin; /* use fixed probability estimation */ + Al = cinfo->Al; + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + /* We simply emit the Al'th bit of the DC coefficient value. */ + arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1); + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int tbl, k, ke, kex; + int v; + const int * natural_order; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + /* Section G.1.3.3: Encoding of AC coefficients */ + + /* Establish EOB (end-of-block) index */ + for (ke = cinfo->Se; ke > 0; ke--) + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if ((v = (*block)[natural_order[ke]]) >= 0) { + if (v >>= cinfo->Al) break; + } else { + v = -v; + if (v >>= cinfo->Al) break; + } + + /* Establish EOBx (previous stage end-of-block) index */ + for (kex = ke; kex > 0; kex--) + if ((v = (*block)[natural_order[kex]]) >= 0) { + if (v >>= cinfo->Ah) break; + } else { + v = -v; + if (v >>= cinfo->Ah) break; + } + + /* Figure G.10: Encode_AC_Coefficients_SA */ + for (k = cinfo->Ss; k <= ke; k++) { + st = entropy->ac_stats[tbl] + 3 * (k - 1); + if (k > kex) + arith_encode(cinfo, st, 0); /* EOB decision */ + for (;;) { + if ((v = (*block)[natural_order[k]]) >= 0) { + if (v >>= cinfo->Al) { + if (v >> 1) /* previously nonzero coef */ + arith_encode(cinfo, st + 2, (v & 1)); + else { /* newly nonzero coef */ + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 0); + } + break; + } + } else { + v = -v; + if (v >>= cinfo->Al) { + if (v >> 1) /* previously nonzero coef */ + arith_encode(cinfo, st + 2, (v & 1)); + else { /* newly nonzero coef */ + arith_encode(cinfo, st + 1, 1); + arith_encode(cinfo, entropy->fixed_bin, 1); + } + break; + } + } + arith_encode(cinfo, st + 1, 0); st += 3; k++; + } + } + /* Encode EOB decision only if k <= cinfo->Se */ + if (k <= cinfo->Se) { + st = entropy->ac_stats[tbl] + 3 * (k - 1); + arith_encode(cinfo, st, 1); + } + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of arithmetic-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + jpeg_component_info * compptr; + JBLOCKROW block; + unsigned char *st; + int blkn, ci, tbl, k, ke; + int v, v2, m; + const int * natural_order; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + emit_restart(cinfo, entropy->next_restart_num); + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + natural_order = cinfo->natural_order; + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */ + + tbl = compptr->dc_tbl_no; + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.4: Encode_DC_DIFF */ + if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) { + arith_encode(cinfo, st, 0); + entropy->dc_context[ci] = 0; /* zero diff category */ + } else { + entropy->last_dc_val[ci] = (*block)[0]; + arith_encode(cinfo, st, 1); + /* Figure F.6: Encoding nonzero value v */ + /* Figure F.7: Encoding the sign of v */ + if (v > 0) { + arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */ + st += 2; /* Table F.4: SP = S0 + 2 */ + entropy->dc_context[ci] = 4; /* small positive diff category */ + } else { + v = -v; + arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */ + st += 3; /* Table F.4: SN = S0 + 3 */ + entropy->dc_context[ci] = 8; /* small negative diff category */ + } + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + arith_encode(cinfo, st, 0); + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] += 8; /* large diff category */ + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + + /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */ + + if ((ke = cinfo->lim_Se) == 0) continue; + tbl = compptr->ac_tbl_no; + + /* Establish EOB (end-of-block) index */ + do { + if ((*block)[natural_order[ke]]) break; + } while (--ke); + + /* Figure F.5: Encode_AC_Coefficients */ + for (k = 0; k < ke;) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 0); /* EOB decision */ + while ((v = (*block)[natural_order[++k]]) == 0) { + arith_encode(cinfo, st + 1, 0); + st += 3; + } + arith_encode(cinfo, st + 1, 1); + /* Figure F.6: Encoding nonzero value v */ + /* Figure F.7: Encoding the sign of v */ + if (v > 0) { + arith_encode(cinfo, entropy->fixed_bin, 0); + } else { + v = -v; + arith_encode(cinfo, entropy->fixed_bin, 1); + } + st += 2; + /* Figure F.8: Encoding the magnitude category of v */ + m = 0; + if (v -= 1) { + arith_encode(cinfo, st, 1); + m = 1; + v2 = v; + if (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (v2 >>= 1) { + arith_encode(cinfo, st, 1); + m <<= 1; + st += 1; + } + } + } + arith_encode(cinfo, st, 0); + /* Figure F.9: Encoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + arith_encode(cinfo, st, (m & v) ? 1 : 0); + } + /* Encode EOB decision only if k < cinfo->lim_Se */ + if (k < cinfo->lim_Se) { + st = entropy->ac_stats[tbl] + 3 * k; + arith_encode(cinfo, st, 1); + } + } + + return TRUE; +} + + +/* + * Initialize for an arithmetic-compressed scan. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo, boolean gather_statistics) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + + if (gather_statistics) + /* Make sure to avoid that in the master control logic! + * We are fully adaptive here and need no extra + * statistics gathering pass! + */ + ERREXIT(cinfo, JERR_NOT_COMPILED); + + /* We assume jcmaster.c already validated the progressive scan parameters. */ + + /* Select execution routines */ + if (cinfo->progressive_mode) { + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else + entropy->pub.encode_mcu = encode_mcu_AC_refine; + } + } else + entropy->pub.encode_mcu = encode_mcu; + + /* Allocate & initialize requested statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + tbl = compptr->dc_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->dc_stats[tbl] == NULL) + entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS); + MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + /* AC needs no table when not present */ + if (cinfo->Se) { + tbl = compptr->ac_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->ac_stats[tbl] == NULL) + entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS); + MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); +#ifdef CALCULATE_SPECTRAL_CONDITIONING + if (cinfo->progressive_mode) + /* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */ + cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4); +#endif + } + } + + /* Initialize arithmetic encoding variables */ + entropy->c = 0; + entropy->a = 0x10000L; + entropy->sc = 0; + entropy->zc = 0; + entropy->ct = 11; + entropy->buffer = -1; /* empty */ + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Module initialization routine for arithmetic entropy encoding. + */ + +GLOBAL(void) +jinit_arith_encoder (j_compress_ptr cinfo) +{ + arith_entropy_ptr entropy; + int i; + + entropy = (arith_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(arith_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass; + entropy->pub.finish_pass = finish_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + entropy->dc_stats[i] = NULL; + entropy->ac_stats[i] = NULL; + } + + /* Initialize index for fixed probability estimation */ + entropy->fixed_bin[0] = 113; +} diff --git a/library/src/main/cpp/jpeg/src/jccoefct.c b/library/src/main/cpp/jpeg/src/jccoefct.c new file mode 100644 index 00000000..924a703d --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jccoefct.c @@ -0,0 +1,454 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2003-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). We allocate a + * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each + * MCU constructed and sent. (On 80x86, the workspace is FAR even though + * it's not really very big; this is to keep the module interfaces unchanged + * when a large coefficient buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, bi, ci, yindex, yoffset, blockcnt; + JDIMENSION ypos, xpos; + jpeg_component_info *compptr; + forward_DCT_ptr forward_DCT; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks + * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks + * sequentially. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + forward_DCT = cinfo->fdct->forward_DCT[compptr->component_index]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + ypos = yoffset * compptr->DCT_v_scaled_size; + /* ypos == (yoffset+yindex) * DCTSIZE */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + (*forward_DCT) (cinfo, compptr, + input_buf[compptr->component_index], + coef->MCU_buffer[blkn], + ypos, xpos, (JDIMENSION) blockcnt); + if (blockcnt < compptr->MCU_width) { + /* Create some dummy blocks at the right edge of the image. */ + FMEMZERO((void FAR *) coef->MCU_buffer[blkn + blockcnt], + (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); + for (bi = blockcnt; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; + } + } + } else { + /* Create a row of dummy blocks at the bottom of the image. */ + FMEMZERO((void FAR *) coef->MCU_buffer[blkn], + compptr->MCU_width * SIZEOF(JBLOCK)); + for (bi = 0; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; + } + } + blkn += compptr->MCU_width; + ypos += compptr->DCT_v_scaled_size; + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + forward_DCT_ptr forward_DCT; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_blocks; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + forward_DCT = cinfo->fdct->forward_DCT[ci]; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*forward_DCT) (cinfo, compptr, input_buf[ci], thisblockrow, + (JDIMENSION) (block_row * compptr->DCT_v_scaled_size), + (JDIMENSION) 0, blocks_across); + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + FMEMZERO((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (coef->iMCU_row_num == last_iMCU_row) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + for (block_row = block_rows; block_row < compptr->v_samp_factor; + block_row++) { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + FMEMZERO((void FAR *) thisblockrow, + (size_t) (blocks_across * SIZEOF(JBLOCK))); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} diff --git a/library/src/main/cpp/jpeg/src/jccolor.c b/library/src/main/cpp/jpeg/src/jccolor.c new file mode 100644 index 00000000..96a4a9e6 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jccolor.c @@ -0,0 +1,491 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE + * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L< Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF(void) +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. + * The input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The caller + * can easily adjust the passed input_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, which is the same + * as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF(void) +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same + * conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF(void) +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCbCr (since Y == gray). + */ + +METHODDEF(void) +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + int instride = cinfo->input_components; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * No colorspace conversion, but change from interleaved + * to separate-planes representation. + */ + +METHODDEF(void) +rgb_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr0[col] = inptr[RGB_RED]; + outptr1[col] = inptr[RGB_GREEN]; + outptr2[col] = inptr[RGB_BLUE]; + inptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF(void) +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + register int ci; + int nc = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +null_method (j_compress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL(void) +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_converter)); + cinfo->cconvert = (struct jpeg_color_converter *) cconvert; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_YCbCr: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_GRAYSCALE || + cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = grayscale_convert; + else if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) + cconvert->pub.color_convert = rgb_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) { + pri_debug("设置转换器"); + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + } else if (cinfo->in_color_space == JCS_YCCK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + } +} diff --git a/library/src/main/cpp/jpeg/src/jcdctmgr.c b/library/src/main/cpp/jpeg/src/jcdctmgr.c new file mode 100644 index 00000000..0bbdbb68 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcdctmgr.c @@ -0,0 +1,482 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_forward_dct pub; /* public fields */ + + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct[MAX_COMPONENTS]; + + /* The actual post-DCT divisors --- not identical to the quant table + * entries, because of scaling (especially for an unnormalized DCT). + * Each table is given in normal array order. + */ + DCTELEM * divisors[NUM_QUANT_TBLS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct[MAX_COMPONENTS]; + FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; +#endif +} my_fdct_controller; + +typedef my_fdct_controller * my_fdct_ptr; + + +/* The current scaled-DCT routines require ISLOW-style divisor tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef DCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_row/start_col, and moving to the right for any additional + * blocks. The quantized coefficients are returned in coef_blocks[]. + */ + +METHODDEF(void) +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index]; + DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) { + /* Perform the DCT */ + (*do_dct) (workspace, sample_data, start_col); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} + + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF(void) +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index]; + FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) { + /* Perform the DCT */ + (*do_dct) (workspace, sample_data, start_col); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF(void) +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + int ci, qtblno, i; + jpeg_component_info *compptr; + int method = 0; + JQUANT_TBL * qtbl; + DCTELEM * dtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper DCT routine for this component's scaling */ + switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) { +#ifdef DCT_SCALING_SUPPORTED + case ((1 << 8) + 1): + fdct->do_dct[ci] = jpeg_fdct_1x1; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((2 << 8) + 2): + fdct->do_dct[ci] = jpeg_fdct_2x2; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((3 << 8) + 3): + fdct->do_dct[ci] = jpeg_fdct_3x3; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((4 << 8) + 4): + fdct->do_dct[ci] = jpeg_fdct_4x4; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((5 << 8) + 5): + fdct->do_dct[ci] = jpeg_fdct_5x5; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((6 << 8) + 6): + fdct->do_dct[ci] = jpeg_fdct_6x6; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((7 << 8) + 7): + fdct->do_dct[ci] = jpeg_fdct_7x7; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((9 << 8) + 9): + fdct->do_dct[ci] = jpeg_fdct_9x9; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((10 << 8) + 10): + fdct->do_dct[ci] = jpeg_fdct_10x10; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((11 << 8) + 11): + fdct->do_dct[ci] = jpeg_fdct_11x11; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((12 << 8) + 12): + fdct->do_dct[ci] = jpeg_fdct_12x12; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((13 << 8) + 13): + fdct->do_dct[ci] = jpeg_fdct_13x13; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((14 << 8) + 14): + fdct->do_dct[ci] = jpeg_fdct_14x14; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((15 << 8) + 15): + fdct->do_dct[ci] = jpeg_fdct_15x15; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((16 << 8) + 16): + fdct->do_dct[ci] = jpeg_fdct_16x16; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((16 << 8) + 8): + fdct->do_dct[ci] = jpeg_fdct_16x8; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((14 << 8) + 7): + fdct->do_dct[ci] = jpeg_fdct_14x7; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((12 << 8) + 6): + fdct->do_dct[ci] = jpeg_fdct_12x6; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((10 << 8) + 5): + fdct->do_dct[ci] = jpeg_fdct_10x5; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((8 << 8) + 4): + fdct->do_dct[ci] = jpeg_fdct_8x4; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((6 << 8) + 3): + fdct->do_dct[ci] = jpeg_fdct_6x3; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((4 << 8) + 2): + fdct->do_dct[ci] = jpeg_fdct_4x2; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((2 << 8) + 1): + fdct->do_dct[ci] = jpeg_fdct_2x1; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((8 << 8) + 16): + fdct->do_dct[ci] = jpeg_fdct_8x16; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((7 << 8) + 14): + fdct->do_dct[ci] = jpeg_fdct_7x14; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((6 << 8) + 12): + fdct->do_dct[ci] = jpeg_fdct_6x12; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((5 << 8) + 10): + fdct->do_dct[ci] = jpeg_fdct_5x10; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((4 << 8) + 8): + fdct->do_dct[ci] = jpeg_fdct_4x8; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((3 << 8) + 6): + fdct->do_dct[ci] = jpeg_fdct_3x6; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((2 << 8) + 4): + fdct->do_dct[ci] = jpeg_fdct_2x4; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; + case ((1 << 8) + 2): + fdct->do_dct[ci] = jpeg_fdct_1x2; + method = JDCT_ISLOW; /* jfdctint uses islow-style table */ + break; +#endif + case ((DCTSIZE << 8) + DCTSIZE): + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + fdct->do_dct[ci] = jpeg_fdct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + fdct->do_dct[ci] = jpeg_fdct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + fdct->do_float_dct[ci] = jpeg_fdct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, + compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size); + break; + } + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Compute divisors for this quant table */ + /* We may do this more than once for same table, but it's not a big deal */ + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3; + } + fdct->pub.forward_DCT[ci] = forward_DCT; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-3); + } + } + fdct->pub.forward_DCT[ci] = forward_DCT; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + if (fdct->float_divisors[qtblno] == NULL) { + fdct->float_divisors[qtblno] = (FAST_FLOAT *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(FAST_FLOAT)); + } + fdtbl = fdct->float_divisors[qtblno]; + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / (((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 8.0))); + i++; + } + } + } + fdct->pub.forward_DCT[ci] = forward_DCT_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize FDCT manager. + */ + +GLOBAL(void) +jinit_forward_dct (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct; + int i; + + fdct = (my_fdct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_fdct_controller)); + cinfo->fdct = (struct jpeg_forward_dct *) fdct; + fdct->pub.start_pass = start_pass_fdctmgr; + + /* Mark divisor tables unallocated */ + for (i = 0; i < NUM_QUANT_TBLS; i++) { + fdct->divisors[i] = NULL; +#ifdef DCT_FLOAT_SUPPORTED + fdct->float_divisors[i] = NULL; +#endif + } +} diff --git a/library/src/main/cpp/jpeg/src/jchuff.c b/library/src/main/cpp/jpeg/src/jchuff.c new file mode 100644 index 00000000..257d7aa1 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jchuff.c @@ -0,0 +1,1576 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2006-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * Both sequential and progressive modes are supported in this single module. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + * + * We do not support output suspension for the progressive JPEG mode, since + * the library currently does not allow multiple-scan files to be written + * with output suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; + + /* Following fields used only in progressive mode */ + + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ +} huff_entropy_encoder; + +typedef huff_entropy_encoder * huff_entropy_ptr; + +/* Working state while writing an MCU (sequential mode). + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +LOCAL(void) +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + c_derived_tbl *dtbl; + int p, i, l, lastp, si, maxsymbol; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set all codeless symbols to have code length 0; + * this lets us detect duplicate VAL entries here, and later + * allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + /* This is also a convenient place to check for out-of-range + * and duplicated VAL entries. We allow 0..255 for AC symbols + * but only 0..15 for DC. (We could constrain them further + * based on data depth and mode, but this seems enough.) + */ + maxsymbol = isDC ? 15 : 255; + + for (p = 0; p < lastp; p++) { + i = htbl->huffval[p]; + if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + dtbl->ehufco[i] = huffcode[p]; + dtbl->ehufsi[i] = huffsize[p]; + } +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte_s(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer_s(state)) \ + { action; } } + +/* Emit a byte */ +#define emit_byte_e(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer_e(entropy); } + + +LOCAL(boolean) +dump_buffer_s (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +LOCAL(void) +dump_buffer_e (huff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this case. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits_s (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte_s(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte_s(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +INLINE +LOCAL(void) +emit_bits_e (huff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = entropy->saved.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + put_buffer &= (((INT32) 1)<saved.put_buffer; + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte_e(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte_e(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->saved.put_buffer = put_buffer; /* update variables */ + entropy->saved.put_bits = put_bits; +} + + +LOCAL(boolean) +flush_bits_s (working_state * state) +{ + if (! emit_bits_s(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +LOCAL(void) +flush_bits_e (huff_entropy_ptr entropy) +{ + emit_bits_e(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->saved.put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->saved.put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL(void) +emit_dc_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->dc_count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->dc_derived_tbls[tbl_no]; + emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +INLINE +LOCAL(void) +emit_ac_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->ac_count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->ac_derived_tbls[tbl_no]; + emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL(void) +emit_buffered_bits (huff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits_e(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL(void) +emit_eobrun (huff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + /* safety check: shouldn't happen given limited correction-bit buffer */ + if (nbits > 14) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + emit_ac_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits_e(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart_s (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits_s(state)) + return FALSE; + + emit_byte_s(state, 0xFF, return FALSE); + emit_byte_s(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +LOCAL(void) +emit_restart_e (huff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits_e(entropy); + emit_byte_e(entropy, 0xFF); + emit_byte_e(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + int blkn, ci; + int Al = cinfo->Al; + JBLOCKROW block; + jpeg_component_info * compptr; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); + + /* DC differences are figured on the point-transformed values. */ + temp = temp2 - entropy->saved.last_dc_val[ci]; + entropy->saved.last_dc_val[ci] = temp2; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_dc_symbol(entropy, compptr->dc_tbl_no, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + emit_bits_e(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + register int r, k; + int Se, Al; + const int * natural_order; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + Se = cinfo->Se; + Al = cinfo->Al; + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + temp >>= Al; /* apply the point transform */ + temp2 = temp; + } + /* Watch out for case that nonzero coef is zero after point transform */ + if (temp == 0) { + r++; + continue; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits_e(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int temp; + int blkn; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* We simply emit the Al'th bit of the DC coefficient value. */ + temp = (*block)[0]; + emit_bits_e(entropy, (unsigned int) (temp >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int temp; + register int r, k; + int EOB; + char *BR_buffer; + unsigned int BR; + int Se, Al; + const int * natural_order; + JBLOCKROW block; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart_e(entropy, entropy->next_restart_num); + + Se = cinfo->Se; + Al = cinfo->Al; + natural_order = cinfo->natural_order; + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[natural_order[k]] < 0) ? 0 : 1; + emit_bits_e(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL(boolean) +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int k, r, i; + int Se = state->cinfo->lim_Se; + const int * natural_order = state->cinfo->natural_order; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = temp2 = block[0] - last_dc_val; + + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + if (! emit_bits_s(state, (unsigned int) temp2, nbits)) + return FALSE; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k <= Se; k++) { + if ((temp = block[natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + if (! emit_bits_s(state, actbl->ehufco[i], actbl->ehufsi[i])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits_s(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits_s(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart_s(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + + if (cinfo->progressive_mode) { + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits_e(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + } else { + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits_s(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + } +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + + +/* Process a single block's worth of coefficients */ + +LOCAL(void) +htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int k, r; + int Se = cinfo->lim_Se; + const int * natural_order = cinfo->natural_order; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = block[0] - last_dc_val; + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k <= Se; k++) { + if ((temp = block[natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(boolean) +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Generate the best Huffman code table for the given counts, fill htbl. + * + * The JPEG standard requires that no symbol be assigned a codeword of all + * one bits (so that padding bits added at the end of a compressed segment + * can't look like a valid code). Because of the canonical ordering of + * codewords, this just means that there must be an unused slot in the + * longest codeword length category. Section K.2 of the JPEG spec suggests + * reserving such a slot by pretending that symbol 256 is a valid symbol + * with count 1. In theory that's not optimal; giving it count zero but + * including it in the symbol set anyway should give a better Huffman code. + * But the theoretically better code actually seems to come out worse in + * practice, because it produces more all-ones bytes (which incur stuffed + * zero bytes in the final file). In any case the difference is tiny. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in JPEG section K.2. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * typically only very-low-frequency symbols will be given less-than-optimal + * lengths, so the code is almost optimal. Experimental comparisons against + * an optimal limited-length-code algorithm indicate that the difference is + * microscopic --- usually less than a hundredth of a percent of total size. + * So the extra complexity of an optimal algorithm doesn't seem worthwhile. + */ + +LOCAL(void) +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure 256 has a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed last in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = (UINT8) j; + p++; + } + } + } + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + if (cinfo->progressive_mode) + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + tbl = compptr->dc_tbl_no; + if (! did_dc[tbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[tbl]); + did_dc[tbl] = TRUE; + } + } + /* AC needs no table when not present */ + if (cinfo->Se) { + tbl = compptr->ac_tbl_no; + if (! did_ac[tbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[tbl]); + did_ac[tbl] = TRUE; + } + } + } +} + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + + if (gather_statistics) + entropy->pub.finish_pass = finish_pass_gather; + else + entropy->pub.finish_pass = finish_pass_huff; + + if (cinfo->progressive_mode) { + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routine */ + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else { + entropy->pub.encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + MAX_CORR_BITS * SIZEOF(char)); + } + } + + /* Initialize AC stuff */ + entropy->ac_tbl_no = cinfo->cur_comp_info[0]->ac_tbl_no; + entropy->EOBRUN = 0; + entropy->BE = 0; + } else { + if (gather_statistics) + entropy->pub.encode_mcu = encode_mcu_gather; + else + entropy->pub.encode_mcu = encode_mcu_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) { + tbl = compptr->dc_tbl_no; + if (gather_statistics) { + /* Check for invalid table index */ + /* (make_c_derived_tbl does this in the other path) */ + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[tbl] == NULL) + entropy->dc_count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, tbl, + & entropy->dc_derived_tbls[tbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + /* AC needs no table when not present */ + if (cinfo->Se) { + tbl = compptr->ac_tbl_no; + if (gather_statistics) { + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + if (entropy->ac_count_ptrs[tbl] == NULL) + entropy->ac_count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + jpeg_make_c_derived_tbl(cinfo, FALSE, tbl, + & entropy->ac_derived_tbls[tbl]); + } + } + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_huff_encoder (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_huff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; + } + + if (cinfo->progressive_mode) + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} diff --git a/library/src/main/cpp/jpeg/src/jcinit.c b/library/src/main/cpp/jpeg/src/jcinit.c new file mode 100644 index 00000000..0ba310f2 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcinit.c @@ -0,0 +1,65 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL(void) +jinit_compress_master (j_compress_ptr cinfo) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_encoder(cinfo); + else { + jinit_huff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding)); + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/library/src/main/cpp/jpeg/src/jcmainct.c b/library/src/main/cpp/jpeg/src/jcmainct.c new file mode 100644 index 00000000..7de75d16 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcmainct.c @@ -0,0 +1,293 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF(void) process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + main->cur_iMCU_row = 0; /* initialize counters */ + main->rowgroup_ctr = 0; + main->suspended = FALSE; + main->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (main->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + main->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (main->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + main->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF(void) +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (main->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) cinfo->min_DCT_v_scaled_size); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (main->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF(void) +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (main->pass_mode != JBUF_CRANK_DEST); + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (main->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, main->whole_image[ci], + main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE), + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE; + main->rowgroup_ctr = DCTSIZE; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + /* Return to application if we need more data to fill the iMCU row. */ + if (main->rowgroup_ctr < DCTSIZE) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (main->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr main; + int ci; + jpeg_component_info *compptr; + + main = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_c_main_controller *) main; + main->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_blocks * compptr->DCT_h_scaled_size, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor) * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + main->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * compptr->DCT_h_scaled_size, + (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size)); + } + } +} diff --git a/library/src/main/cpp/jpeg/src/jcmarker.c b/library/src/main/cpp/jpeg/src/jcmarker.c new file mode 100644 index 00000000..606c19af --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcmarker.c @@ -0,0 +1,682 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2003-2010 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_writer pub; /* public fields */ + + unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ +} my_marker_writer; + +typedef my_marker_writer * my_marker_ptr; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL(void) +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL(void) +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL(void) +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL(int) +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i <= cinfo->lim_Se; i++) { + if (qtbl->quantval[cinfo->natural_order[i]] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, + prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i <= cinfo->lim_Se; i++) { + /* The table entries must be emitted in zigzag order. */ + unsigned int qval = qtbl->quantval[cinfo->natural_order[i]]; + if (prec) + emit_byte(cinfo, (int) (qval >> 8)); + emit_byte(cinfo, (int) (qval & 0xFF)); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL(void) +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL(void) +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) + dc_in_use[compptr->dc_tbl_no] = 1; + /* AC needs no table when not present */ + if (cinfo->Se) + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + if (length) { + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } + } +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL(void) +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL(void) +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->jpeg_height > 65535L || + (long) cinfo->jpeg_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->jpeg_height); + emit_2bytes(cinfo, (int) cinfo->jpeg_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL(void) +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + + /* We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + + /* DC needs no table for refinement scan */ + td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0; + /* AC needs no table when not present */ + ta = cinfo->Se ? compptr->ac_tbl_no : 0; + + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL(void) +emit_pseudo_sos (j_compress_ptr cinfo) +/* Emit a pseudo SOS marker */ +{ + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 + 1 + 3); /* length */ + + emit_byte(cinfo, 0); /* Ns */ + + emit_byte(cinfo, 0); /* Ss */ + emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */ + emit_byte(cinfo, 0); /* Ah/Al */ +} + + +LOCAL(void) +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - major first) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ + emit_byte(cinfo, cinfo->JFIF_minor_version); + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL(void) +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + break; + } +} + + +/* + * These routines allow writing an arbitrary marker with parameters. + * The only intended use is to emit COM or APPn markers after calling + * write_file_header and before calling write_frame_header. + * Other uses are not guaranteed to produce desirable results. + * Counting the parameter bytes properly is the caller's responsibility. + */ + +METHODDEF(void) +write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +/* Emit an arbitrary marker header */ +{ + if (datalen > (unsigned int) 65533) /* safety check */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ +} + +METHODDEF(void) +write_marker_byte (j_compress_ptr cinfo, int val) +/* Emit one byte of marker parameters following write_marker_header */ +{ + emit_byte(cinfo, val); +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker should NOT + * be used for any other JPEG colorspace. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF(void) +write_file_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + /* SOI is defined to reset restart interval to 0 */ + marker->last_restart_interval = 0; + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers, and a conditional pseudo SOS marker. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF(void) +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + prec = 0; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->progressive_mode || + cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */ + else + emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */ + } else { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } + + /* Check to emit pseudo SOS marker */ + if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE) + emit_pseudo_sos(cinfo); +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF(void) +write_scan_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + /* DC needs no table for refinement scan */ + if (cinfo->Ss == 0 && cinfo->Ah == 0) + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + /* AC needs no table when not present */ + if (cinfo->Se) + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * We avoid wasting space with unnecessary DRIs, however. + */ + if (cinfo->restart_interval != marker->last_restart_interval) { + emit_dri(cinfo); + marker->last_restart_interval = cinfo->restart_interval; + } + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF(void) +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF(void) +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL(void) +jinit_marker_writer (j_compress_ptr cinfo) +{ + my_marker_ptr marker; + + /* Create the subobject */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_marker_writer)); + cinfo->marker = (struct jpeg_marker_writer *) marker; + /* Initialize method pointers */ + marker->pub.write_file_header = write_file_header; + marker->pub.write_frame_header = write_frame_header; + marker->pub.write_scan_header = write_scan_header; + marker->pub.write_file_trailer = write_file_trailer; + marker->pub.write_tables_only = write_tables_only; + marker->pub.write_marker_header = write_marker_header; + marker->pub.write_marker_byte = write_marker_byte; + /* Initialize private state */ + marker->last_restart_interval = 0; +} diff --git a/library/src/main/cpp/jpeg/src/jcmaster.c b/library/src/main/cpp/jpeg/src/jcmaster.c new file mode 100644 index 00000000..caf80a53 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcmaster.c @@ -0,0 +1,858 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2003-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +/* + * Compute JPEG image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + */ + +GLOBAL(void) +jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ +#ifdef DCT_SCALING_SUPPORTED + + /* Sanity check on input image dimensions to prevent overflow in + * following calculation. + * We do check jpeg_width and jpeg_height in initial_setup below, + * but image_width and image_height can come from arbitrary data, + * and we need some space for multiplication by block_size. + */ + if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24)) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Compute actual JPEG image dimensions and DCT scaling choices. */ + if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/1 scaling */ + cinfo->jpeg_width = cinfo->image_width * cinfo->block_size; + cinfo->jpeg_height = cinfo->image_height * cinfo->block_size; + cinfo->min_DCT_h_scaled_size = 1; + cinfo->min_DCT_v_scaled_size = 1; + } else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/2 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L); + cinfo->min_DCT_h_scaled_size = 2; + cinfo->min_DCT_v_scaled_size = 2; + } else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/3 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L); + cinfo->min_DCT_h_scaled_size = 3; + cinfo->min_DCT_v_scaled_size = 3; + } else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/4 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L); + cinfo->min_DCT_h_scaled_size = 4; + cinfo->min_DCT_v_scaled_size = 4; + } else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/5 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L); + cinfo->min_DCT_h_scaled_size = 5; + cinfo->min_DCT_v_scaled_size = 5; + } else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/6 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L); + cinfo->min_DCT_h_scaled_size = 6; + cinfo->min_DCT_v_scaled_size = 6; + } else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/7 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L); + cinfo->min_DCT_h_scaled_size = 7; + cinfo->min_DCT_v_scaled_size = 7; + } else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/8 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L); + cinfo->min_DCT_h_scaled_size = 8; + cinfo->min_DCT_v_scaled_size = 8; + } else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/9 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L); + cinfo->min_DCT_h_scaled_size = 9; + cinfo->min_DCT_v_scaled_size = 9; + } else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/10 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L); + cinfo->min_DCT_h_scaled_size = 10; + cinfo->min_DCT_v_scaled_size = 10; + } else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/11 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L); + cinfo->min_DCT_h_scaled_size = 11; + cinfo->min_DCT_v_scaled_size = 11; + } else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/12 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L); + cinfo->min_DCT_h_scaled_size = 12; + cinfo->min_DCT_v_scaled_size = 12; + } else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/13 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L); + cinfo->min_DCT_h_scaled_size = 13; + cinfo->min_DCT_v_scaled_size = 13; + } else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/14 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L); + cinfo->min_DCT_h_scaled_size = 14; + cinfo->min_DCT_v_scaled_size = 14; + } else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) { + /* Provide block_size/15 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L); + cinfo->min_DCT_h_scaled_size = 15; + cinfo->min_DCT_v_scaled_size = 15; + } else { + /* Provide block_size/16 scaling */ + cinfo->jpeg_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L); + cinfo->jpeg_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L); + cinfo->min_DCT_h_scaled_size = 16; + cinfo->min_DCT_v_scaled_size = 16; + } + +#else /* !DCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->jpeg_width = cinfo->image_width; + cinfo->jpeg_height = cinfo->image_height; + cinfo->min_DCT_h_scaled_size = DCTSIZE; + cinfo->min_DCT_v_scaled_size = DCTSIZE; + +#endif /* DCT_SCALING_SUPPORTED */ +} + + +LOCAL(void) +jpeg_calc_trans_dimensions (j_compress_ptr cinfo) +{ + if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size) + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, + cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size); + + cinfo->block_size = cinfo->min_DCT_h_scaled_size; +} + + +LOCAL(void) +initial_setup (j_compress_ptr cinfo, boolean transcode_only) +/* Do computations that are needed before master selection phase */ +{ + int ci, ssize; + jpeg_component_info *compptr; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + if (transcode_only) + jpeg_calc_trans_dimensions(cinfo); + else + jpeg_calc_jpeg_dimensions(cinfo); + + /* Sanity check on block_size */ + if (cinfo->block_size < 1 || cinfo->block_size > 16) + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size); + + /* Derive natural_order from block_size */ + switch (cinfo->block_size) { + case 2: cinfo->natural_order = jpeg_natural_order2; break; + case 3: cinfo->natural_order = jpeg_natural_order3; break; + case 4: cinfo->natural_order = jpeg_natural_order4; break; + case 5: cinfo->natural_order = jpeg_natural_order5; break; + case 6: cinfo->natural_order = jpeg_natural_order6; break; + case 7: cinfo->natural_order = jpeg_natural_order7; break; + default: cinfo->natural_order = jpeg_natural_order; break; + } + + /* Derive lim_Se from block_size */ + cinfo->lim_Se = cinfo->block_size < DCTSIZE ? + cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1; + + /* Sanity check on image dimensions */ + if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 || + cinfo->num_components <= 0 || cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* In selecting the actual DCT scaling for each component, we try to + * scale down the chroma components via DCT scaling rather than downsampling. + * This saves time if the downsampler gets to use 1:1 scaling. + * Note this code adapts subsampling ratios which are powers of 2. + */ + ssize = 1; +#ifdef DCT_SCALING_SUPPORTED + while (cinfo->min_DCT_h_scaled_size * ssize <= + (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) { + ssize = ssize * 2; + } +#endif + compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize; + ssize = 1; +#ifdef DCT_SCALING_SUPPORTED + while (cinfo->min_DCT_v_scaled_size * ssize <= + (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) { + ssize = ssize * 2; + } +#endif + compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize; + + /* We don't support DCT ratios larger than 2. */ + if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2) + compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2; + else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2) + compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2; + + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_width * + (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size), + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height * + (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size), + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + /* Mark component needed (this flag isn't actually used for compression) */ + compptr->component_needed = TRUE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(void) +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->progressive_mode. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + scanptr = cinfo->scan_info; + if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->progressive_mode = TRUE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N+1 for N-bit precision. + * Here we allow 0..10 for 8-bit data; Al larger than 10 results in + * out-of-range reconstructed DC values during the first DC scan, + * which might cause problems for some decoders. + */ +#if BITS_IN_JSAMPLE == 8 +#define MAX_AH_AL 10 +#else +#define MAX_AH_AL 13 +#endif + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + + +LOCAL(void) +reduce_script (j_compress_ptr cinfo) +/* Adapt scan script for use with reduced block size; + * assume that script has been validated before. + */ +{ + jpeg_scan_info * scanptr; + int idxout, idxin; + + /* Circumvent const declaration for this function */ + scanptr = (jpeg_scan_info *) cinfo->scan_info; + idxout = 0; + + for (idxin = 0; idxin < cinfo->num_scans; idxin++) { + /* After skipping, idxout becomes smaller than idxin */ + if (idxin != idxout) + /* Copy rest of data; + * note we stay in given chunk of allocated memory. + */ + scanptr[idxout] = scanptr[idxin]; + if (scanptr[idxout].Ss > cinfo->lim_Se) + /* Entire scan out of range - skip this entry */ + continue; + if (scanptr[idxout].Se > cinfo->lim_Se) + /* Limit scan to end of block */ + scanptr[idxout].Se = cinfo->lim_Se; + idxout++; + } + + cinfo->num_scans = idxout; +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +LOCAL(void) +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + if (cinfo->progressive_mode) { + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + return; + } + } + else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + } + cinfo->Ss = 0; + cinfo->Se = cinfo->block_size * cinfo->block_size - 1; + cinfo->Ah = 0; + cinfo->Al = 0; +} + + +LOCAL(void) +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_h_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_width, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->jpeg_height, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF(void) +prepare_for_pass (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->fdct->start_pass) (cinfo); + (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->coef->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (cinfo->Ss != 0 || cinfo->Ah == 0) { + (*cinfo->entropy->start_pass) (cinfo, TRUE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->entropy->start_pass) (cinfo, FALSE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF(void) +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF(void) +finish_pass_master (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*cinfo->entropy->finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL(void) +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_comp_master)); + cinfo->master = (struct jpeg_comp_master *) master; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo, transcode_only); + + if (cinfo->scan_info != NULL) { +#ifdef C_MULTISCAN_FILES_SUPPORTED + validate_script(cinfo); + if (cinfo->block_size < DCTSIZE) + reduce_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + cinfo->num_scans = 1; + } + + if ((cinfo->progressive_mode || cinfo->block_size < DCTSIZE) && + !cinfo->arith_code) /* TEMPORARY HACK ??? */ + /* assume default tables no good for progressive or downscale mode */ + cinfo->optimize_coding = TRUE; + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/library/src/main/cpp/jpeg/src/jcomapi.c b/library/src/main/cpp/jpeg/src/jcomapi.c new file mode 100644 index 00000000..9b1fa756 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcomapi.c @@ -0,0 +1,106 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Do nothing if called on a not-initialized or destroyed JPEG object. */ + if (cinfo->mem == NULL) + return; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + if (cinfo->is_decompressor) { + cinfo->global_state = DSTATE_START; + /* Try to keep application from accessing now-deleted marker list. + * A bit kludgy to do it here, but this is the most central place. + */ + ((j_decompress_ptr) cinfo)->marker_list = NULL; + } else { + cinfo->global_state = CSTATE_START; + } +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL(JQUANT_TBL *) +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL(JHUFF_TBL *) +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} diff --git a/library/src/main/cpp/jpeg/src/jcparam.c b/library/src/main/cpp/jpeg/src/jcparam.c new file mode 100644 index 00000000..c5e85dda --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcparam.c @@ -0,0 +1,632 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2003-2008 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL(void) +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); + + qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +/* These are the sample quantization tables given in JPEG spec section K.1. + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. + */ +static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; +static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + + +GLOBAL(void) +jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and straight percentage-scaling quality scales. + * This entry point allows different scalings for luminance and chrominance. + */ +{ + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + cinfo->q_scale_factor[0], force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + cinfo->q_scale_factor[1], force_baseline); +} + + +GLOBAL(void) +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL(int) +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table + * to make all the table entries 1 (hence, minimum quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL(void) +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding three routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Huffman table setup routines + */ + +LOCAL(void) +add_huff_table (j_compress_ptr cinfo, + JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + int nsymbols, len; + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + /* Copy the number-of-symbols-of-each-code-length counts */ + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + + /* Validate the counts. We do this here mainly so we can copy the right + * number of symbols from the val[] array, without risking marching off + * the end of memory. jchuff.c will do a more thorough test later. + */ + nsymbols = 0; + for (len = 1; len <= 16; len++) + nsymbols += bits[len]; + if (nsymbols < 1 || nsymbols > 256) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + + +LOCAL(void) +std_huff_tables (j_compress_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ +{ + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL(void) +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Set up two Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, force optimization on so that usable + * tables will be computed. This test can be removed if default tables + * are supplied that are valid for the desired precision. + */ + if (cinfo->data_precision > 8) + cinfo->optimize_coding = TRUE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* By default, apply fancy downsampling */ + cinfo->do_fancy_downsampling = TRUE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + * + * By default, the library emits JFIF version code 1.01. + * An application that wants to emit JFIF 1.02 extension markers should set + * JFIF_minor_version to 2. We could probably get away with just defaulting + * to 1.02, but there may still be some decoders in use that will complain + * about that; saying 1.01 should minimize compatibility problems. + */ + cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL(void) +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL(void) +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 1, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 2,2, 0, 0,0); + break; + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL(jpeg_scan_info *) +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL(void) +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_progression is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space, and we allocate + * enough space to handle YCbCr even if initially asked for grayscale. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = MAX(nscans, 10); + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jcprepct.c b/library/src/main/cpp/jpeg/src/jcprepct.c new file mode 100644 index 00000000..be44cc4b --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcprepct.c @@ -0,0 +1,358 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL(void) +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data, input_rows-1, image_data, row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF(void) +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + numrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; + expand_bottom_edge(output_buf[ci], + compptr->width_in_blocks * compptr->DCT_h_scaled_size, + (int) (*out_row_group_ctr * numrows), + (int) (out_row_groups_avail * numrows)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF(void) +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], 0, + prep->color_buf[ci], -row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + /* When at bottom of image, pad to fill the conversion buffer. */ + if (prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL(void) +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * + SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * + cinfo->min_DCT_h_scaled_size * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL(void) +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_prep_controller)); + cinfo->prep = (struct jpeg_c_prep_controller *) prep; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * + cinfo->min_DCT_h_scaled_size * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/library/src/main/cpp/jpeg/src/jcsample.c b/library/src/main/cpp/jpeg/src/jcsample.c new file mode 100644 index 00000000..4d36f85f --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jcsample.c @@ -0,0 +1,545 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; + + /* Height of an output row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_downsample need not + * recompute them each time. They are unused for other downsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF(void) +start_pass_downsample (j_compress_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL(void) +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF(void) +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + + (out_row_group_index * downsample->rowgroup_height[ci]); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF(void) +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = downsample->h_expand[compptr->component_index]; + v_expand = downsample->v_expand[compptr->component_index]; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = outrow = 0; + while (inrow < cinfo->max_v_samp_factor) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + outrow++; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF(void) +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, 0, output_data, 0, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width, + compptr->width_in_blocks * compptr->DCT_h_scaled_size); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + outptr = output_data[inrow]; + inptr = input_data[inrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF(void) +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = outrow = 0; + while (inrow < cinfo->max_v_samp_factor) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + outrow++; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = outrow = 0; + while (inrow < cinfo->max_v_samp_factor) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + outrow++; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + outptr = output_data[inrow]; + inptr = input_data[inrow]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL(void) +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + int h_in_group, v_in_group, h_out_group, v_out_group; + + downsample = (my_downsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_downsampler)); + cinfo->downsample = (struct jpeg_downsampler *) downsample; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "output group" for DCT scaling. This many samples + * are to be converted from max_h_samp_factor * max_v_samp_factor pixels. + */ + h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) / + cinfo->min_DCT_h_scaled_size; + v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; + h_in_group = cinfo->max_h_samp_factor; + v_in_group = cinfo->max_v_samp_factor; + downsample->rowgroup_height[ci] = v_out_group; /* save for use later */ + if (h_in_group == h_out_group && v_in_group == v_out_group) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (h_in_group == h_out_group * 2 && + v_in_group == v_out_group) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (h_in_group == h_out_group * 2 && + v_in_group == v_out_group * 2) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((h_in_group % h_out_group) == 0 && + (v_in_group % v_out_group) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group); + downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/library/src/main/cpp/jpeg/src/jctrans.c b/library/src/main/cpp/jpeg/src/jctrans.c new file mode 100644 index 00000000..f7d7b814 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jctrans.c @@ -0,0 +1,382 @@ +/* + * jctrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * Modified 2000-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL(void) +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL(void) +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + dstinfo->jpeg_width = srcinfo->output_width; + dstinfo->jpeg_height = srcinfo->output_height; + dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size; + dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + */ + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's Huffman table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } + /* Also copy JFIF version and resolution information, if available. + * Strictly speaking this isn't "critical" info, but it's nearly + * always appropriate to copy it if available. In particular, + * if the application chooses to copy JFIF 1.02 extension markers from + * the source file, we need to copy the version to make sure we don't + * emit a file that has 1.02 extensions but a claimed version of 1.01. + * We will *not*, however, copy version info from mislabeled "2.01" files. + */ + if (srcinfo->saw_JFIF_marker) { + if (srcinfo->JFIF_major_version == 1) { + dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; + dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; + } + dstinfo->density_unit = srcinfo->density_unit; + dstinfo->X_density = srcinfo->X_density; + dstinfo->Y_density = srcinfo->Y_density; + } +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL(void) +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_encoder(cinfo); + else { + jinit_huff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI, JFIF) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yindex+yoffset < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < blockcnt; xindex++) + MCU_buffer[blkn++] = buffer_ptr++; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = 0; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + for (; xindex < compptr->MCU_width; xindex++) { + MCU_buffer[blkn] = coef->dummy_buffer[blkn]; + MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; + blkn++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_blocks wide and height_in_blocks high, + * with unitheight at least v_samp_factor. + */ + +LOCAL(void) +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + my_coef_ptr coef; + JBLOCKROW buffer; + int i; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + coef->pub.compress_data = compress_output; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Allocate and pre-zero space for dummy DCT blocks. */ + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + FMEMZERO((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->dummy_buffer[i] = buffer + i; + } +} diff --git a/library/src/main/cpp/jpeg/src/jdapimin.c b/library/src/main/cpp/jpeg/src/jdapimin.c new file mode 100644 index 00000000..09f75f2a --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdapimin.c @@ -0,0 +1,397 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + + +GLOBAL(void) +jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) +{ + + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_decompress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + cinfo->marker_list = NULL; + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL(void) +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Set default decompression parameters. + */ + +LOCAL(void) +default_decompress_parms (j_decompress_ptr cinfo) +{ + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* (Wish JPEG committee had provided a real way to specify this...) */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + } else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + break; + } + } else { + /* Saw no special markers, try to guess from the component IDs */ + int cid0 = cinfo->comp_info[0].component_id; + int cid1 = cinfo->comp_info[1].component_id; + int cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + break; + } + } else { + /* No special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + break; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = cinfo->block_size; /* 1:1 scaling */ + cinfo->scale_denom = cinfo->block_size; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL(int) +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL(int) +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL(boolean) +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL(boolean) +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/library/src/main/cpp/jpeg/src/jdapistd.c b/library/src/main/cpp/jpeg/src/jdapistd.c new file mode 100644 index 00000000..3924ec80 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdapistd.c @@ -0,0 +1,274 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL(boolean) +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL(JDIMENSION) +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->coef->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL(boolean) +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jdarith.c b/library/src/main/cpp/jpeg/src/jdarith.c new file mode 100644 index 00000000..092f8af5 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdarith.c @@ -0,0 +1,776 @@ +/* + * jdarith.c + * + * Developed 1997-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains portable arithmetic entropy decoding routines for JPEG + * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81). + * + * Both sequential and progressive modes are supported in this single module. + * + * Suspension is not currently supported in this module. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Expanded entropy decoder object for arithmetic decoding. */ + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + INT32 c; /* C register, base of coding interval + input bit buffer */ + INT32 a; /* A register, normalized size of coding interval */ + int ct; /* bit shift counter, # of bits left in bit buffer part of C */ + /* init: ct = -16 */ + /* run: ct = 0..7 */ + /* error: ct = -1 */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to statistics areas (these workspaces have image lifespan) */ + unsigned char * dc_stats[NUM_ARITH_TBLS]; + unsigned char * ac_stats[NUM_ARITH_TBLS]; + + /* Statistics bin for coding with fixed probability 0.5 */ + unsigned char fixed_bin[4]; +} arith_entropy_decoder; + +typedef arith_entropy_decoder * arith_entropy_ptr; + +/* The following two definitions specify the allocation chunk size + * for the statistics area. + * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least + * 49 statistics bins for DC, and 245 statistics bins for AC coding. + * + * We use a compact representation with 1 byte per statistics bin, + * thus the numbers directly represent byte sizes. + * This 1 byte per statistics bin contains the meaning of the MPS + * (more probable symbol) in the highest bit (mask 0x80), and the + * index into the probability estimation state machine table + * in the lower bits (mask 0x7F). + */ + +#define DC_STAT_BINS 64 +#define AC_STAT_BINS 256 + + +LOCAL(int) +get_byte (j_decompress_ptr cinfo) +/* Read next input byte; we do not support suspension in this module. */ +{ + struct jpeg_source_mgr * src = cinfo->src; + + if (src->bytes_in_buffer == 0) + if (! (*src->fill_input_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + src->bytes_in_buffer--; + return GETJOCTET(*src->next_input_byte++); +} + + +/* + * The core arithmetic decoding routine (common in JPEG and JBIG). + * This needs to go as fast as possible. + * Machine-dependent optimization facilities + * are not utilized in this portable implementation. + * However, this code should be fairly efficient and + * may be a good base for further optimizations anyway. + * + * Return value is 0 or 1 (binary decision). + * + * Note: I've changed the handling of the code base & bit + * buffer register C compared to other implementations + * based on the standards layout & procedures. + * While it also contains both the actual base of the + * coding interval (16 bits) and the next-bits buffer, + * the cut-point between these two parts is floating + * (instead of fixed) with the bit shift counter CT. + * Thus, we also need only one (variable instead of + * fixed size) shift for the LPS/MPS decision, and + * we can get away with any renormalization update + * of C (except for new data insertion, of course). + * + * I've also introduced a new scheme for accessing + * the probability estimation state machine table, + * derived from Markus Kuhn's JBIG implementation. + */ + +LOCAL(int) +arith_decode (j_decompress_ptr cinfo, unsigned char *st) +{ + register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy; + register unsigned char nl, nm; + register INT32 qe, temp; + register int sv, data; + + /* Renormalization & data input per section D.2.6 */ + while (e->a < 0x8000L) { + if (--e->ct < 0) { + /* Need to fetch next data byte */ + if (cinfo->unread_marker) + data = 0; /* stuff zero data */ + else { + data = get_byte(cinfo); /* read next input byte */ + if (data == 0xFF) { /* zero stuff or marker code */ + do data = get_byte(cinfo); + while (data == 0xFF); /* swallow extra 0xFF bytes */ + if (data == 0) + data = 0xFF; /* discard stuffed zero byte */ + else { + /* Note: Different from the Huffman decoder, hitting + * a marker while processing the compressed data + * segment is legal in arithmetic coding. + * The convention is to supply zero data + * then until decoding is complete. + */ + cinfo->unread_marker = data; + data = 0; + } + } + } + e->c = (e->c << 8) | data; /* insert data into C register */ + if ((e->ct += 8) < 0) /* update bit shift counter */ + /* Need more initial bytes */ + if (++e->ct == 0) + /* Got 2 initial bytes -> re-init A and exit loop */ + e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */ + } + e->a <<= 1; + } + + /* Fetch values from our compact representation of Table D.3(D.2): + * Qe values and probability estimation state machine + */ + sv = *st; + qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */ + nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */ + nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */ + + /* Decode & estimation procedures per sections D.2.4 & D.2.5 */ + temp = e->a - qe; + e->a = temp; + temp <<= e->ct; + if (e->c >= temp) { + e->c -= temp; + /* Conditional LPS (less probable symbol) exchange */ + if (e->a < qe) { + e->a = qe; + *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ + } else { + e->a = qe; + *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ + sv ^= 0x80; /* Exchange LPS/MPS */ + } + } else if (e->a < 0x8000L) { + /* Conditional MPS (more probable symbol) exchange */ + if (e->a < qe) { + *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */ + sv ^= 0x80; /* Exchange LPS/MPS */ + } else { + *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */ + } + } + + return sv >> 7; +} + + +/* + * Check for a restart marker & resynchronize decoder. + */ + +LOCAL(void) +process_restart (j_decompress_ptr cinfo) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci; + jpeg_component_info * compptr; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Re-initialize statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { + MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); + /* Reset DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + if ((! cinfo->progressive_mode && cinfo->lim_Se) || + (cinfo->progressive_mode && cinfo->Ss)) { + MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); + } + } + + /* Reset arithmetic decoding variables */ + entropy->c = 0; + entropy->a = 0; + entropy->ct = -16; /* force reading 2 initial bytes to fill C */ + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Arithmetic MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * arithmetic-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int blkn, ci, tbl, sign; + int v, m; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + tbl = cinfo->cur_comp_info[ci]->dc_tbl_no; + + /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.19: Decode_DC_DIFF */ + if (arith_decode(cinfo, st) == 0) + entropy->dc_context[ci] = 0; + else { + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, st + 1); + st += 2; st += sign; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == 0x8000) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ + else + entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + entropy->last_dc_val[ci] += v; + } + + /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al); + } + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + unsigned char *st; + int tbl, sign, k; + int v, m; + const int * natural_order; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + natural_order = cinfo->natural_order; + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ + + /* Figure F.20: Decode_AC_coefficients */ + for (k = cinfo->Ss; k <= cinfo->Se; k++) { + st = entropy->ac_stats[tbl] + 3 * (k - 1); + if (arith_decode(cinfo, st)) break; /* EOB flag */ + while (arith_decode(cinfo, st + 1) == 0) { + st += 3; k++; + if (k > cinfo->Se) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* spectral overflow */ + return TRUE; + } + } + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, entropy->fixed_bin); + st += 2; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + if (arith_decode(cinfo, st)) { + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == 0x8000) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + } + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al); + } + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + unsigned char *st; + int p1, blkn; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + st = entropy->fixed_bin; /* use fixed probability estimation */ + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + /* Encoded data is simply the next bit of the two's-complement DC value */ + if (arith_decode(cinfo, st)) + MCU_data[blkn][0][0] |= p1; + } + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + JBLOCKROW block; + JCOEFPTR thiscoef; + unsigned char *st; + int tbl, k, kex; + int p1, m1; + const int * natural_order; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + natural_order = cinfo->natural_order; + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = cinfo->cur_comp_info[0]->ac_tbl_no; + + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + + /* Establish EOBx (previous stage end-of-block) index */ + for (kex = cinfo->Se; kex > 0; kex--) + if ((*block)[natural_order[kex]]) break; + + for (k = cinfo->Ss; k <= cinfo->Se; k++) { + st = entropy->ac_stats[tbl] + 3 * (k - 1); + if (k > kex) + if (arith_decode(cinfo, st)) break; /* EOB flag */ + for (;;) { + thiscoef = *block + natural_order[k]; + if (*thiscoef) { /* previously nonzero coef */ + if (arith_decode(cinfo, st + 2)) { + if (*thiscoef < 0) + *thiscoef += m1; + else + *thiscoef += p1; + } + break; + } + if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */ + if (arith_decode(cinfo, entropy->fixed_bin)) + *thiscoef = m1; + else + *thiscoef = p1; + break; + } + st += 3; k++; + if (k > cinfo->Se) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* spectral overflow */ + return TRUE; + } + } + } + + return TRUE; +} + + +/* + * Decode one MCU's worth of arithmetic-compressed coefficients. + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + jpeg_component_info * compptr; + JBLOCKROW block; + unsigned char *st; + int blkn, ci, tbl, sign, k; + int v, m; + const int * natural_order; + + /* Process restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + process_restart(cinfo); + entropy->restarts_to_go--; + } + + if (entropy->ct == -1) return TRUE; /* if error do nothing */ + + natural_order = cinfo->natural_order; + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */ + + tbl = compptr->dc_tbl_no; + + /* Table F.4: Point to statistics bin S0 for DC coefficient coding */ + st = entropy->dc_stats[tbl] + entropy->dc_context[ci]; + + /* Figure F.19: Decode_DC_DIFF */ + if (arith_decode(cinfo, st) == 0) + entropy->dc_context[ci] = 0; + else { + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, st + 1); + st += 2; st += sign; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */ + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == 0x8000) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + /* Section F.1.4.4.1.2: Establish dc_context conditioning category */ + if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1)) + entropy->dc_context[ci] = 0; /* zero diff category */ + else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1)) + entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */ + else + entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */ + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + entropy->last_dc_val[ci] += v; + } + + (*block)[0] = (JCOEF) entropy->last_dc_val[ci]; + + /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */ + + if (cinfo->lim_Se == 0) continue; + tbl = compptr->ac_tbl_no; + k = 0; + + /* Figure F.20: Decode_AC_coefficients */ + do { + st = entropy->ac_stats[tbl] + 3 * k; + if (arith_decode(cinfo, st)) break; /* EOB flag */ + for (;;) { + k++; + if (arith_decode(cinfo, st + 1)) break; + st += 3; + if (k >= cinfo->lim_Se) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* spectral overflow */ + return TRUE; + } + } + /* Figure F.21: Decoding nonzero value v */ + /* Figure F.22: Decoding the sign of v */ + sign = arith_decode(cinfo, entropy->fixed_bin); + st += 2; + /* Figure F.23: Decoding the magnitude category of v */ + if ((m = arith_decode(cinfo, st)) != 0) { + if (arith_decode(cinfo, st)) { + m <<= 1; + st = entropy->ac_stats[tbl] + + (k <= cinfo->arith_ac_K[tbl] ? 189 : 217); + while (arith_decode(cinfo, st)) { + if ((m <<= 1) == 0x8000) { + WARNMS(cinfo, JWRN_ARITH_BAD_CODE); + entropy->ct = -1; /* magnitude overflow */ + return TRUE; + } + st += 1; + } + } + } + v = m; + /* Figure F.24: Decoding the magnitude bit pattern of v */ + st += 14; + while (m >>= 1) + if (arith_decode(cinfo, st)) v |= m; + v += 1; if (sign) v = -v; + (*block)[natural_order[k]] = (JCOEF) v; + } while (k < cinfo->lim_Se); + } + + return TRUE; +} + + +/* + * Initialize for an arithmetic-compressed scan. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy; + int ci, tbl; + jpeg_component_info * compptr; + + if (cinfo->progressive_mode) { + /* Validate progressive scan parameters */ + if (cinfo->Ss == 0) { + if (cinfo->Se != 0) + goto bad; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se) + goto bad; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + goto bad; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Ah-1 != cinfo->Al) + goto bad; + } + if (cinfo->Al > 13) { /* need not check for < 0 */ + bad: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + } + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; + int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + } else { + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning. + */ + if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || + (cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se)) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + /* Select MCU decoding routine */ + entropy->pub.decode_mcu = decode_mcu; + } + + /* Allocate & initialize requested statistics areas */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { + tbl = compptr->dc_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->dc_stats[tbl] == NULL) + entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS); + MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + entropy->dc_context[ci] = 0; + } + if ((! cinfo->progressive_mode && cinfo->lim_Se) || + (cinfo->progressive_mode && cinfo->Ss)) { + tbl = compptr->ac_tbl_no; + if (tbl < 0 || tbl >= NUM_ARITH_TBLS) + ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl); + if (entropy->ac_stats[tbl] == NULL) + entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS); + MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); + } + } + + /* Initialize arithmetic decoding variables */ + entropy->c = 0; + entropy->a = 0; + entropy->ct = -16; /* force reading 2 initial bytes to fill C */ + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Module initialization routine for arithmetic entropy decoding. + */ + +GLOBAL(void) +jinit_arith_decoder (j_decompress_ptr cinfo) +{ + arith_entropy_ptr entropy; + int i; + + entropy = (arith_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(arith_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + entropy->dc_stats[i] = NULL; + entropy->ac_stats[i] = NULL; + } + + /* Initialize index for fixed probability estimation */ + entropy->fixed_bin[0] = 113; + + if (cinfo->progressive_mode) { + /* Create progression status table */ + int *coef_bit_ptr, ci; + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; + } +} diff --git a/library/src/main/cpp/jpeg/src/jdatadst.c b/library/src/main/cpp/jpeg/src/jdatadst.c new file mode 100644 index 00000000..6981fb73 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdatadst.c @@ -0,0 +1,267 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2009-2012 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to memory or to a file (or any stdio stream). + * While these routines are sufficient for most applications, + * some will want to use a different destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* Expanded data destination object for stdio output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* Expanded data destination object for memory output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + unsigned char ** outbuffer; /* target buffer */ + unsigned long * outsize; + unsigned char * newbuffer; /* newly allocated buffer */ + JOCTET * buffer; /* start of buffer */ + size_t bufsize; +} my_mem_destination_mgr; + +typedef my_mem_destination_mgr * my_mem_dest_ptr; + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +METHODDEF(void) +init_mem_destination (j_compress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +METHODDEF(boolean) +empty_mem_output_buffer (j_compress_ptr cinfo) +{ + size_t nextsize; + JOCTET * nextbuffer; + my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; + + /* Try to allocate new buffer with double size */ + nextsize = dest->bufsize * 2; + nextbuffer = (JOCTET *) malloc(nextsize); + + if (nextbuffer == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); + + MEMCOPY(nextbuffer, dest->buffer, dest->bufsize); + + if (dest->newbuffer != NULL) + free(dest->newbuffer); + + dest->newbuffer = nextbuffer; + + dest->pub.next_output_byte = nextbuffer + dest->bufsize; + dest->pub.free_in_buffer = dest->bufsize; + + dest->buffer = nextbuffer; + dest->bufsize = nextsize; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + +METHODDEF(void) +term_mem_destination (j_compress_ptr cinfo) +{ + my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; + + *dest->outbuffer = dest->buffer; + *dest->outsize = dest->bufsize - dest->pub.free_in_buffer; +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} + + +/* + * Prepare for output to a memory buffer. + * The caller may supply an own initial buffer with appropriate size. + * Otherwise, or when the actual data output exceeds the given size, + * the library adapts the buffer size as necessary. + * The standard library functions malloc/free are used for allocating + * larger memory, so the buffer is available to the application after + * finishing compression, and then the application is responsible for + * freeing the requested memory. + */ + +GLOBAL(void) +jpeg_mem_dest (j_compress_ptr cinfo, + unsigned char ** outbuffer, unsigned long * outsize) +{ + my_mem_dest_ptr dest; + + if (outbuffer == NULL || outsize == NULL) /* sanity check */ + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same buffer without re-executing jpeg_mem_dest. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_mem_destination_mgr)); + } + + dest = (my_mem_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_mem_destination; + dest->pub.empty_output_buffer = empty_mem_output_buffer; + dest->pub.term_destination = term_mem_destination; + dest->outbuffer = outbuffer; + dest->outsize = outsize; + dest->newbuffer = NULL; + + if (*outbuffer == NULL || *outsize == 0) { + /* Allocate initial buffer */ + dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE); + if (dest->newbuffer == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); + *outsize = OUTPUT_BUF_SIZE; + } + + dest->pub.next_output_byte = dest->buffer = *outbuffer; + dest->pub.free_in_buffer = dest->bufsize = *outsize; +} diff --git a/library/src/main/cpp/jpeg/src/jdatasrc.c b/library/src/main/cpp/jpeg/src/jdatasrc.c new file mode 100644 index 00000000..c13d11b3 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdatasrc.c @@ -0,0 +1,276 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2009-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from memory or from a file (or any stdio stream). + * While these routines are sufficient for most applications, + * some will want to use a different source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + +METHODDEF(void) +init_mem_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + +METHODDEF(boolean) +fill_mem_input_buffer (j_decompress_ptr cinfo) +{ + static const JOCTET mybuffer[4] = { + (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 + }; + + /* The whole JPEG data is expected to reside in the supplied memory + * buffer, so any request for more data beyond the given buffer size + * is treated as an error. + */ + WARNMS(cinfo, JWRN_JPEG_EOF); + + /* Insert a fake EOI marker */ + + cinfo->src->next_input_byte = mybuffer; + cinfo->src->bytes_in_buffer = 2; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + struct jpeg_source_mgr * src = cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->bytes_in_buffer) { + num_bytes -= (long) src->bytes_in_buffer; + (void) (*src->fill_input_buffer) (cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->next_input_byte += (size_t) num_bytes; + src->bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + + +/* + * Prepare for input from a supplied memory buffer. + * The buffer must contain the whole JPEG data. + */ + +GLOBAL(void) +jpeg_mem_src (j_decompress_ptr cinfo, + unsigned char * inbuffer, unsigned long insize) +{ + + struct jpeg_source_mgr * src; + + if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + + /* The source object is made permanent so that a series of JPEG images + * can be read from the same buffer by calling jpeg_mem_src only before + * the first one. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(struct jpeg_source_mgr)); + } + + src = cinfo->src; + src->init_source = init_mem_source; + src->fill_input_buffer = fill_mem_input_buffer; + src->skip_input_data = skip_input_data; + src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->term_source = term_source; + src->bytes_in_buffer = (size_t) insize; + src->next_input_byte = (JOCTET *) inbuffer; +} diff --git a/library/src/main/cpp/jpeg/src/jdcoefct.c b/library/src/main/cpp/jpeg/src/jdcoefct.c new file mode 100644 index 00000000..ed02fc37 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdcoefct.c @@ -0,0 +1,741 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * Modified 2002-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_coef_controller pub; /* public fields */ + + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * (On 80x86, the workspace is FAR even though it's not really very big; + * this is to keep the module interfaces unchanged when a large coefficient + * buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF(int) decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (coef->pub.coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + coef->pub.decompress_data = decompress_smooth_data; + else + coef->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, useful_width; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + if (cinfo->lim_Se) /* can bypass in DC only case */ + FMEMZERO((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkn gets + * incremented past them!). Note the inner loop relies on having + * allocated the MCU_buffer[] blocks sequentially. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkn += compptr->MCU_blocks; + continue; + } + inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + output_ptr = output_buf[compptr->component_index] + + yoffset * compptr->DCT_v_scaled_size; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); + output_col += compptr->DCT_h_scaled_size; + } + } + blkn += compptr->MCU_width; + output_ptr += compptr->DCT_v_scaled_size; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->DCT_h_scaled_size; + } + output_ptr += compptr->DCT_v_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* Natural-order array positions of the first 5 zigzag-order coefficients */ +#define Q01_POS 1 +#define Q10_POS 8 +#define Q20_POS 16 +#define Q11_POS 9 +#define Q02_POS 2 + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL(boolean) +smoothing_ok (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * + (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + if (qtable->quantval[0] == 0 || + qtable->quantval[Q01_POS] == 0 || + qtable->quantval[Q10_POS] == 0 || + qtable->quantval[Q20_POS] == 0 || + qtable->quantval[Q11_POS] == 0 || + qtable->quantval[Q02_POS] == 0) + return FALSE; + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF(int) +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[Q01_POS]; + Q10 = quanttbl->quantval[Q10_POS]; + Q20 = quanttbl->quantval[Q20_POS]; + Q11 = quanttbl->quantval[Q11_POS]; + Q02 = quanttbl->quantval[Q02_POS]; + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_blocks - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_h_scaled_size; + } + output_ptr += compptr->DCT_v_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_d_coef_controller *) coef; + coef->pub.start_input_pass = start_input_pass; + coef->pub.start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->progressive_mode) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + coef->pub.consume_data = consume_data; + coef->pub.decompress_data = decompress_data; + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + if (cinfo->lim_Se == 0) /* DC only case: want to bypass later */ + FMEMZERO((void FAR *) buffer, + (size_t) (D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK))); + coef->pub.consume_data = dummy_consume_data; + coef->pub.decompress_data = decompress_onepass; + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + } +} diff --git a/library/src/main/cpp/jpeg/src/jdcolor.c b/library/src/main/cpp/jpeg/src/jdcolor.c new file mode 100644 index 00000000..74a03676 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdcolor.c @@ -0,0 +1,518 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* Private state for RGB->Y conversion */ + INT32 * rgb_y_tab; /* => table for RGB to Y conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/**************** YCbCr -> RGB conversion: most common case **************/ +/**************** RGB -> Y conversion: less common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + * values for the G calculation are left scaled up, since we must add them + * together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<Y conversion and divide it up into + * three parts, instead of doing three alloc_small requests. This lets us + * use a single table base address, which can be held in a register in the + * inner loops on many machines (more than can hold all three addresses, + * anyway). + */ + +#define R_Y_OFF 0 /* offset to R => Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define TABLE_SIZE (3*(MAXJSAMPLE+1)) + + +/* + * Initialize tables for YCC->RGB colorspace conversion. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; + SHIFT_TEMPS + + cconvert->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCbCr -> RGB **************/ + + +/* + * Initialize for RGB->grayscale colorspace conversion. + */ + +LOCAL(void) +build_rgb_y_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_y_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_y_tab = rgb_y_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_y_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_y_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_y_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + } +} + + +/* + * Convert RGB to grayscale. + */ + +METHODDEF(void) +rgb_gray_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_y_tab; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr0[col]); + g = GETJSAMPLE(inptr1[col]); + b = GETJSAMPLE(inptr2[col]); + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * No colorspace change, but conversion from separate-planes + * to interleaved representation. + */ + +METHODDEF(void) +rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = inptr0[col]; + outptr[RGB_GREEN] = inptr1[col]; + outptr[RGB_BLUE] = inptr2[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + */ + +METHODDEF(void) +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION count; + register int num_components = cinfo->num_components; + JDIMENSION num_cols = cinfo->output_width; + int ci; + + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = output_buf[0] + ci; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + outptr += num_components; + } + } + input_row++; + output_buf++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF(void) +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + num_rows, cinfo->output_width); +} + + +/* + * Convert grayscale to RGB: just duplicate the graylevel three times. + * This is provided to support applications that don't want to cope + * with grayscale as a separate case. + */ + +METHODDEF(void) +gray_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Adobe-style YCCK->CMYK conversion. + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + * conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF(void) +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + +// int jj = 0; + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + + outptr += 4; + + } + } + +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +start_pass_dcolor (j_decompress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL(void) +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + + my_cconvert_ptr cconvert; + int ci; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_deconverter)); + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + } + + /* Set out_color_components and conversion method based on requested space. + * Also clear the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + } else if (cinfo->jpeg_color_space == JCS_RGB) { + cconvert->pub.color_convert = rgb_gray_convert; + build_rgb_y_table(cinfo); + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB) { + cconvert->pub.color_convert = rgb_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + cinfo->out_color_components = 4; + if (cinfo->jpeg_color_space == JCS_YCCK) { + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: + /* Permit null conversion to same output space */ + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + cinfo->out_color_components = cinfo->num_components; + cconvert->pub.color_convert = null_convert; + } else /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/library/src/main/cpp/jpeg/src/jddctmgr.c b/library/src/main/cpp/jpeg/src/jddctmgr.c new file mode 100644 index 00000000..0ded9d57 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jddctmgr.c @@ -0,0 +1,384 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2002-2010 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_inverse_dct pub; /* public fields */ + + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} my_idct_controller; + +typedef my_idct_controller * my_idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + my_idct_ptr idct = (my_idct_ptr) cinfo->idct; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) { +#ifdef IDCT_SCALING_SUPPORTED + case ((1 << 8) + 1): + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((2 << 8) + 2): + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((3 << 8) + 3): + method_ptr = jpeg_idct_3x3; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((4 << 8) + 4): + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((5 << 8) + 5): + method_ptr = jpeg_idct_5x5; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((6 << 8) + 6): + method_ptr = jpeg_idct_6x6; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((7 << 8) + 7): + method_ptr = jpeg_idct_7x7; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((9 << 8) + 9): + method_ptr = jpeg_idct_9x9; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((10 << 8) + 10): + method_ptr = jpeg_idct_10x10; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((11 << 8) + 11): + method_ptr = jpeg_idct_11x11; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((12 << 8) + 12): + method_ptr = jpeg_idct_12x12; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((13 << 8) + 13): + method_ptr = jpeg_idct_13x13; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((14 << 8) + 14): + method_ptr = jpeg_idct_14x14; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((15 << 8) + 15): + method_ptr = jpeg_idct_15x15; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((16 << 8) + 16): + method_ptr = jpeg_idct_16x16; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((16 << 8) + 8): + method_ptr = jpeg_idct_16x8; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((14 << 8) + 7): + method_ptr = jpeg_idct_14x7; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((12 << 8) + 6): + method_ptr = jpeg_idct_12x6; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((10 << 8) + 5): + method_ptr = jpeg_idct_10x5; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((8 << 8) + 4): + method_ptr = jpeg_idct_8x4; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((6 << 8) + 3): + method_ptr = jpeg_idct_6x3; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((4 << 8) + 2): + method_ptr = jpeg_idct_4x2; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((2 << 8) + 1): + method_ptr = jpeg_idct_2x1; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((8 << 8) + 16): + method_ptr = jpeg_idct_8x16; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((7 << 8) + 14): + method_ptr = jpeg_idct_7x14; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((6 << 8) + 12): + method_ptr = jpeg_idct_6x12; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((5 << 8) + 10): + method_ptr = jpeg_idct_5x10; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((4 << 8) + 8): + method_ptr = jpeg_idct_4x8; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((3 << 8) + 6): + method_ptr = jpeg_idct_3x6; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((2 << 8) + 4): + method_ptr = jpeg_idct_2x4; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; + case ((1 << 8) + 2): + method_ptr = jpeg_idct_1x2; + method = JDCT_ISLOW; /* jidctint uses islow-style table */ + break; +#endif + case ((DCTSIZE << 8) + DCTSIZE): + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT2(cinfo, JERR_BAD_DCTSIZE, + compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size); + break; + } + idct->pub.inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored as ints to ensure access efficiency. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 1/8. + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 0.125); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL(void) +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + my_idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (my_idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_idct_controller)); + cinfo->idct = (struct jpeg_inverse_dct *) idct; + idct->pub.start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/library/src/main/cpp/jpeg/src/jdhuff.c b/library/src/main/cpp/jpeg/src/jdhuff.c new file mode 100644 index 00000000..06f92fe4 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdhuff.c @@ -0,0 +1,1541 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2006-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * Both sequential and progressive modes are supported in this single module. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & BIT_MASK(nbits)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + + +/* + * Expanded entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + boolean insufficient_data; /* set TRUE after emitting warning */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Following two fields used only in progressive mode */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ + + /* Following fields used only in sequential mode */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcu: */ + + /* Pointers to derived tables to be used for each block within an MCU */ + d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + /* Whether we care about the DC and AC coefficient values for each block */ + int coef_limit[D_MAX_BLOCKS_IN_MCU]; +} huff_entropy_decoder; + +typedef huff_entropy_decoder * huff_entropy_ptr; + + +static const int jpeg_zigzag_order[8][8] = { + { 0, 1, 5, 6, 14, 15, 27, 28 }, + { 2, 4, 7, 13, 16, 26, 29, 42 }, + { 3, 8, 12, 17, 25, 30, 41, 43 }, + { 9, 11, 18, 24, 31, 40, 44, 53 }, + { 10, 19, 23, 32, 39, 45, 52, 54 }, + { 20, 22, 33, 38, 46, 51, 55, 60 }, + { 21, 34, 37, 47, 50, 56, 59, 61 }, + { 35, 36, 48, 49, 57, 58, 62, 63 } +}; + +static const int jpeg_zigzag_order7[7][7] = { + { 0, 1, 5, 6, 14, 15, 27 }, + { 2, 4, 7, 13, 16, 26, 28 }, + { 3, 8, 12, 17, 25, 29, 38 }, + { 9, 11, 18, 24, 30, 37, 39 }, + { 10, 19, 23, 31, 36, 40, 45 }, + { 20, 22, 32, 35, 41, 44, 46 }, + { 21, 33, 34, 42, 43, 47, 48 } +}; + +static const int jpeg_zigzag_order6[6][6] = { + { 0, 1, 5, 6, 14, 15 }, + { 2, 4, 7, 13, 16, 25 }, + { 3, 8, 12, 17, 24, 26 }, + { 9, 11, 18, 23, 27, 32 }, + { 10, 19, 22, 28, 31, 33 }, + { 20, 21, 29, 30, 34, 35 } +}; + +static const int jpeg_zigzag_order5[5][5] = { + { 0, 1, 5, 6, 14 }, + { 2, 4, 7, 13, 15 }, + { 3, 8, 12, 16, 21 }, + { 9, 11, 17, 20, 22 }, + { 10, 18, 19, 23, 24 } +}; + +static const int jpeg_zigzag_order4[4][4] = { + { 0, 1, 5, 6 }, + { 2, 4, 7, 12 }, + { 3, 8, 11, 13 }, + { 9, 10, 14, 15 } +}; + +static const int jpeg_zigzag_order3[3][3] = { + { 0, 1, 5 }, + { 2, 4, 6 }, + { 3, 7, 8 } +}; + +static const int jpeg_zigzag_order2[2][2] = { + { 0, 1 }, + { 2, 3 } +}; + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +LOCAL(void) +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + d_derived_tbl *dtbl; + int p, i, l, si, numsymbols; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + numsymbols = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + /* valoffset[l] = huffval[] index of 1st symbol of code length l, + * minus the minimum code of length l + */ + dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } + + /* Validate symbols as being reasonable. + * For AC tables, we make no check, but accept all byte values 0..255. + * For DC tables, we require the symbols to be in range 0..15. + * (Tighter bounds could be applied depending on the data depth and mode, + * but this is sufficient to ensure safe decoding.) + */ + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; + if (sym < 0 || sym > 15) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + } + } +} + + +/* + * Out-of-line code for bit fetching. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +LOCAL(boolean) +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + j_decompress_ptr cinfo = state->cinfo; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + /* We fail to do so only if we hit a marker or are forced to suspend. */ + + if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ + while (bits_left < MIN_GET_BITS) { + register int c; + + /* Attempt to read a byte */ + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + /* Loop here to discard any padding FF's on terminating marker, + * so that we can save a valid unread_marker value. NOTE: we will + * accept multiple FF's followed by a 0 as meaning a single FF data + * byte. This data pattern is not valid according to the standard. + */ + do { + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. + * Save the marker code for later use. + * Fine point: it might appear that we should save the marker into + * bitread working state, not straight into permanent state. But + * once we have hit a marker, we cannot need to suspend within the + * current MCU, because we will read no more bytes from the data + * source. So it is OK to update permanent state right away. + */ + cinfo->unread_marker = c; + /* See if we need to insert some fake zero bits. */ + goto no_more_bytes; + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } /* end while */ + } else { + no_more_bytes: + /* We get here if we've read the marker that terminates the compressed + * data segment. There should be enough bits in the buffer register + * to satisfy the request; if so, no problem. + */ + if (nbits > bits_left) { + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * We use a nonvolatile flag to ensure that only one warning message + * appears per data segment. + */ + if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) { + WARNMS(cinfo, JWRN_HIT_MARKER); + ((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE; + } + /* Fill the buffer with zero bits */ + get_buffer <<= MIN_GET_BITS - bits_left; + bits_left = MIN_GET_BITS; + } + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and sub will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define BIT_MASK(nbits) ((1<<(nbits))-1) +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x)) + +#else + +#define BIT_MASK(nbits) bmask[nbits] +#define HUFF_EXTEND(x,s) ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x)) + +static const int bmask[16] = /* bmask[n] is mask for n rightmost bits */ + { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF }; + +#endif /* AVOID_TABLES */ + + +/* + * Out-of-line code for Huffman code decoding. + */ + +LOCAL(int) +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; +} + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int s, k, r; + unsigned int EOBRUN; + int Se, Al; + const int * natural_order; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + Se = cinfo->Se; + Al = cinfo->Al; + natural_order = cinfo->natural_order; + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + + if (EOBRUN > 0) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r == 15) { /* ZRL */ + k += 15; /* skip 15 zeroes in band */ + } else { /* EOBr, run length is 2^r + appended bits */ + EOBRUN = 1 << r; + if (r) { /* EOBr, r > 0 */ + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + } + EOBRUN--; /* this band is processed at this moment */ + break; /* force end-of-band */ + } + } + } + + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int blkn; + JBLOCKROW block; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Not worth the cycles to check insufficient_data here, + * since we will not change the data anyway if we read zeroes. + */ + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + (*block)[0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int s, k, r; + unsigned int EOBRUN; + int Se, p1, m1; + const int * natural_order; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, don't modify the MCU. + */ + if (! entropy->insufficient_data) { + + Se = cinfo->Se; + p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + natural_order = cinfo->natural_order; + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + } + } + + if (EOBRUN > 0) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + for (; k <= Se; k++) { + thiscoef = *block + natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + } + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz > 0) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Decode one MCU's worth of Huffman-compressed coefficients, + * partial blocks. + */ + +METHODDEF(boolean) +decode_mcu_sub (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + const int * natural_order; + int Se, blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + natural_order = cinfo->natural_order; + Se = cinfo->lim_Se; + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * htbl; + register int s, k, r; + int coef_limit, ci; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + htbl = entropy->dc_cur_tbls[blkn]; + HUFF_DECODE(s, br_state, htbl, return FALSE, label1); + + htbl = entropy->ac_cur_tbls[blkn]; + k = 1; + coef_limit = entropy->coef_limit[blkn]; + if (coef_limit) { + /* Convert DC difference to actual value, update last_dc_val */ + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient */ + (*block)[0] = (JCOEF) s; + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (; k < coef_limit; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in natural_order[] will save us + * if k > Se, which could happen if the data is corrupted. + */ + (*block)[natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + goto EndOfBlock; + k += 15; + } + } + } else { + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } + } + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + EndOfBlock: ; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Decode one MCU's worth of Huffman-compressed coefficients, + * full-size blocks. + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * htbl; + register int s, k, r; + int coef_limit, ci; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + htbl = entropy->dc_cur_tbls[blkn]; + HUFF_DECODE(s, br_state, htbl, return FALSE, label1); + + htbl = entropy->ac_cur_tbls[blkn]; + k = 1; + coef_limit = entropy->coef_limit[blkn]; + if (coef_limit) { + /* Convert DC difference to actual value, update last_dc_val */ + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient */ + (*block)[0] = (JCOEF) s; + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (; k < coef_limit; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + goto EndOfBlock; + k += 15; + } + } + } else { + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } + } + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, htbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + EndOfBlock: ; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, blkn, tbl, i; + jpeg_component_info * compptr; + + if (cinfo->progressive_mode) { + /* Validate progressive scan parameters */ + if (cinfo->Ss == 0) { + if (cinfo->Se != 0) + goto bad; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se) + goto bad; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + goto bad; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Ah-1 != cinfo->Al) + goto bad; + } + if (cinfo->Al > 13) { /* need not check for < 0 */ + /* Arguably the maximum Al value should be less than 13 for 8-bit precision, + * but the spec doesn't say so, and we try to be liberal about what we + * accept. Note: large Al values could result in out-of-range DC + * coefficients during early scans, leading to bizarre displays due to + * overflows in the IDCT math. But we won't crash. + */ + bad: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + } + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int coefi, cindex = cinfo->cur_comp_info[ci]->component_index; + int *coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (cinfo->Ss == 0) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + } else { + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || + ((cinfo->is_baseline || cinfo->Se < DCTSIZE2) && + cinfo->Se != cinfo->lim_Se)) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + /* Select MCU decoding routine */ + /* We retain the hard-coded case for full-size blocks. + * This is not necessary, but it appears that this version is slightly + * more performant in the given implementation. + * With an improved implementation we would prefer a single optimized + * function. + */ + if (cinfo->lim_Se != DCTSIZE2-1) + entropy->pub.decode_mcu = decode_mcu_sub; + else + entropy->pub.decode_mcu = decode_mcu; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->dc_derived_tbls[tbl]); + if (cinfo->lim_Se) { /* AC needs no table when not present */ + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->ac_derived_tbls[tbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Precalculate decoding info for each block in an MCU of this scan */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Precalculate which table to use for each block */ + entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + /* Decide whether we really care about the coefficient values */ + if (compptr->component_needed) { + ci = compptr->DCT_v_scaled_size; + i = compptr->DCT_h_scaled_size; + switch (cinfo->lim_Se) { + case (1*1-1): + entropy->coef_limit[blkn] = 1; + break; + case (2*2-1): + if (ci <= 0 || ci > 2) ci = 2; + if (i <= 0 || i > 2) i = 2; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1]; + break; + case (3*3-1): + if (ci <= 0 || ci > 3) ci = 3; + if (i <= 0 || i > 3) i = 3; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1]; + break; + case (4*4-1): + if (ci <= 0 || ci > 4) ci = 4; + if (i <= 0 || i > 4) i = 4; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1]; + break; + case (5*5-1): + if (ci <= 0 || ci > 5) ci = 5; + if (i <= 0 || i > 5) i = 5; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1]; + break; + case (6*6-1): + if (ci <= 0 || ci > 6) ci = 6; + if (i <= 0 || i > 6) i = 6; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1]; + break; + case (7*7-1): + if (ci <= 0 || ci > 7) ci = 7; + if (i <= 0 || i > 7) i = 7; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1]; + break; + default: + if (ci <= 0 || ci > 8) ci = 8; + if (i <= 0 || i > 8) i = 8; + entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1]; + break; + } + } else { + entropy->coef_limit[blkn] = 0; + } + } + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_huff_decoder; + + if (cinfo->progressive_mode) { + /* Create progression status table */ + int *coef_bit_ptr, ci; + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + } else { + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } + } +} diff --git a/library/src/main/cpp/jpeg/src/jdinput.c b/library/src/main/cpp/jpeg/src/jdinput.c new file mode 100644 index 00000000..1d9ae580 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdinput.c @@ -0,0 +1,660 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2002-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient decoding). The actual input + * reading is done in jdmarker.c, jdhuff.c, and jdarith.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + int inheaders; /* Nonzero until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + */ + +GLOBAL(void) +jpeg_core_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase. + * This function is used for transcoding and full decompression. + */ +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) { + /* Provide 1/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 1; + cinfo->min_DCT_v_scaled_size = 1; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) { + /* Provide 2/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 2; + cinfo->min_DCT_v_scaled_size = 2; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) { + /* Provide 3/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 3; + cinfo->min_DCT_v_scaled_size = 3; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) { + /* Provide 4/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 4; + cinfo->min_DCT_v_scaled_size = 4; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) { + /* Provide 5/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 5; + cinfo->min_DCT_v_scaled_size = 5; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) { + /* Provide 6/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 6; + cinfo->min_DCT_v_scaled_size = 6; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) { + /* Provide 7/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 7; + cinfo->min_DCT_v_scaled_size = 7; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) { + /* Provide 8/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 8; + cinfo->min_DCT_v_scaled_size = 8; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) { + /* Provide 9/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 9; + cinfo->min_DCT_v_scaled_size = 9; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) { + /* Provide 10/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 10; + cinfo->min_DCT_v_scaled_size = 10; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) { + /* Provide 11/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 11; + cinfo->min_DCT_v_scaled_size = 11; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) { + /* Provide 12/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 12; + cinfo->min_DCT_v_scaled_size = 12; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) { + /* Provide 13/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 13; + cinfo->min_DCT_v_scaled_size = 13; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) { + /* Provide 14/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 14; + cinfo->min_DCT_v_scaled_size = 14; + } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) { + /* Provide 15/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 15; + cinfo->min_DCT_v_scaled_size = 15; + } else { + /* Provide 16/block_size scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size); + cinfo->min_DCT_h_scaled_size = 16; + cinfo->min_DCT_v_scaled_size = 16; + } + + /* Recompute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size; + compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size; + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized DCT_scaled_size, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ +} + + +LOCAL(void) +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Derive block_size, natural_order, and lim_Se */ + if (cinfo->is_baseline || (cinfo->progressive_mode && + cinfo->comps_in_scan)) { /* no pseudo SOS marker */ + cinfo->block_size = DCTSIZE; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + } else + switch (cinfo->Se) { + case (1*1-1): + cinfo->block_size = 1; + cinfo->natural_order = jpeg_natural_order; /* not needed */ + cinfo->lim_Se = cinfo->Se; + break; + case (2*2-1): + cinfo->block_size = 2; + cinfo->natural_order = jpeg_natural_order2; + cinfo->lim_Se = cinfo->Se; + break; + case (3*3-1): + cinfo->block_size = 3; + cinfo->natural_order = jpeg_natural_order3; + cinfo->lim_Se = cinfo->Se; + break; + case (4*4-1): + cinfo->block_size = 4; + cinfo->natural_order = jpeg_natural_order4; + cinfo->lim_Se = cinfo->Se; + break; + case (5*5-1): + cinfo->block_size = 5; + cinfo->natural_order = jpeg_natural_order5; + cinfo->lim_Se = cinfo->Se; + break; + case (6*6-1): + cinfo->block_size = 6; + cinfo->natural_order = jpeg_natural_order6; + cinfo->lim_Se = cinfo->Se; + break; + case (7*7-1): + cinfo->block_size = 7; + cinfo->natural_order = jpeg_natural_order7; + cinfo->lim_Se = cinfo->Se; + break; + case (8*8-1): + cinfo->block_size = 8; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (9*9-1): + cinfo->block_size = 9; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (10*10-1): + cinfo->block_size = 10; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (11*11-1): + cinfo->block_size = 11; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (12*12-1): + cinfo->block_size = 12; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (13*13-1): + cinfo->block_size = 13; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (14*14-1): + cinfo->block_size = 14; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (15*15-1): + cinfo->block_size = 15; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + case (16*16-1): + cinfo->block_size = 16; + cinfo->natural_order = jpeg_natural_order; + cinfo->lim_Se = DCTSIZE2-1; + break; + default: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + break; + } + + /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size. + * In the full decompressor, + * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c; + * but in the transcoder, + * jpeg_calc_output_dimensions is not used, so we must do it here. + */ + cinfo->min_DCT_h_scaled_size = cinfo->block_size; + cinfo->min_DCT_v_scaled_size = cinfo->block_size; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_h_scaled_size = cinfo->block_size; + compptr->DCT_v_scaled_size = cinfo->block_size; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL(void) +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_h_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL(void) +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + latch_quant_tables(cinfo); + (*cinfo->entropy->start_pass) (cinfo); + (*cinfo->coef->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->coef->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF(void) +finish_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + * + * Note: This function should NOT return a pseudo SOS marker (with zero + * component number) to the caller. A pseudo marker received by + * read_markers is processed and then skipped for other markers. + */ + +METHODDEF(int) +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + for (;;) { /* Loop to pass pseudo SOS marker */ + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + if (inputctl->inheaders == 1) + initial_setup(cinfo); + if (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */ + inputctl->inheaders = 2; + break; + } + inputctl->inheaders = 0; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapimin.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + if (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */ + break; + start_input_pass(cinfo); + } + return val; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + return val; + case JPEG_SUSPENDED: + return val; + default: + return val; + } + } +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = 1; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_input_controller)); + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = 1; +} diff --git a/library/src/main/cpp/jpeg/src/jdmainct.c b/library/src/main/cpp/jpeg/src/jdmainct.c new file mode 100644 index 00000000..02723ca7 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdmainct.c @@ -0,0 +1,512 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. (We require DCT_scaled_size values to be + * chosen such that these numbers are integers. In practice DCT_scaled_size + * values will likely be powers of two, so we actually have the stronger + * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The coefficient controller will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or + * exactly min_DCT_scaled_size row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the DCT_scaled_size values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_DCT_scaled_size is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF(void) process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL(void) +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_DCT_v_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + main->xbuffer[0] = (JSAMPIMAGE) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + main->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + main->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL(void) +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in main->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_v_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + xbuf0 = main->xbuffer[0][ci]; + xbuf1 = main->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = main->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_v_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + xbuf0 = main->xbuffer[0][ci]; + xbuf1 = main->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL(void) +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size; + rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = main->xbuffer[main->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + main->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + main->context_state = CTX_PREPARE_FOR_IMCU; + main->iMCU_row_ctr = 0; + } else { + /* Simple case with no context needed */ + main->pub.process_data = process_data_simple_main; + } + main->buffer_full = FALSE; /* Mark buffer empty */ + main->rowgroup_ctr = 0; + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + main->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF(void) +process_data_simple_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + JDIMENSION rowgroups_avail; + + /* Read input data if we haven't filled the main buffer yet */ + if (! main->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer)) + return; /* suspension forced, can do nothing more */ + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + } + + /* There are always min_DCT_scaled_size row groups in an iMCU row. */ + rowgroups_avail = (JDIMENSION) cinfo->min_DCT_v_scaled_size; + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, main->buffer, + &main->rowgroup_ctr, rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + if (main->rowgroup_ctr >= rowgroups_avail) { + main->buffer_full = FALSE; + main->rowgroup_ctr = 0; + } +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF(void) +process_data_context_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! main->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, + main->xbuffer[main->whichptr])) + return; /* suspension forced, can do nothing more */ + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + main->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (main->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + &main->rowgroup_ctr, main->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (main->rowgroup_ctr < main->rowgroups_avail) + return; /* Need to suspend */ + main->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + main->rowgroup_ctr = 0; + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (main->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + main->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + &main->rowgroup_ctr, main->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (main->rowgroup_ctr < main->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (main->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + main->whichptr ^= 1; /* 0=>1 or 1=>0 */ + main->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1); + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2); + main->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF(void) +process_data_crank_post (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr main; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + main = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_d_main_controller *) main; + main->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_DCT_v_scaled_size + 2; + } else { + ngroups = cinfo->min_DCT_v_scaled_size; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; /* height of a row group of component */ + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * compptr->DCT_h_scaled_size, + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/library/src/main/cpp/jpeg/src/jdmarker.c b/library/src/main/cpp/jpeg/src/jdmarker.c new file mode 100644 index 00000000..f2a9cc42 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdmarker.c @@ -0,0 +1,1406 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_reader pub; /* public fields */ + + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* Limit on marker data length to save for each marker type */ + unsigned int length_limit_COM; + unsigned int length_limit_APPn[16]; + + /* Status of COM/APPn marker saving */ + jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ + unsigned int bytes_read; /* data bytes read so far in marker */ + /* Note: cur_marker is not linked into marker_list until it's all read. */ +} my_marker_reader; + +typedef my_marker_reader * my_marker_ptr; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters + * can fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments + * that might not fit. If we are simply dropping such a marker, we use + * skip_input_data to get past it, and thereby put the problem on the + * source manager's shoulders. If we are saving the marker's contents + * into memory, we use a slightly different convention: when forced to + * suspend, the marker processor updates the restart point to the end of + * what it's consumed (ie, the end of the buffer) before returning FALSE. + * On resumption, cinfo->unread_marker still contains the marker code, + * but the data source will point to the next chunk of marker data. + * The marker processor must retain internal state to deal with this. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL(boolean) +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL(boolean) +get_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog, + boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->is_baseline = is_baseline; + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN || + (n == 0 && !cinfo->progressive_mode)) + /* pseudo SOS marker only allowed in progressive mode */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another (non-pseudo) SOS marker */ + if (n) cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +#ifdef D_ARITH_CODING_SUPPORTED + +LOCAL(boolean) +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + +#else /* ! D_ARITH_CODING_SUPPORTED */ + +#define get_dac(cinfo) skip_variable(cinfo) + +#endif /* D_ARITH_CODING_SUPPORTED */ + + +LOCAL(boolean) +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 16) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + /* Here we just do minimal validation of the counts to avoid walking + * off the end of our table space. jdhuff.c will check more carefully. + */ + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length, count, i; + int n, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + const int *natural_order; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + length--; + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + if (prec) { + if (length < DCTSIZE2 * 2) { + /* Initialize full table for safety. */ + for (i = 0; i < DCTSIZE2; i++) { + quant_ptr->quantval[i] = 1; + } + count = length >> 1; + } else + count = DCTSIZE2; + } else { + if (length < DCTSIZE2) { + /* Initialize full table for safety. */ + for (i = 0; i < DCTSIZE2; i++) { + quant_ptr->quantval[i] = 1; + } + count = length; + } else + count = DCTSIZE2; + } + + switch (count) { + case (2*2): natural_order = jpeg_natural_order2; break; + case (3*3): natural_order = jpeg_natural_order3; break; + case (4*4): natural_order = jpeg_natural_order4; break; + case (5*5): natural_order = jpeg_natural_order5; break; + case (6*6): natural_order = jpeg_natural_order6; break; + case (7*7): natural_order = jpeg_natural_order7; break; + default: natural_order = jpeg_natural_order; break; + } + + for (i = 0; i < count; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + /* We convert the zigzag-order table to natural array order. */ + quant_ptr->quantval[natural_order[i]] = (UINT16) tmp; + } + + if (cinfo->err->trace_level >= 2) { + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + } + + length -= count; + if (prec) length -= count; + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Routines for processing APPn and COM markers. + * These are either saved in memory or discarded, per application request. + * APP0 and APP14 are specially checked to see if they are + * JFIF and Adobe markers, respectively. + */ + +#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ +#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ +#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ + + +LOCAL(void) +examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP0. + * Take appropriate action if it is a JFIF marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + INT32 totallen = (INT32) datalen + remaining; + + if (datalen >= APP0_DATA_LEN && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x49 && + GETJOCTET(data[3]) == 0x46 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF APP0 marker: save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = GETJOCTET(data[5]); + cinfo->JFIF_minor_version = GETJOCTET(data[6]); + cinfo->density_unit = GETJOCTET(data[7]); + cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); + cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); + /* Check version. + * Major version must be 1, anything else signals an incompatible change. + * (We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec.) + * Minor version should be 0..2, but process anyway if newer. + */ + if (cinfo->JFIF_major_version != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version); + /* Generate trace messages */ + TRACEMS5(cinfo, 1, JTRC_JFIF, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + /* Validate thumbnail dimensions and issue appropriate messages */ + if (GETJOCTET(data[12]) | GETJOCTET(data[13])) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, + GETJOCTET(data[12]), GETJOCTET(data[13])); + totallen -= APP0_DATA_LEN; + if (totallen != + ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); + } else if (datalen >= 6 && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x58 && + GETJOCTET(data[3]) == 0x58 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF "JFXX" extension APP0 marker */ + /* The library doesn't actually do anything with these, + * but we try to produce a helpful trace message. + */ + switch (GETJOCTET(data[5])) { + case 0x10: + TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); + break; + case 0x11: + TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); + break; + case 0x13: + TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); + break; + default: + TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, + GETJOCTET(data[5]), (int) totallen); + break; + } + } else { + /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); + } +} + + +LOCAL(void) +examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP14. + * Take appropriate action if it is an Adobe marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + unsigned int version, flags0, flags1, transform; + + if (datalen >= APP14_DATA_LEN && + GETJOCTET(data[0]) == 0x41 && + GETJOCTET(data[1]) == 0x64 && + GETJOCTET(data[2]) == 0x6F && + GETJOCTET(data[3]) == 0x62 && + GETJOCTET(data[4]) == 0x65) { + /* Found Adobe APP14 marker */ + version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); + flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); + flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); + transform = GETJOCTET(data[11]); + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); + } +} + + +METHODDEF(boolean) +get_interesting_appn (j_decompress_ptr cinfo) +/* Process an APP0 or APP14 marker without saving it */ +{ + INT32 length; + JOCTET b[APPN_DATA_LEN]; + unsigned int i, numtoread; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* get the interesting part of the marker data */ + if (length >= APPN_DATA_LEN) + numtoread = APPN_DATA_LEN; + else if (length > 0) + numtoread = (unsigned int) length; + else + numtoread = 0; + for (i = 0; i < numtoread; i++) + INPUT_BYTE(cinfo, b[i], return FALSE); + length -= numtoread; + + /* process it */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + case M_APP14: + examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + default: + /* can't get here unless jpeg_save_markers chooses wrong processor */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +#ifdef SAVE_MARKERS_SUPPORTED + +METHODDEF(boolean) +save_marker (j_decompress_ptr cinfo) +/* Save an APPn or COM marker into the marker list */ +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + jpeg_saved_marker_ptr cur_marker = marker->cur_marker; + unsigned int bytes_read, data_length; + JOCTET FAR * data; + INT32 length = 0; + INPUT_VARS(cinfo); + + if (cur_marker == NULL) { + /* begin reading a marker */ + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + if (length >= 0) { /* watch out for bogus length word */ + /* figure out how much we want to save */ + unsigned int limit; + if (cinfo->unread_marker == (int) M_COM) + limit = marker->length_limit_COM; + else + limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; + if ((unsigned int) length < limit) + limit = (unsigned int) length; + /* allocate and initialize the marker item */ + cur_marker = (jpeg_saved_marker_ptr) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_struct) + limit); + cur_marker->next = NULL; + cur_marker->marker = (UINT8) cinfo->unread_marker; + cur_marker->original_length = (unsigned int) length; + cur_marker->data_length = limit; + /* data area is just beyond the jpeg_marker_struct */ + data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); + marker->cur_marker = cur_marker; + marker->bytes_read = 0; + bytes_read = 0; + data_length = limit; + } else { + /* deal with bogus length word */ + bytes_read = data_length = 0; + data = NULL; + } + } else { + /* resume reading a marker */ + bytes_read = marker->bytes_read; + data_length = cur_marker->data_length; + data = cur_marker->data + bytes_read; + } + + while (bytes_read < data_length) { + INPUT_SYNC(cinfo); /* move the restart point to here */ + marker->bytes_read = bytes_read; + /* If there's not at least one byte in buffer, suspend */ + MAKE_BYTE_AVAIL(cinfo, return FALSE); + /* Copy bytes with reasonable rapidity */ + while (bytes_read < data_length && bytes_in_buffer > 0) { + *data++ = *next_input_byte++; + bytes_in_buffer--; + bytes_read++; + } + } + + /* Done reading what we want to read */ + if (cur_marker != NULL) { /* will be NULL if bogus length word */ + /* Add new marker to end of list */ + if (cinfo->marker_list == NULL) { + cinfo->marker_list = cur_marker; + } else { + jpeg_saved_marker_ptr prev = cinfo->marker_list; + while (prev->next != NULL) + prev = prev->next; + prev->next = cur_marker; + } + /* Reset pointer & calc remaining data length */ + data = cur_marker->data; + length = cur_marker->original_length - data_length; + } + /* Reset to initial state for next marker */ + marker->cur_marker = NULL; + + /* Process the marker if interesting; else just make a generic trace msg */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, data, data_length, length); + break; + case M_APP14: + examine_app14(cinfo, data, data_length, length); + break; + default: + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, + (int) (data_length + length)); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +METHODDEF(boolean) +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL(boolean) +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * Note: This function may return a pseudo SOS marker (with zero + * component number) for treat by input controller's consume_input. + * consume_input itself should filter out (skip) the pseudo marker + * after processing for the caller. + */ + +METHODDEF(int) +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + if (! get_sof(cinfo, TRUE, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, FALSE, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ + cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF(boolean) +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL(boolean) +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + marker->pub.saw_SOI = FALSE; /* set internal state too */ + marker->pub.saw_SOF = FALSE; + marker->pub.discarded_bytes = 0; + marker->cur_marker = NULL; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker; + int i; + + /* Create subobject in permanent pool */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_marker_reader)); + cinfo->marker = (struct jpeg_marker_reader *) marker; + /* Initialize public method pointers */ + marker->pub.reset_marker_reader = reset_marker_reader; + marker->pub.read_markers = read_markers; + marker->pub.read_restart_marker = read_restart_marker; + /* Initialize COM/APPn processing. + * By default, we examine and then discard APP0 and APP14, + * but simply discard COM and all other APPn. + */ + marker->process_COM = skip_variable; + marker->length_limit_COM = 0; + for (i = 0; i < 16; i++) { + marker->process_APPn[i] = skip_variable; + marker->length_limit_APPn[i] = 0; + } + marker->process_APPn[0] = get_interesting_appn; + marker->process_APPn[14] = get_interesting_appn; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} + + +/* + * Control saving of COM and APPn markers into marker_list. + */ + +#ifdef SAVE_MARKERS_SUPPORTED + +GLOBAL(void) +jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + long maxlength; + jpeg_marker_parser_method processor; + + /* Length limit mustn't be larger than what we can allocate + * (should only be a concern in a 16-bit environment). + */ + maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); + if (((long) length_limit) > maxlength) + length_limit = (unsigned int) maxlength; + + /* Choose processor routine to use. + * APP0/APP14 have special requirements. + */ + if (length_limit) { + processor = save_marker; + /* If saving APP0/APP14, save at least enough for our internal use. */ + if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) + length_limit = APP0_DATA_LEN; + else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) + length_limit = APP14_DATA_LEN; + } else { + processor = skip_variable; + /* If discarding APP0/APP14, use our regular on-the-fly processor. */ + if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) + processor = get_interesting_appn; + } + + if (marker_code == (int) M_COM) { + marker->process_COM = processor; + marker->length_limit_COM = length_limit; + } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { + marker->process_APPn[marker_code - (int) M_APP0] = processor; + marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; + } else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL(void) +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + if (marker_code == (int) M_COM) + marker->process_COM = routine; + else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) + marker->process_APPn[marker_code - (int) M_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} diff --git a/library/src/main/cpp/jpeg/src/jdmaster.c b/library/src/main/cpp/jpeg/src/jdmaster.c new file mode 100644 index 00000000..fef72a21 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdmaster.c @@ -0,0 +1,531 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2002-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL(boolean) +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || + cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || + cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size || + cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size || + cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size || + cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL(void) +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase. + * This function is used for full decompression. + */ +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; +#endif + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Compute core output image dimensions and DCT scaling choices. */ + jpeg_core_output_dimensions(cinfo); + +#ifdef IDCT_SCALING_SUPPORTED + + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code adapts subsampling ratios which are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = 1; + while (cinfo->min_DCT_h_scaled_size * ssize <= + (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) { + ssize = ssize * 2; + } + compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize; + ssize = 1; + while (cinfo->min_DCT_v_scaled_size * ssize <= + (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) && + (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) { + ssize = ssize * 2; + } + compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize; + + /* We don't support IDCT ratios larger than 2. */ + if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2) + compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2; + else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2) + compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size), + (long) (cinfo->max_h_samp_factor * cinfo->block_size)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size), + (long) (cinfo->max_v_samp_factor * cinfo->block_size)); + } + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + break; + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL(void) +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL(void) +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_decoder(cinfo); + else { + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapistd.c will crank the pass to completion.) + */ + +METHODDEF(void) +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF(void) +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL(void) +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL(void) +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/library/src/main/cpp/jpeg/src/jdmerge.c b/library/src/main/cpp/jpeg/src/jdmerge.c new file mode 100644 index 00000000..37444468 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdmerge.c @@ -0,0 +1,400 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters of the + * multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCbCr => RGB color conversion only. + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these are + * the only common cases. (For uncommon cases we fall back on the more + * general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + upsample->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + upsample->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF(void) +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF(void) +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF(void) +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF(void) +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL(void) +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jdpostct.c b/library/src/main/cpp/jpeg/src/jdpostct.c new file mode 100644 index 00000000..571563d7 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdpostct.c @@ -0,0 +1,290 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF(void) post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF(void) post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF(void) +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL(void) +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/library/src/main/cpp/jpeg/src/jdsample.c b/library/src/main/cpp/jpeg/src/jdsample.c new file mode 100644 index 00000000..7bc8885b --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdsample.c @@ -0,0 +1,361 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2002-2008 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF(void) +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF(void) +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = input_data; +} + + +/* + * This is a no-op version used for "uninteresting" components. + * These components will not be referenced by color conversion. + */ + +METHODDEF(void) +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = NULL; /* safety check */ +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF(void) +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + int inrow, outrow; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + /* Generate one output row with proper horizontal expansion */ + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + v_expand-1, cinfo->output_width); + } + inrow++; + outrow += v_expand; + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int outrow; + + for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) { + inptr = input_data[outrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow, outrow; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + 1, cinfo->output_width); + inrow++; + outrow += 2; + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL(void) +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + boolean need_buffer; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) / + cinfo->min_DCT_h_scaled_size; + v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) / + cinfo->min_DCT_v_scaled_size; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + need_buffer = TRUE; + if (! compptr->component_needed) { + /* Don't bother to upsample an uninteresting component. */ + upsample->methods[ci] = noop_upsample; + need_buffer = FALSE; + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + need_buffer = FALSE; + } else if (h_in_group * 2 == h_out_group && + v_in_group == v_out_group) { + /* Special case for 2h1v upsampling */ + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special case for 2h2v upsampling */ + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + if (need_buffer) { + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/library/src/main/cpp/jpeg/src/jdtrans.c b/library/src/main/cpp/jpeg/src/jdtrans.c new file mode 100644 index 00000000..22dd47fb --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jdtrans.c @@ -0,0 +1,140 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * Modified 2000-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * An alternative usage is to simply obtain access to the coefficient arrays + * during a buffered-image-mode decompression operation. This is allowed + * after any jpeg_finish_output() call. The arrays can be accessed until + * jpeg_finish_decompress() is called. (Note that any call to the library + * may reposition the arrays, so don't rely on access_virt_barray() results + * to stay valid across library calls.) + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL(jvirt_barray_ptr *) +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return cinfo->coef->coef_arrays; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return NULL; /* keep compiler happy */ +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL(void) +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* This is effectively a buffered-image operation. */ + cinfo->buffered_image = TRUE; + + /* Compute output image dimensions and related values. */ + jpeg_core_output_dimensions(cinfo); + + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) + jinit_arith_decoder(cinfo); + else { + jinit_huff_decoder(cinfo); + } + + /* Always get a full-image coefficient buffer. */ + jinit_d_coef_controller(cinfo, TRUE); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/library/src/main/cpp/jpeg/src/jerror.c b/library/src/main/cpp/jpeg/src/jerror.c new file mode 100644 index 00000000..3da7be86 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jerror.c @@ -0,0 +1,252 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, + * you get a Windows-specific hack to display error messages in a dialog box. + * It ain't much, but it beats dropping error messages into the bit bucket, + * which is what happens to output to stderr under most Windows C compilers. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifdef USE_WINDOWS_MESSAGEBOX +#include +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF(void) +error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + exit(EXIT_FAILURE); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL(struct jpeg_error_mgr *) +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/library/src/main/cpp/jpeg/src/jfdctflt.c b/library/src/main/cpp/jpeg/src/jfdctflt.c new file mode 100644 index 00000000..74d0d862 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jfdctflt.c @@ -0,0 +1,174 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_float (FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + JSAMPROW elemptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Load data into workspace */ + tmp0 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7])); + tmp7 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7])); + tmp1 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6])); + tmp6 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6])); + tmp2 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5])); + tmp5 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5])); + tmp3 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4])); + tmp4 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4])); + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Apply unsigned->signed conversion */ + dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jfdctfst.c b/library/src/main/cpp/jpeg/src/jfdctfst.c new file mode 100644 index 00000000..8cad5f22 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jfdctfst.c @@ -0,0 +1,230 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * Modified 2003-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_ifast (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Load data into workspace */ + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp7 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp6 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp5 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + tmp4 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Apply unsigned->signed conversion */ + dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jfdctint.c b/library/src/main/cpp/jpeg/src/jfdctint.c new file mode 100644 index 00000000..1dde58c4 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jfdctint.c @@ -0,0 +1,4348 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modification developed 2003-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + * + * We also provide FDCT routines with various input sample block sizes for + * direct resolution reduction or enlargement and for direct resolving the + * common 2x1 and 1x2 subsampling cases without additional resampling: NxN + * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 output DCT block. + * + * For N<8 we fill the remaining block coefficients with zero. + * For N>8 we apply a partial N-point FDCT on the input samples, computing + * just the lower 8 frequency coefficients and discarding the rest. + * + * We must scale the output coefficients of the N-point FDCT appropriately + * to the standard 8-point FDCT level by 8/N per 1-D pass. This scaling + * is folded into the constant multipliers (pass 2) and/or final/initial + * shifting. + * + * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases + * since there would be too many additional constants to pre-calculate. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_islow (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + dataptr[2] = (DCTELEM) RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents sqrt(2) * cos(K*pi/16). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp10 = tmp0 + tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */ + tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + + tmp12 += z1; + tmp13 += z1; + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) + RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) + RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + /* Add fudge factor here for final descale. */ + tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1)); + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + dataptr[DCTSIZE*2] = (DCTELEM) + RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents sqrt(2) * cos(K*pi/16). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp10 = tmp0 + tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */ + tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + + tmp12 += z1; + tmp13 += z1; + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) + RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) + RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#ifdef DCT_SCALING_SUPPORTED + + +/* + * Perform the forward DCT on a 7x7 sample block. + */ + +GLOBAL(void) +jpeg_fdct_7x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* cK represents sqrt(2) * cos(K*pi/14). */ + + dataptr = data; + for (ctr = 0; ctr < 7; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]); + tmp3 = GETJSAMPLE(elemptr[3]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]); + + z1 = tmp0 + tmp2; + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */ + dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */ + dataptr[4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/7)**2 = 64/49, which we fold + * into the constant multipliers: + * cK now represents sqrt(2) * cos(K*pi/14) * 64/49. + */ + + dataptr = data; + for (ctr = 0; ctr < 7; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4]; + tmp3 = dataptr[DCTSIZE*3]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5]; + tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4]; + + z1 = tmp0 + tmp2; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */ + CONST_BITS+PASS1_BITS); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */ + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 6x6 sample block. + */ + +GLOBAL(void) +jpeg_fdct_6x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11, tmp12; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* cK represents sqrt(2) * cos(K*pi/12). */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]); + tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */ + CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */ + CONST_BITS-PASS1_BITS); + + dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS)); + dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS); + dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS)); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)**2 = 16/9, which we fold + * into the constant multipliers: + * cK now represents sqrt(2) * cos(K*pi/12) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5]; + tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3]; + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 5x5 sample block. + */ + +GLOBAL(void) +jpeg_fdct_5x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We scale the results further by 2 as part of output adaption */ + /* scaling for different DCT size. */ + /* cK represents sqrt(2) * cos(K*pi/10). */ + + dataptr = data; + for (ctr = 0; ctr < 5; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]); + tmp2 = GETJSAMPLE(elemptr[2]); + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << (PASS1_BITS+1)); + tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */ + dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS-1); + dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS-1); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */ + + dataptr[1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */ + CONST_BITS-PASS1_BITS-1); + dataptr[3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */ + CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/5)**2 = 64/25, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * cK now represents sqrt(2) * cos(K*pi/10) * 32/25. + */ + + dataptr = data; + for (ctr = 0; ctr < 5; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3]; + tmp2 = dataptr[DCTSIZE*2]; + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 4x4 sample block. + */ + +GLOBAL(void) +jpeg_fdct_4x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We must also scale the output by (8/4)**2 = 2**2, which we add here. */ + /* cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+2)); + dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+2)); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-3); + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS-2); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS-2); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1)); + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS+PASS1_BITS-1); + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 3x3 sample block. + */ + +GLOBAL(void) +jpeg_fdct_3x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We scale the results further by 2**2 as part of output adaption */ + /* scaling for different DCT size. */ + /* cK represents sqrt(2) * cos(K*pi/6). */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]); + tmp1 = GETJSAMPLE(elemptr[1]); + + tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+2)); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */ + CONST_BITS-PASS1_BITS-2); + + /* Odd part */ + + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */ + CONST_BITS-PASS1_BITS-2); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/3)**2 = 64/9, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * cK now represents sqrt(2) * cos(K*pi/6) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2]; + tmp1 = dataptr[DCTSIZE*1]; + + tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 2x2 sample block. + */ + +GLOBAL(void) +jpeg_fdct_2x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + JSAMPROW elemptr; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT. */ + + /* Row 0 */ + elemptr = sample_data[0] + start_col; + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]); + tmp1 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]); + + /* Row 1 */ + elemptr = sample_data[1] + start_col; + + tmp2 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]); + tmp3 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]); + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/2)**2 = 2**4. + */ + + /* Column 0 */ + /* Apply unsigned->signed conversion */ + data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp2 - 4 * CENTERJSAMPLE) << 4); + data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp2) << 4); + + /* Column 1 */ + data[DCTSIZE*0+1] = (DCTELEM) ((tmp1 + tmp3) << 4); + data[DCTSIZE*1+1] = (DCTELEM) ((tmp1 - tmp3) << 4); +} + + +/* + * Perform the forward DCT on a 1x1 sample block. + */ + +GLOBAL(void) +jpeg_fdct_1x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* We leave the result scaled up by an overall factor of 8. */ + /* We must also scale the output by (8/1)**2 = 2**6. */ + /* Apply unsigned->signed conversion */ + data[0] = (DCTELEM) + ((GETJSAMPLE(sample_data[0][start_col]) - CENTERJSAMPLE) << 6); +} + + +/* + * Perform the forward DCT on a 9x9 sample block. + */ + +GLOBAL(void) +jpeg_fdct_9x9 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2; + DCTELEM workspace[8]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* we scale the results further by 2 as part of output adaption */ + /* scaling for different DCT size. */ + /* cK represents sqrt(2) * cos(K*pi/18). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[8]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[7]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[6]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[5]); + tmp4 = GETJSAMPLE(elemptr[4]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[8]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[7]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[6]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[5]); + + z1 = tmp0 + tmp2 + tmp3; + z2 = tmp1 + tmp4; + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) ((z1 + z2 - 9 * CENTERJSAMPLE) << 1); + dataptr[6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z2 - z2, FIX(0.707106781)), /* c6 */ + CONST_BITS-1); + z1 = MULTIPLY(tmp0 - tmp2, FIX(1.328926049)); /* c2 */ + z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(0.707106781)); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.083350441)) /* c4 */ + + z1 + z2, CONST_BITS-1); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.245575608)) /* c8 */ + + z1 - z2, CONST_BITS-1); + + /* Odd part */ + + dataptr[3] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.224744871)), /* c3 */ + CONST_BITS-1); + + tmp11 = MULTIPLY(tmp11, FIX(1.224744871)); /* c3 */ + tmp0 = MULTIPLY(tmp10 + tmp12, FIX(0.909038955)); /* c5 */ + tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.483689525)); /* c7 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS-1); + + tmp2 = MULTIPLY(tmp12 - tmp13, FIX(1.392728481)); /* c1 */ + + dataptr[5] = (DCTELEM) DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS-1); + dataptr[7] = (DCTELEM) DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS-1); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 9) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/9)**2 = 64/81, which we partially + * fold into the constant multipliers and final/initial shifting: + * cK now represents sqrt(2) * cos(K*pi/18) * 128/81. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*0]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*7]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*6]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*5]; + tmp4 = dataptr[DCTSIZE*4]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*0]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*7]; + tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*6]; + tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*5]; + + z1 = tmp0 + tmp2 + tmp3; + z2 = tmp1 + tmp4; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + z2, FIX(1.580246914)), /* 128/81 */ + CONST_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z2 - z2, FIX(1.117403309)), /* c6 */ + CONST_BITS+2); + z1 = MULTIPLY(tmp0 - tmp2, FIX(2.100031287)); /* c2 */ + z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(1.117403309)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.711961190)) /* c4 */ + + z1 + z2, CONST_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.388070096)) /* c8 */ + + z1 - z2, CONST_BITS+2); + + /* Odd part */ + + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.935399303)), /* c3 */ + CONST_BITS+2); + + tmp11 = MULTIPLY(tmp11, FIX(1.935399303)); /* c3 */ + tmp0 = MULTIPLY(tmp10 + tmp12, FIX(1.436506004)); /* c5 */ + tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.764348879)); /* c7 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS+2); + + tmp2 = MULTIPLY(tmp12 - tmp13, FIX(2.200854883)); /* c1 */ + + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) + DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 10x10 sample block. + */ + +GLOBAL(void) +jpeg_fdct_10x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + DCTELEM workspace[8*2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* we scale the results further by 2 as part of output adaption */ + /* scaling for different DCT size. */ + /* cK represents sqrt(2) * cos(K*pi/20). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]); + tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]); + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << 1); + tmp12 += tmp12; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */ + CONST_BITS-1); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */ + CONST_BITS-1); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */ + CONST_BITS-1); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << 1); + tmp2 <<= CONST_BITS; + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */ + CONST_BITS-1); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */ + (tmp11 << (CONST_BITS - 1)) - tmp2; + dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-1); + dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-1); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 10) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/10)**2 = 16/25, which we partially + * fold into the constant multipliers and final/initial shifting: + * cK now represents sqrt(2) * cos(K*pi/20) * 32/25. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0]; + tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5]; + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */ + CONST_BITS+2); + tmp12 += tmp12; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */ + CONST_BITS+2); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */ + CONST_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */ + CONST_BITS+2); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+2); + tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */ + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */ + CONST_BITS+2); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */ + MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */ + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on an 11x11 sample block. + */ + +GLOBAL(void) +jpeg_fdct_11x11 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 z1, z2, z3; + DCTELEM workspace[8*3]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* we scale the results further by 2 as part of output adaption */ + /* scaling for different DCT size. */ + /* cK represents sqrt(2) * cos(K*pi/22). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[10]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[9]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[8]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[7]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[6]); + tmp5 = GETJSAMPLE(elemptr[5]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[10]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[9]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[8]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[7]); + tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[6]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - 11 * CENTERJSAMPLE) << 1); + tmp5 += tmp5; + tmp0 -= tmp5; + tmp1 -= tmp5; + tmp2 -= tmp5; + tmp3 -= tmp5; + tmp4 -= tmp5; + z1 = MULTIPLY(tmp0 + tmp3, FIX(1.356927976)) + /* c2 */ + MULTIPLY(tmp2 + tmp4, FIX(0.201263574)); /* c10 */ + z2 = MULTIPLY(tmp1 - tmp3, FIX(0.926112931)); /* c6 */ + z3 = MULTIPLY(tmp0 - tmp1, FIX(1.189712156)); /* c4 */ + dataptr[2] = (DCTELEM) + DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.018300590)) /* c2+c8-c6 */ + - MULTIPLY(tmp4, FIX(1.390975730)), /* c4+c10 */ + CONST_BITS-1); + dataptr[4] = (DCTELEM) + DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.062335650)) /* c4-c6-c10 */ + - MULTIPLY(tmp2, FIX(1.356927976)) /* c2 */ + + MULTIPLY(tmp4, FIX(0.587485545)), /* c8 */ + CONST_BITS-1); + dataptr[6] = (DCTELEM) + DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.620527200)) /* c2+c4-c6 */ + - MULTIPLY(tmp2, FIX(0.788749120)), /* c8+c10 */ + CONST_BITS-1); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.286413905)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.068791298)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.764581576)); /* c7 */ + tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.719967871)) /* c7+c5+c3-c1 */ + + MULTIPLY(tmp14, FIX(0.398430003)); /* c9 */ + tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.764581576)); /* -c7 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.399818907)); /* -c1 */ + tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.276416582)) /* c9+c7+c1-c3 */ + - MULTIPLY(tmp14, FIX(1.068791298)); /* c5 */ + tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.398430003)); /* c9 */ + tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(1.989053629)) /* c9+c5+c3-c7 */ + + MULTIPLY(tmp14, FIX(1.399818907)); /* c1 */ + tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.305598626)) /* c1+c5-c9-c7 */ + - MULTIPLY(tmp14, FIX(1.286413905)); /* c3 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-1); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-1); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-1); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-1); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 11) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/11)**2 = 64/121, which we partially + * fold into the constant multipliers and final/initial shifting: + * cK now represents sqrt(2) * cos(K*pi/22) * 128/121. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*2]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*1]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*0]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*7]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*6]; + tmp5 = dataptr[DCTSIZE*5]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*2]; + tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*1]; + tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*0]; + tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*7]; + tmp14 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*6]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5, + FIX(1.057851240)), /* 128/121 */ + CONST_BITS+2); + tmp5 += tmp5; + tmp0 -= tmp5; + tmp1 -= tmp5; + tmp2 -= tmp5; + tmp3 -= tmp5; + tmp4 -= tmp5; + z1 = MULTIPLY(tmp0 + tmp3, FIX(1.435427942)) + /* c2 */ + MULTIPLY(tmp2 + tmp4, FIX(0.212906922)); /* c10 */ + z2 = MULTIPLY(tmp1 - tmp3, FIX(0.979689713)); /* c6 */ + z3 = MULTIPLY(tmp0 - tmp1, FIX(1.258538479)); /* c4 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.077210542)) /* c2+c8-c6 */ + - MULTIPLY(tmp4, FIX(1.471445400)), /* c4+c10 */ + CONST_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.065941844)) /* c4-c6-c10 */ + - MULTIPLY(tmp2, FIX(1.435427942)) /* c2 */ + + MULTIPLY(tmp4, FIX(0.621472312)), /* c8 */ + CONST_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.714276708)) /* c2+c4-c6 */ + - MULTIPLY(tmp2, FIX(0.834379234)), /* c8+c10 */ + CONST_BITS+2); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.360834544)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.130622199)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.808813568)); /* c7 */ + tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.819470145)) /* c7+c5+c3-c1 */ + + MULTIPLY(tmp14, FIX(0.421479672)); /* c9 */ + tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.808813568)); /* -c7 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.480800167)); /* -c1 */ + tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.350258864)) /* c9+c7+c1-c3 */ + - MULTIPLY(tmp14, FIX(1.130622199)); /* c5 */ + tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.421479672)); /* c9 */ + tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(2.104122847)) /* c9+c5+c3-c7 */ + + MULTIPLY(tmp14, FIX(1.480800167)); /* c1 */ + tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.381129125)) /* c1+c5-c9-c7 */ + - MULTIPLY(tmp14, FIX(1.360834544)); /* c3 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 12x12 sample block. + */ + +GLOBAL(void) +jpeg_fdct_12x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + DCTELEM workspace[8*4]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT. */ + /* cK represents sqrt(2) * cos(K*pi/24). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]); + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) (tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE); + dataptr[6] = (DCTELEM) (tmp13 - tmp14 - tmp15); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */ + CONST_BITS); + dataptr[2] = (DCTELEM) + DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */ + CONST_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 12) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/12)**2 = 4/9, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/24) * 8/9. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6]; + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */ + CONST_BITS+1); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */ + MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */ + CONST_BITS+1); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 13x13 sample block. + */ + +GLOBAL(void) +jpeg_fdct_13x13 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 z1, z2; + DCTELEM workspace[8*5]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT. */ + /* cK represents sqrt(2) * cos(K*pi/26). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[12]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[11]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[10]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[9]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[8]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[7]); + tmp6 = GETJSAMPLE(elemptr[6]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[12]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[11]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[10]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[9]); + tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[8]); + tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[7]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + (tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 - 13 * CENTERJSAMPLE); + tmp6 += tmp6; + tmp0 -= tmp6; + tmp1 -= tmp6; + tmp2 -= tmp6; + tmp3 -= tmp6; + tmp4 -= tmp6; + tmp5 -= tmp6; + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.373119086)) + /* c2 */ + MULTIPLY(tmp1, FIX(1.058554052)) + /* c6 */ + MULTIPLY(tmp2, FIX(0.501487041)) - /* c10 */ + MULTIPLY(tmp3, FIX(0.170464608)) - /* c12 */ + MULTIPLY(tmp4, FIX(0.803364869)) - /* c8 */ + MULTIPLY(tmp5, FIX(1.252223920)), /* c4 */ + CONST_BITS); + z1 = MULTIPLY(tmp0 - tmp2, FIX(1.155388986)) - /* (c4+c6)/2 */ + MULTIPLY(tmp3 - tmp4, FIX(0.435816023)) - /* (c2-c10)/2 */ + MULTIPLY(tmp1 - tmp5, FIX(0.316450131)); /* (c8-c12)/2 */ + z2 = MULTIPLY(tmp0 + tmp2, FIX(0.096834934)) - /* (c4-c6)/2 */ + MULTIPLY(tmp3 + tmp4, FIX(0.937303064)) + /* (c2+c10)/2 */ + MULTIPLY(tmp1 + tmp5, FIX(0.486914739)); /* (c8+c12)/2 */ + + dataptr[4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.322312651)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.163874945)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.937797057)) + /* c7 */ + MULTIPLY(tmp14 + tmp15, FIX(0.338443458)); /* c11 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(tmp10, FIX(2.020082300)) + /* c3+c5+c7-c1 */ + MULTIPLY(tmp14, FIX(0.318774355)); /* c9-c11 */ + tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.937797057)) - /* c7 */ + MULTIPLY(tmp11 + tmp12, FIX(0.338443458)); /* c11 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.163874945)); /* -c5 */ + tmp1 += tmp4 + tmp5 + + MULTIPLY(tmp11, FIX(0.837223564)) - /* c5+c9+c11-c3 */ + MULTIPLY(tmp14, FIX(2.341699410)); /* c1+c7 */ + tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.657217813)); /* -c9 */ + tmp2 += tmp4 + tmp6 - + MULTIPLY(tmp12, FIX(1.572116027)) + /* c1+c5-c9-c11 */ + MULTIPLY(tmp15, FIX(2.260109708)); /* c3+c7 */ + tmp3 += tmp5 + tmp6 + + MULTIPLY(tmp13, FIX(2.205608352)) - /* c3+c5+c9-c7 */ + MULTIPLY(tmp15, FIX(1.742345811)); /* c1+c11 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 13) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/13)**2 = 64/169, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/26) * 128/169. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*3]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*2]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*1]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*0]; + tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*7]; + tmp6 = dataptr[DCTSIZE*6]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*4]; + tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*3]; + tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*2]; + tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*1]; + tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*0]; + tmp15 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*7]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6, + FIX(0.757396450)), /* 128/169 */ + CONST_BITS+1); + tmp6 += tmp6; + tmp0 -= tmp6; + tmp1 -= tmp6; + tmp2 -= tmp6; + tmp3 -= tmp6; + tmp4 -= tmp6; + tmp5 -= tmp6; + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.039995521)) + /* c2 */ + MULTIPLY(tmp1, FIX(0.801745081)) + /* c6 */ + MULTIPLY(tmp2, FIX(0.379824504)) - /* c10 */ + MULTIPLY(tmp3, FIX(0.129109289)) - /* c12 */ + MULTIPLY(tmp4, FIX(0.608465700)) - /* c8 */ + MULTIPLY(tmp5, FIX(0.948429952)), /* c4 */ + CONST_BITS+1); + z1 = MULTIPLY(tmp0 - tmp2, FIX(0.875087516)) - /* (c4+c6)/2 */ + MULTIPLY(tmp3 - tmp4, FIX(0.330085509)) - /* (c2-c10)/2 */ + MULTIPLY(tmp1 - tmp5, FIX(0.239678205)); /* (c8-c12)/2 */ + z2 = MULTIPLY(tmp0 + tmp2, FIX(0.073342435)) - /* (c4-c6)/2 */ + MULTIPLY(tmp3 + tmp4, FIX(0.709910013)) + /* (c2+c10)/2 */ + MULTIPLY(tmp1 + tmp5, FIX(0.368787494)); /* (c8+c12)/2 */ + + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS+1); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.001514908)); /* c3 */ + tmp2 = MULTIPLY(tmp10 + tmp12, FIX(0.881514751)); /* c5 */ + tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.710284161)) + /* c7 */ + MULTIPLY(tmp14 + tmp15, FIX(0.256335874)); /* c11 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(tmp10, FIX(1.530003162)) + /* c3+c5+c7-c1 */ + MULTIPLY(tmp14, FIX(0.241438564)); /* c9-c11 */ + tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.710284161)) - /* c7 */ + MULTIPLY(tmp11 + tmp12, FIX(0.256335874)); /* c11 */ + tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(0.881514751)); /* -c5 */ + tmp1 += tmp4 + tmp5 + + MULTIPLY(tmp11, FIX(0.634110155)) - /* c5+c9+c11-c3 */ + MULTIPLY(tmp14, FIX(1.773594819)); /* c1+c7 */ + tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.497774438)); /* -c9 */ + tmp2 += tmp4 + tmp6 - + MULTIPLY(tmp12, FIX(1.190715098)) + /* c1+c5-c9-c11 */ + MULTIPLY(tmp15, FIX(1.711799069)); /* c3+c7 */ + tmp3 += tmp5 + tmp6 + + MULTIPLY(tmp13, FIX(1.670519935)) - /* c3+c5+c9-c7 */ + MULTIPLY(tmp15, FIX(1.319646532)); /* c1+c11 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 14x14 sample block. + */ + +GLOBAL(void) +jpeg_fdct_14x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + DCTELEM workspace[8*6]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT. */ + /* cK represents sqrt(2) * cos(K*pi/28). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]); + tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]); + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + (tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE); + tmp13 += tmp13; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */ + CONST_BITS); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */ + CONST_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */ + CONST_BITS); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[7] = (DCTELEM) (tmp0 - tmp10 + tmp3 - tmp11 - tmp6); + tmp3 <<= CONST_BITS; + tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */ + dataptr[5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */ + CONST_BITS); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */ + dataptr[3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */ + CONST_BITS); + dataptr[1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + tmp6 - + MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */ + CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 14) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/14)**2 = 16/49, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/28) * 32/49. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3]; + tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7]; + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+1); + tmp13 += tmp13; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */ + CONST_BITS+1); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */ + CONST_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */ + CONST_BITS+1); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[DCTSIZE*7] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+1); + tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */ + tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */ + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */ + CONST_BITS+1); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */ + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */ + CONST_BITS+1); + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */ + - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */ + CONST_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 15x15 sample block. + */ + +GLOBAL(void) +jpeg_fdct_15x15 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 z1, z2, z3; + DCTELEM workspace[8*7]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT. */ + /* cK represents sqrt(2) * cos(K*pi/30). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[14]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[13]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[12]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[11]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[10]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[9]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[8]); + tmp7 = GETJSAMPLE(elemptr[7]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[14]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[13]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[12]); + tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[11]); + tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[10]); + tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[9]); + tmp16 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[8]); + + z1 = tmp0 + tmp4 + tmp5; + z2 = tmp1 + tmp3 + tmp6; + z3 = tmp2 + tmp7; + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) (z1 + z2 + z3 - 15 * CENTERJSAMPLE); + z3 += z3; + dataptr[6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z3, FIX(1.144122806)) - /* c6 */ + MULTIPLY(z2 - z3, FIX(0.437016024)), /* c12 */ + CONST_BITS); + tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7; + z1 = MULTIPLY(tmp3 - tmp2, FIX(1.531135173)) - /* c2+c14 */ + MULTIPLY(tmp6 - tmp2, FIX(2.238241955)); /* c4+c8 */ + z2 = MULTIPLY(tmp5 - tmp2, FIX(0.798468008)) - /* c8-c14 */ + MULTIPLY(tmp0 - tmp2, FIX(0.091361227)); /* c2-c4 */ + z3 = MULTIPLY(tmp0 - tmp3, FIX(1.383309603)) + /* c2 */ + MULTIPLY(tmp6 - tmp5, FIX(0.946293579)) + /* c8 */ + MULTIPLY(tmp1 - tmp4, FIX(0.790569415)); /* (c6+c12)/2 */ + + dataptr[2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS); + dataptr[4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS); + + /* Odd part */ + + tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16, + FIX(1.224744871)); /* c5 */ + tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.344997024)) + /* c3 */ + MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.831253876)); /* c9 */ + tmp12 = MULTIPLY(tmp12, FIX(1.224744871)); /* c5 */ + tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.406466353)) + /* c1 */ + MULTIPLY(tmp11 + tmp14, FIX(1.344997024)) + /* c3 */ + MULTIPLY(tmp13 + tmp15, FIX(0.575212477)); /* c11 */ + tmp0 = MULTIPLY(tmp13, FIX(0.475753014)) - /* c7-c11 */ + MULTIPLY(tmp14, FIX(0.513743148)) + /* c3-c9 */ + MULTIPLY(tmp16, FIX(1.700497885)) + tmp4 + tmp12; /* c1+c13 */ + tmp3 = MULTIPLY(tmp10, - FIX(0.355500862)) - /* -(c1-c7) */ + MULTIPLY(tmp11, FIX(2.176250899)) - /* c3+c9 */ + MULTIPLY(tmp15, FIX(0.869244010)) + tmp4 - tmp12; /* c11+c13 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 15) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/15)**2 = 64/225, which we partially + * fold into the constant multipliers and final shifting: + * cK now represents sqrt(2) * cos(K*pi/30) * 256/225. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*6]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*5]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*4]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*3]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*2]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*1]; + tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*0]; + tmp7 = dataptr[DCTSIZE*7]; + + tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*6]; + tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*5]; + tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*4]; + tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*3]; + tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*2]; + tmp15 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*1]; + tmp16 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*0]; + + z1 = tmp0 + tmp4 + tmp5; + z2 = tmp1 + tmp3 + tmp6; + z3 = tmp2 + tmp7; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + z2 + z3, FIX(1.137777778)), /* 256/225 */ + CONST_BITS+2); + z3 += z3; + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(z1 - z3, FIX(1.301757503)) - /* c6 */ + MULTIPLY(z2 - z3, FIX(0.497227121)), /* c12 */ + CONST_BITS+2); + tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7; + z1 = MULTIPLY(tmp3 - tmp2, FIX(1.742091575)) - /* c2+c14 */ + MULTIPLY(tmp6 - tmp2, FIX(2.546621957)); /* c4+c8 */ + z2 = MULTIPLY(tmp5 - tmp2, FIX(0.908479156)) - /* c8-c14 */ + MULTIPLY(tmp0 - tmp2, FIX(0.103948774)); /* c2-c4 */ + z3 = MULTIPLY(tmp0 - tmp3, FIX(1.573898926)) + /* c2 */ + MULTIPLY(tmp6 - tmp5, FIX(1.076671805)) + /* c8 */ + MULTIPLY(tmp1 - tmp4, FIX(0.899492312)); /* (c6+c12)/2 */ + + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS+2); + + /* Odd part */ + + tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16, + FIX(1.393487498)); /* c5 */ + tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.530307725)) + /* c3 */ + MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.945782187)); /* c9 */ + tmp12 = MULTIPLY(tmp12, FIX(1.393487498)); /* c5 */ + tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.600246161)) + /* c1 */ + MULTIPLY(tmp11 + tmp14, FIX(1.530307725)) + /* c3 */ + MULTIPLY(tmp13 + tmp15, FIX(0.654463974)); /* c11 */ + tmp0 = MULTIPLY(tmp13, FIX(0.541301207)) - /* c7-c11 */ + MULTIPLY(tmp14, FIX(0.584525538)) + /* c3-c9 */ + MULTIPLY(tmp16, FIX(1.934788705)) + tmp4 + tmp12; /* c1+c13 */ + tmp3 = MULTIPLY(tmp10, - FIX(0.404480980)) - /* -(c1-c7) */ + MULTIPLY(tmp11, FIX(2.476089912)) - /* c3+c9 */ + MULTIPLY(tmp15, FIX(0.989006518)) + tmp4 - tmp12; /* c11+c13 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 16x16 sample block. + */ + +GLOBAL(void) +jpeg_fdct_16x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + DCTELEM workspace[DCTSIZE2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* cK represents sqrt(2) * cos(K*pi/32). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]); + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS-PASS1_BITS); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == DCTSIZE * 2) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/16)**2 = 1/2**2. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0]; + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+2); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS+PASS1_BITS+2); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+10 */ + CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS+PASS1_BITS+2); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+2); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+2); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 16x8 sample block. + * + * 16-point FDCT in pass 1 (rows), 8-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_16x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32). */ + + dataptr = data; + ctr = 0; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]); + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]); + tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS-PASS1_BITS); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by 8/16 = 1/2. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS+1); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), + CONST_BITS+PASS1_BITS+1); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp10 = tmp0 + tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */ + tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + + tmp12 += z1; + tmp13 += z1; + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0 + tmp10 + tmp12, + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1 + tmp11 + tmp13, + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2 + tmp11 + tmp12, + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3 + tmp10 + tmp13, + CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 14x7 sample block. + * + * 14-point FDCT in pass 1 (rows), 7-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_14x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 z1, z2, z3; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero bottom row of output coefficient block. */ + MEMZERO(&data[DCTSIZE*7], SIZEOF(DCTELEM) * DCTSIZE); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28). */ + + dataptr = data; + for (ctr = 0; ctr < 7; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]); + tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]); + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]); + tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE) << PASS1_BITS); + tmp13 += tmp13; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */ + CONST_BITS-PASS1_BITS); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */ + + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[7] = (DCTELEM) ((tmp0 - tmp10 + tmp3 - tmp11 - tmp6) << PASS1_BITS); + tmp3 <<= CONST_BITS; + tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */ + dataptr[5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */ + CONST_BITS-PASS1_BITS); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */ + dataptr[3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */ + CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + tmp6 - + MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */ + CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/14)*(8/7) = 32/49, which we + * partially fold into the constant multipliers and final shifting: + * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14) * 64/49. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4]; + tmp3 = dataptr[DCTSIZE*3]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5]; + tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4]; + + z1 = tmp0 + tmp2; + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */ + CONST_BITS+PASS1_BITS+1); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS+1); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */ + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS+1); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 12x6 sample block. + * + * 12-point FDCT in pass 1 (rows), 6-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_12x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero 2 bottom rows of output coefficient block. */ + MEMZERO(&data[DCTSIZE*6], SIZEOF(DCTELEM) * DCTSIZE * 2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24). */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]); + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]); + tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[6] = (DCTELEM) ((tmp13 - tmp14 - tmp15) << PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */ + CONST_BITS-PASS1_BITS); + dataptr[2] = (DCTELEM) + DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/12)*(8/6) = 8/9, which we + * partially fold into the constant multipliers and final shifting: + * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5]; + tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3]; + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */ + CONST_BITS+PASS1_BITS+1); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 10x5 sample block. + * + * 10-point FDCT in pass 1 (rows), 5-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_10x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero 3 bottom rows of output coefficient block. */ + MEMZERO(&data[DCTSIZE*5], SIZEOF(DCTELEM) * DCTSIZE * 3); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20). */ + + dataptr = data; + for (ctr = 0; ctr < 5; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]); + tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]); + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]); + tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << PASS1_BITS); + tmp12 += tmp12; + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */ + CONST_BITS-PASS1_BITS); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */ + dataptr[2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << PASS1_BITS); + tmp2 <<= CONST_BITS; + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */ + CONST_BITS-PASS1_BITS); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */ + (tmp11 << (CONST_BITS - 1)) - tmp2; + dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/10)*(8/5) = 32/25, which we + * fold into the constant multipliers: + * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10) * 32/25. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3]; + tmp2 = dataptr[DCTSIZE*2]; + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */ + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on an 8x4 sample block. + * + * 8-point FDCT in pass 1 (rows), 4-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_8x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Zero 4 bottom rows of output coefficient block. */ + MEMZERO(&data[DCTSIZE*4], SIZEOF(DCTELEM) * DCTSIZE * 4); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We must also scale the output by 8/4 = 2, which we add here. */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << (PASS1_BITS+1)); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-2); + dataptr[2] = (DCTELEM) RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), + CONST_BITS-PASS1_BITS-1); + dataptr[6] = (DCTELEM) RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), + CONST_BITS-PASS1_BITS-1); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp10 = tmp0 + tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-2); + + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */ + tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + + tmp12 += z1; + tmp13 += z1; + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS-1); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS-1); + dataptr[5] = (DCTELEM) + RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS-1); + dataptr[7] = (DCTELEM) + RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * 4-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1)); + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS+PASS1_BITS-1); + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 6x3 sample block. + * + * 6-point FDCT in pass 1 (rows), 3-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_6x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11, tmp12; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We scale the results further by 2 as part of output adaption */ + /* scaling for different DCT size. */ + /* 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]); + tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */ + CONST_BITS-PASS1_BITS-1); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */ + CONST_BITS-PASS1_BITS-1); + + /* Odd part */ + + tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */ + CONST_BITS-PASS1_BITS-1); + + dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << (PASS1_BITS+1))); + dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << (PASS1_BITS+1)); + dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << (PASS1_BITS+1))); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2]; + tmp1 = dataptr[DCTSIZE*1]; + + tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 4x2 sample block. + * + * 4-point FDCT in pass 1 (rows), 2-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_4x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We must also scale the output by (8/4)*(8/2) = 2**3, which we add here. */ + /* 4-point FDCT kernel, */ + /* cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. */ + + dataptr = data; + for (ctr = 0; ctr < 2; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+3)); + dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+3)); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-4); + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS-3); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS-3); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = dataptr[DCTSIZE*0] + (ONE << (PASS1_BITS-1)); + tmp1 = dataptr[DCTSIZE*1]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS); + + /* Odd part */ + + dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 2x1 sample block. + * + * 2-point FDCT in pass 1 (rows), 1-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_2x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + JSAMPROW elemptr; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + elemptr = sample_data[0] + start_col; + + tmp0 = GETJSAMPLE(elemptr[0]); + tmp1 = GETJSAMPLE(elemptr[1]); + + /* We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/2)*(8/1) = 2**5. + */ + + /* Even part */ + /* Apply unsigned->signed conversion */ + data[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5); + + /* Odd part */ + data[1] = (DCTELEM) ((tmp0 - tmp1) << 5); +} + + +/* + * Perform the forward DCT on an 8x16 sample block. + * + * 8-point FDCT in pass 1 (rows), 16-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_8x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + INT32 z1; + DCTELEM workspace[DCTSIZE2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]); + + tmp10 = tmp0 + tmp3; + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]); + tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp10 = tmp0 + tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */ + tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + + tmp12 += z1; + tmp13 += z1; + + dataptr[1] = (DCTELEM) DESCALE(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS); + dataptr[7] = (DCTELEM) DESCALE(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == DCTSIZE * 2) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by 8/16 = 1/2. + * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + + dataptr = data; + wsptr = workspace; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0]; + + tmp10 = tmp0 + tmp7; + tmp14 = tmp0 - tmp7; + tmp11 = tmp1 + tmp6; + tmp15 = tmp1 - tmp6; + tmp12 = tmp2 + tmp5; + tmp16 = tmp2 - tmp5; + tmp13 = tmp3 + tmp4; + tmp17 = tmp3 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2]; + tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1]; + tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+1); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */ + MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */ + CONST_BITS+PASS1_BITS+1); + + tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */ + MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */ + + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */ + CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */ + - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */ + CONST_BITS+PASS1_BITS+1); + + /* Odd part */ + + tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */ + MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */ + MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */ + MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */ + tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */ + MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */ + tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */ + MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */ + tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */ + MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */ + MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */ + tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */ + - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */ + tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */ + + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */ + tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */ + + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+1); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+1); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 7x14 sample block. + * + * 7-point FDCT in pass 1 (rows), 14-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_7x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 z1, z2, z3; + DCTELEM workspace[8*6]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]); + tmp3 = GETJSAMPLE(elemptr[3]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]); + tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]); + + z1 = tmp0 + tmp2; + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS); + tmp3 += tmp3; + z1 -= tmp3; + z1 -= tmp3; + z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */ + z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */ + dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS); + z1 -= z2; + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */ + dataptr[4] = (DCTELEM) + DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */ + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */ + tmp0 += tmp3; + tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */ + + dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 14) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/7)*(8/14) = 32/49, which we + * fold into the constant multipliers: + * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28) * 32/49. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3]; + tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7]; + + tmp10 = tmp0 + tmp6; + tmp14 = tmp0 - tmp6; + tmp11 = tmp1 + tmp5; + tmp15 = tmp1 - tmp5; + tmp12 = tmp2 + tmp4; + tmp16 = tmp2 - tmp4; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2]; + tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1]; + tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0]; + tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+PASS1_BITS); + tmp13 += tmp13; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */ + MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */ + MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */ + CONST_BITS+PASS1_BITS); + + tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */ + + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */ + + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */ + - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp1 + tmp2; + tmp11 = tmp5 - tmp4; + dataptr[DCTSIZE*7] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6, + FIX(0.653061224)), /* 32/49 */ + CONST_BITS+PASS1_BITS); + tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */ + tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */ + tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */ + tmp10 += tmp11 - tmp3; + tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */ + MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */ + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */ + + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */ + CONST_BITS+PASS1_BITS); + tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */ + MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */ + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */ + - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp11 + tmp12 + tmp3 + - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */ + - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 6x12 sample block. + * + * 6-point FDCT in pass 1 (rows), 12-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_6x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + DCTELEM workspace[8*4]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]); + tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]); + tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */ + CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */ + CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */ + CONST_BITS-PASS1_BITS); + + dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS)); + dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS); + dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS)); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 12) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)*(8/12) = 8/9, which we + * fold into the constant multipliers: + * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24) * 8/9. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6]; + + tmp10 = tmp0 + tmp5; + tmp13 = tmp0 - tmp5; + tmp11 = tmp1 + tmp4; + tmp14 = tmp1 - tmp4; + tmp12 = tmp2 + tmp3; + tmp15 = tmp2 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2]; + tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1]; + tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7]; + tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */ + MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */ + tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */ + tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */ + tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */ + tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */ + tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */ + + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */ + tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */ + tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */ + + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */ + tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */ + - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */ + tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */ + - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */ + + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 5x10 sample block. + * + * 5-point FDCT in pass 1 (rows), 10-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_5x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + DCTELEM workspace[8*2]; + DCTELEM *dataptr; + DCTELEM *wsptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10). */ + + dataptr = data; + ctr = 0; + for (;;) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]); + tmp2 = GETJSAMPLE(elemptr[2]); + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + + tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]); + tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << PASS1_BITS); + tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */ + tmp10 -= tmp2 << 2; + tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */ + dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS); + dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */ + + dataptr[1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */ + CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */ + CONST_BITS-PASS1_BITS); + + ctr++; + + if (ctr != DCTSIZE) { + if (ctr == 10) + break; /* Done. */ + dataptr += DCTSIZE; /* advance pointer to next row */ + } else + dataptr = workspace; /* switch pointer to extended workspace */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/5)*(8/10) = 32/25, which we + * fold into the constant multipliers: + * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20) * 32/25. + */ + + dataptr = data; + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0]; + tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5]; + + tmp10 = tmp0 + tmp4; + tmp13 = tmp0 - tmp4; + tmp11 = tmp1 + tmp3; + tmp14 = tmp1 - tmp3; + + tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1]; + tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6]; + tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp12 += tmp12; + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */ + MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */ + CONST_BITS+PASS1_BITS); + tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */ + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = tmp0 + tmp4; + tmp11 = tmp1 - tmp3; + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */ + CONST_BITS+PASS1_BITS); + tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */ + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */ + MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */ + MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */ + MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */ + CONST_BITS+PASS1_BITS); + tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */ + MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */ + tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */ + MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */ + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + wsptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 4x8 sample block. + * + * 4-point FDCT in pass 1 (rows), 8-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_4x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We must also scale the output by 8/4 = 2, which we add here. */ + /* 4-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). */ + + dataptr = data; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]); + tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]); + + tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]); + tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+1)); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-2); + + dataptr[1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS-1); + dataptr[3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + /* Add fudge factor here for final descale. */ + tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1)); + tmp12 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp13 = tmp1 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + dataptr[DCTSIZE*2] = (DCTELEM) + RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) + RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + * i0..i3 in the paper are tmp0..tmp3 here. + */ + + tmp10 = tmp0 + tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp0 + tmp2; + tmp13 = tmp1 + tmp3; + z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS+PASS1_BITS-1); + + tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */ + tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */ + tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */ + tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */ + tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */ + tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */ + tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */ + tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */ + + tmp12 += z1; + tmp13 += z1; + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) + RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*7] = (DCTELEM) + RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 3x6 sample block. + * + * 3-point FDCT in pass 1 (rows), 6-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_3x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1, tmp2; + INT32 tmp10, tmp11, tmp12; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + /* We scale the results further by 2 as part of output adaption */ + /* scaling for different DCT size. */ + /* 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6). */ + + dataptr = data; + for (ctr = 0; ctr < 6; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]); + tmp1 = GETJSAMPLE(elemptr[1]); + + tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) + ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+1)); + dataptr[2] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */ + CONST_BITS-PASS1_BITS-1); + + /* Odd part */ + + dataptr[1] = (DCTELEM) + DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */ + CONST_BITS-PASS1_BITS-1); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially + * fold into the constant multipliers (other part was done in pass 1): + * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9. + */ + + dataptr = data; + for (ctr = 0; ctr < 3; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5]; + tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3]; + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5]; + tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4]; + tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3]; + + dataptr[DCTSIZE*0] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*2] = (DCTELEM) + DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) + DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */ + CONST_BITS+PASS1_BITS); + + /* Odd part */ + + tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */ + + dataptr[DCTSIZE*1] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) + DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */ + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 2x4 sample block. + * + * 2-point FDCT in pass 1 (rows), 4-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_2x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + INT32 tmp10, tmp11; + DCTELEM *dataptr; + JSAMPROW elemptr; + int ctr; + SHIFT_TEMPS + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT. */ + /* We must also scale the output by (8/2)*(8/4) = 2**3, which we add here. */ + + dataptr = data; + for (ctr = 0; ctr < 4; ctr++) { + elemptr = sample_data[ctr] + start_col; + + /* Even part */ + + tmp0 = GETJSAMPLE(elemptr[0]); + tmp1 = GETJSAMPLE(elemptr[1]); + + /* Apply unsigned->signed conversion */ + dataptr[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 3); + + /* Odd part */ + + dataptr[1] = (DCTELEM) ((tmp0 - tmp1) << 3); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We leave the results scaled up by an overall factor of 8. + * 4-point FDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. + */ + + dataptr = data; + for (ctr = 0; ctr < 2; ctr++) { + /* Even part */ + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2]; + + tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3]; + tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2]; + + dataptr[DCTSIZE*0] = (DCTELEM) (tmp0 + tmp1); + dataptr[DCTSIZE*2] = (DCTELEM) (tmp0 - tmp1); + + /* Odd part */ + + tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-1); + + dataptr[DCTSIZE*1] = (DCTELEM) + RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */ + CONST_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) + RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */ + CONST_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + + +/* + * Perform the forward DCT on a 1x2 sample block. + * + * 1-point FDCT in pass 1 (rows), 2-point in pass 2 (columns). + */ + +GLOBAL(void) +jpeg_fdct_1x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col) +{ + INT32 tmp0, tmp1; + + /* Pre-zero output coefficient block. */ + MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2); + + tmp0 = GETJSAMPLE(sample_data[0][start_col]); + tmp1 = GETJSAMPLE(sample_data[1][start_col]); + + /* We leave the results scaled up by an overall factor of 8. + * We must also scale the output by (8/1)*(8/2) = 2**5. + */ + + /* Even part */ + /* Apply unsigned->signed conversion */ + data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5); + + /* Odd part */ + data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp1) << 5); +} + +#endif /* DCT_SCALING_SUPPORTED */ +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jidctflt.c b/library/src/main/cpp/jpeg/src/jidctflt.c new file mode 100644 index 00000000..23ae9d33 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jidctflt.c @@ -0,0 +1,235 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * Modified 2010 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */ + tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 - tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*3] = tmp3 + tmp4; + wsptr[DCTSIZE*4] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + /* Apply signed->unsigned and prepare float->int conversion */ + z5 = wsptr[0] + ((FAST_FLOAT) CENTERJSAMPLE + (FAST_FLOAT) 0.5); + tmp10 = z5 + wsptr[4]; + tmp11 = z5 - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */ + tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 - tmp5; + + /* Final output stage: float->int conversion and range-limit */ + + outptr[0] = range_limit[((int) (tmp0 + tmp7)) & RANGE_MASK]; + outptr[7] = range_limit[((int) (tmp0 - tmp7)) & RANGE_MASK]; + outptr[1] = range_limit[((int) (tmp1 + tmp6)) & RANGE_MASK]; + outptr[6] = range_limit[((int) (tmp1 - tmp6)) & RANGE_MASK]; + outptr[2] = range_limit[((int) (tmp2 + tmp5)) & RANGE_MASK]; + outptr[5] = range_limit[((int) (tmp2 - tmp5)) & RANGE_MASK]; + outptr[3] = range_limit[((int) (tmp3 + tmp4)) & RANGE_MASK]; + outptr[4] = range_limit[((int) (tmp3 - tmp4)) & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jidctfst.c b/library/src/main/cpp/jpeg/src/jidctfst.c new file mode 100644 index 00000000..dba4216f --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jidctfst.c @@ -0,0 +1,368 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* Like DESCALE, but applies to a DCTELEM and produces an int. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +#ifdef USE_ACCURATE_ROUNDING +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) +#else +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IDESCALE */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); + tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); + + tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) + - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jidctint.c b/library/src/main/cpp/jpeg/src/jidctint.c new file mode 100644 index 00000000..dcdf7ce4 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jidctint.c @@ -0,0 +1,5137 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modification developed 2002-2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + * + * We also provide IDCT routines with various output sample block sizes for + * direct resolution reduction or enlargement and for direct resolving the + * common 2x1 and 1x2 subsampling cases without additional resampling: NxN + * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block. + * + * For N<8 we simply take the corresponding low-frequency coefficients of + * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block + * to yield the downscaled outputs. + * This can be seen as direct low-pass downsampling from the DCT domain + * point of view rather than the usual spatial domain point of view, + * yielding significant computational savings and results at least + * as good as common bilinear (averaging) spatial downsampling. + * + * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as + * lower frequencies and higher frequencies assumed to be zero. + * It turns out that the computational effort is similar to the 8x8 IDCT + * regarding the output size. + * Furthermore, the scaling and descaling is the same for all IDCT sizes. + * + * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases + * since there would be too many additional constants to pre-calculate. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 <<= CONST_BITS; + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z2 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = z2 + z3; + tmp1 = z2 - z3; + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); + + /* Add fudge factor here for final descale. */ + z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 = (INT32) wsptr[4]; + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 7x7 output block. + * + * Optimized algorithm with 12 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/14). + */ + +GLOBAL(void) +jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[7*7]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp13 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp13 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp0 = z1 + z3; + z2 -= tmp0; + tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */ + tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + + tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp0 += z2; + tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 7 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp13 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp13 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp0 = z1 + z3; + z2 -= tmp0; + tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */ + tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + + tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp0 = tmp1 - tmp2; + tmp1 += tmp2; + tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp1 += tmp2; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp0 += z2; + tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 7; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 6x6 output block. + * + * Optimized algorithm with 3 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/12). + */ + +GLOBAL(void) +jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[6*6]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS); + tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*1] = (int) (tmp11 + tmp1); + wsptr[6*4] = (int) (tmp11 - tmp1); + wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 6 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[4]; + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = tmp0 - tmp10 - tmp10; + tmp10 = (INT32) wsptr[2]; + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << CONST_BITS; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 6; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 5x5 output block. + * + * Optimized algorithm with 5 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/10). + */ + +GLOBAL(void) +jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[5*5]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp12 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 5 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp12 <<= CONST_BITS; + tmp0 = (INT32) wsptr[2]; + tmp1 = (INT32) wsptr[4]; + z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 5; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + * + * Optimized algorithm with 3 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[4*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp10 = (tmp0 + tmp2) << PASS1_BITS; + tmp12 = (tmp0 - tmp2) << PASS1_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Final output stage */ + + wsptr[4*0] = (int) (tmp10 + tmp0); + wsptr[4*3] = (int) (tmp10 - tmp0); + wsptr[4*1] = (int) (tmp12 + tmp2); + wsptr[4*2] = (int) (tmp12 - tmp2); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp2 = (INT32) wsptr[2]; + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 4; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 3x3 output block. + * + * Optimized algorithm with 2 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/6). + */ + +GLOBAL(void) +jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[3*3]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 3 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[2]; + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = (INT32) wsptr[1]; + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 3; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + * + * Multiplication-less algorithm. + */ + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* Pass 1: process columns from input. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Column 0 */ + tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]); + /* Add fudge factor here for final descale. */ + tmp4 += ONE << 2; + + tmp0 = tmp4 + tmp5; + tmp2 = tmp4 - tmp5; + + /* Column 1 */ + tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]); + tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]); + + tmp1 = tmp4 + tmp5; + tmp3 = tmp4 - tmp5; + + /* Pass 2: process 2 rows, store into output array. */ + + /* Row 0 */ + outptr = output_buf[0] + output_col; + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK]; + + /* Row 1 */ + outptr = output_buf[1] + output_col; + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK]; +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + * + * We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + int dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* 1x1 is trivial: just take the DC coefficient divided by 8. */ + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + dcval = (int) DESCALE((INT32) dcval, 3); + + output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 9x9 output block. + * + * Optimized algorithm with 10 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/18). + */ + +GLOBAL(void) +jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*9]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */ + tmp1 = tmp0 + tmp3; + tmp2 = tmp0 - tmp3 - tmp3; + + tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */ + tmp11 = tmp2 + tmp0; + tmp14 = tmp2 - tmp0 - tmp0; + + tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */ + tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */ + tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */ + + tmp10 = tmp1 + tmp0 - tmp3; + tmp12 = tmp1 - tmp0 + tmp2; + tmp13 = tmp1 - tmp2 + tmp3; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */ + + tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */ + tmp0 = tmp2 + tmp3 - z2; + tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */ + tmp2 += z2 - tmp1; + tmp3 += z2 + tmp1; + tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 9 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 9; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */ + tmp1 = tmp0 + tmp3; + tmp2 = tmp0 - tmp3 - tmp3; + + tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */ + tmp11 = tmp2 + tmp0; + tmp14 = tmp2 - tmp0 - tmp0; + + tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */ + tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */ + tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */ + + tmp10 = tmp1 + tmp0 - tmp3; + tmp12 = tmp1 - tmp0 + tmp2; + tmp13 = tmp1 - tmp2 + tmp3; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */ + + tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */ + tmp0 = tmp2 + tmp3 - z2; + tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */ + tmp2 += z2 - tmp1; + tmp3 += z2 + tmp1; + tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 10x10 output block. + * + * Optimized algorithm with 12 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/20). + */ + +GLOBAL(void) +jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*10]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + z5 = z3 << CONST_BITS; + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z5 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) (tmp22 + tmp12); + wsptr[8*7] = (int) (tmp22 - tmp12); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 10 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 10; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[7]; + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z3 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 11x11 output block. + * + * Optimized algorithm with 24 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/22). + */ + +GLOBAL(void) +jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*11]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */ + tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */ + z4 = z1 + z3; + tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */ + z4 -= z2; + tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */ + tmp21 = tmp20 + tmp23 + tmp25 - + MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */ + tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */ + tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */ + tmp24 += tmp25; + tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */ + tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */ + MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */ + tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z1 + z2; + tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */ + tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */ + tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */ + z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */ + tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */ + tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */ + z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */ + tmp11 += z1; + tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */ + tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */ + MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */ + MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 11 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 11; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp10 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */ + tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */ + z4 = z1 + z3; + tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */ + z4 -= z2; + tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */ + tmp21 = tmp20 + tmp23 + tmp25 - + MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */ + tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */ + tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */ + tmp24 += tmp25; + tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */ + tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */ + MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */ + tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = z1 + z2; + tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */ + tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */ + tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */ + z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */ + tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */ + tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */ + z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */ + tmp11 += z1; + tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */ + tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */ + MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */ + MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 12x12 output block. + * + * Optimized algorithm with 15 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/24). + */ + +GLOBAL(void) +jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*12]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 12 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 12; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 <<= CONST_BITS; + + z4 = (INT32) wsptr[4]; + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = (INT32) wsptr[2]; + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = (INT32) wsptr[6]; + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 13x13 output block. + * + * Optimized algorithm with 29 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/26). + */ + +GLOBAL(void) +jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*13]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */ + + tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */ + tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */ + + tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */ + tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */ + + tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */ + tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */ + + tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */ + tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */ + tmp15 = z1 + z4; + tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */ + tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */ + tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */ + tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */ + tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */ + tmp11 += tmp14; + tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */ + tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */ + tmp12 += tmp14; + tmp13 += tmp14; + tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */ + tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */ + MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */ + z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */ + tmp14 += z1; + tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */ + MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 13 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 13; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z1 <<= CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[4]; + z4 = (INT32) wsptr[6]; + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */ + + tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */ + tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */ + + tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */ + tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */ + + tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */ + tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */ + + tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */ + tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */ + + tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */ + tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */ + tmp15 = z1 + z4; + tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */ + tmp10 = tmp11 + tmp12 + tmp13 - + MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */ + tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */ + tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */ + tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */ + tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */ + tmp11 += tmp14; + tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */ + tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */ + tmp12 += tmp14; + tmp13 += tmp14; + tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */ + tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */ + MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */ + z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */ + tmp14 += z1; + tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */ + MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 14x14 output block. + * + * Optimized algorithm with 20 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/28). + */ + +GLOBAL(void) +jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*14]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp13 = z4 << CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */ + tmp16 += tmp15; + z1 += z4; + z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */ + tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = (z1 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) (tmp23 + tmp13); + wsptr[8*10] = (int) (tmp23 - tmp13); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 14 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 14; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z1 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + z4 <<= CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */ + tmp16 += tmp15; + tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */ + tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = ((z1 - z3) << CONST_BITS) + z4; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 15x15 output block. + * + * Optimized algorithm with 22 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/30). + */ + +GLOBAL(void) +jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*15]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */ + tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */ + + tmp12 = z1 - tmp10; + tmp13 = z1 + tmp11; + z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ + + z4 = z2 - z3; + z3 += z2; + tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */ + z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */ + + tmp20 = tmp13 + tmp10 + tmp11; + tmp23 = tmp12 - tmp10 + tmp11 + z2; + + tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */ + + tmp25 = tmp13 - tmp10 - tmp11; + tmp26 = tmp12 + tmp10 - tmp11 - z2; + + tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */ + + tmp21 = tmp12 + tmp10 + tmp11; + tmp24 = tmp13 - tmp10 + tmp11; + tmp11 += tmp11; + tmp22 = z1 + tmp11; /* c10 = c6-c12 */ + tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */ + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp13 = z2 - z4; + tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */ + tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */ + tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */ + + tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */ + tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */ + z2 = z1 - z4; + tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */ + + tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */ + tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */ + tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */ + z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */ + tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */ + tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 15 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 15; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z1 <<= CONST_BITS; + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[4]; + z4 = (INT32) wsptr[6]; + + tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */ + tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */ + + tmp12 = z1 - tmp10; + tmp13 = z1 + tmp11; + z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ + + z4 = z2 - z3; + z3 += z2; + tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */ + z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */ + + tmp20 = tmp13 + tmp10 + tmp11; + tmp23 = tmp12 - tmp10 + tmp11 + z2; + + tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */ + + tmp25 = tmp13 - tmp10 - tmp11; + tmp26 = tmp12 + tmp10 - tmp11 - z2; + + tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */ + tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */ + + tmp21 = tmp12 + tmp10 + tmp11; + tmp24 = tmp13 - tmp10 + tmp11; + tmp11 += tmp11; + tmp22 = z1 + tmp11; /* c10 = c6-c12 */ + tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[5]; + z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */ + z4 = (INT32) wsptr[7]; + + tmp13 = z2 - z4; + tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */ + tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */ + tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */ + + tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */ + tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */ + z2 = z1 - z4; + tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */ + + tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */ + tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */ + tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */ + z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */ + tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */ + tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 16x16 output block. + * + * Optimized algorithm with 28 multiplications in the 1-D kernel. + * cK represents sqrt(2) * cos(K*pi/32). + */ + +GLOBAL(void) +jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*16]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += 1 << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 16 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 16; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + + z1 = (INT32) wsptr[4]; + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 16x8 output block. + * + * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*8]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 <<= CONST_BITS; + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z2 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = z2 + z3; + tmp1 = z2 - z3; + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process 8 rows from work array, store into output array. + * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + + z1 = (INT32) wsptr[4]; + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 14x7 output block. + * + * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*7]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp23 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp23 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp10 = z1 + z3; + z2 -= tmp10; + tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */ + tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + + tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp10 = tmp11 - tmp12; + tmp11 += tmp12; + tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp11 += tmp12; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp10 += z2; + tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 7 rows from work array, store into output array. + * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28). + */ + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z1 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[6]; + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + z4 <<= CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */ + tmp16 += tmp15; + tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */ + tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = ((z1 - z3) << CONST_BITS) + z4; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 12x6 output block. + * + * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*6]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */ + tmp11 = tmp10 + tmp20; + tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS); + tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */ + tmp20 = tmp11 + tmp10; + tmp22 = tmp11 - tmp10; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp10 = tmp11 + ((z1 + z2) << CONST_BITS); + tmp12 = tmp11 + ((z3 - z2) << CONST_BITS); + tmp11 = (z1 - z2 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) (tmp21 + tmp11); + wsptr[8*4] = (int) (tmp21 - tmp11); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 6 rows from work array, store into output array. + * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24). + */ + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 <<= CONST_BITS; + + z4 = (INT32) wsptr[4]; + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = (INT32) wsptr[2]; + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = (INT32) wsptr[6]; + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z4 = (INT32) wsptr[7]; + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 10x5 output block. + * + * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*5]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp12 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 5 rows from work array, store into output array. + * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20). + */ + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[4]; + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + z3 <<= CONST_BITS; + z4 = (INT32) wsptr[7]; + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z3 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 8; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 8x4 output block. + * + * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 4-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp10 = (tmp0 + tmp2) << PASS1_BITS; + tmp12 = (tmp0 - tmp2) << PASS1_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */ + CONST_BITS-PASS1_BITS); + tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */ + CONST_BITS-PASS1_BITS); + + /* Final output stage */ + + wsptr[8*0] = (int) (tmp10 + tmp0); + wsptr[8*3] = (int) (tmp10 - tmp0); + wsptr[8*1] = (int) (tmp12 + tmp2); + wsptr[8*2] = (int) (tmp12 - tmp2); + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); + + /* Add fudge factor here for final descale. */ + z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 = (INT32) wsptr[4]; + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 6x3 output block. + * + * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[6*3]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 3 rows from work array, store into output array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[4]; + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = tmp0 - tmp10 - tmp10; + tmp10 = (INT32) wsptr[2]; + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << CONST_BITS; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 6; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 4x2 output block. + * + * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + INT32 * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + INT32 workspace[4*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + /* Odd part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + /* Final output stage */ + + wsptr[4*0] = tmp10 + tmp0; + wsptr[4*1] = tmp10 - tmp0; + } + + /* Pass 2: process 2 rows from work array, store into output array. + * 4-point IDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = wsptr[0] + (ONE << 2); + tmp2 = wsptr[2]; + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = wsptr[1]; + z3 = wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+3) + & RANGE_MASK]; + + wsptr += 4; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 2x1 output block. + * + * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10; + ISLOW_MULT_TYPE * quantptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* Pass 1: empty. */ + + /* Pass 2: process 1 row from input, store into output array. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + outptr = output_buf[0] + output_col; + + /* Even part */ + + tmp10 = DEQUANTIZE(coef_block[0], quantptr[0]); + /* Add fudge factor here for final descale. */ + tmp10 += ONE << 2; + + /* Odd part */ + + tmp0 = DEQUANTIZE(coef_block[1], quantptr[1]); + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, 3) & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, 3) & RANGE_MASK]; +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 8x16 output block. + * + * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[8*16]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + + z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ + tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */ + + tmp10 = tmp0 + tmp1; + tmp11 = tmp0 - tmp1; + tmp12 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z3 = z1 - z2; + z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */ + z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */ + + tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */ + tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */ + tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */ + tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */ + + tmp20 = tmp10 + tmp0; + tmp27 = tmp10 - tmp0; + tmp21 = tmp12 + tmp1; + tmp26 = tmp12 - tmp1; + tmp22 = tmp13 + tmp2; + tmp25 = tmp13 - tmp2; + tmp23 = tmp11 + tmp3; + tmp24 = tmp11 - tmp3; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z1 + z3; + + tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */ + tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */ + tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */ + tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */ + tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */ + tmp0 = tmp1 + tmp2 + tmp3 - + MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */ + tmp13 = tmp10 + tmp11 + tmp12 - + MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */ + z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */ + tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */ + tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */ + z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */ + tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */ + tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */ + z2 += z4; + z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */ + tmp1 += z1; + tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */ + z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */ + tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */ + tmp12 += z2; + z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */ + tmp2 += z2; + tmp3 += z2; + z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */ + tmp10 += z2; + tmp11 += z2; + + /* Final output stage */ + + wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < 16; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); + + /* Add fudge factor here for final descale. */ + z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + z3 = (INT32) wsptr[4]; + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 7x14 output block. + * + * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[7*14]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z1 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z1 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ + z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ + z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */ + + tmp10 = z1 + z2; + tmp11 = z1 + z3; + tmp12 = z1 - z4; + + tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */ + + tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */ + tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */ + tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */ + MULTIPLY(z2, FIX(1.378756276)); /* c2 */ + + tmp20 = tmp10 + tmp13; + tmp26 = tmp10 - tmp13; + tmp21 = tmp11 + tmp14; + tmp25 = tmp11 - tmp14; + tmp22 = tmp12 + tmp15; + tmp24 = tmp12 - tmp15; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp13 = z4 << CONST_BITS; + + tmp14 = z1 + z3; + tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ + tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */ + tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */ + tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */ + tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */ + z1 -= z2; + tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */ + tmp16 += tmp15; + z1 += z4; + z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */ + tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */ + tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */ + z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */ + tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ + tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ + + tmp13 = (z1 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[7*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[7*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[7*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[7*3] = (int) (tmp23 + tmp13); + wsptr[7*10] = (int) (tmp23 - tmp13); + wsptr[7*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[7*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[7*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[7*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + wsptr[7*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS); + wsptr[7*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 14 rows from work array, store into output array. + * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14). + */ + wsptr = workspace; + for (ctr = 0; ctr < 14; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp23 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp23 <<= CONST_BITS; + + z1 = (INT32) wsptr[2]; + z2 = (INT32) wsptr[4]; + z3 = (INT32) wsptr[6]; + + tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */ + tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */ + tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */ + tmp10 = z1 + z3; + z2 -= tmp10; + tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */ + tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */ + tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */ + tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */ + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + + tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */ + tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */ + tmp10 = tmp11 - tmp12; + tmp11 += tmp12; + tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */ + tmp11 += tmp12; + z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */ + tmp10 += z2; + tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 7; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 6x12 output block. + * + * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[6*12]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ + + tmp10 = z3 + z4; + tmp11 = z3 - z4; + + z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ + z1 <<= CONST_BITS; + z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + z2 <<= CONST_BITS; + + tmp12 = z1 - z2; + + tmp21 = z3 + tmp12; + tmp24 = z3 - tmp12; + + tmp12 = z4 + z2; + + tmp20 = tmp10 + tmp12; + tmp25 = tmp10 - tmp12; + + tmp12 = z4 - z1 - z2; + + tmp22 = tmp11 + tmp12; + tmp23 = tmp11 - tmp12; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */ + tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */ + + tmp10 = z1 + z3; + tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */ + tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */ + tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */ + tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */ + tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */ + tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */ + tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */ + MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */ + + z1 -= z4; + z2 -= z3; + z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */ + tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */ + tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */ + + /* Final output stage */ + + wsptr[6*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[6*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[6*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS); + wsptr[6*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS); + wsptr[6*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[6*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[6*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[6*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + wsptr[6*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS); + wsptr[6*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 12 rows from work array, store into output array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + wsptr = workspace; + for (ctr = 0; ctr < 12; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp10 <<= CONST_BITS; + tmp12 = (INT32) wsptr[4]; + tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */ + tmp11 = tmp10 + tmp20; + tmp21 = tmp10 - tmp20 - tmp20; + tmp20 = (INT32) wsptr[2]; + tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */ + tmp20 = tmp11 + tmp10; + tmp22 = tmp11 - tmp10; + + /* Odd part */ + + z1 = (INT32) wsptr[1]; + z2 = (INT32) wsptr[3]; + z3 = (INT32) wsptr[5]; + tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp10 = tmp11 + ((z1 + z2) << CONST_BITS); + tmp12 = tmp11 + ((z3 - z2) << CONST_BITS); + tmp11 = (z1 - z2 - z3) << CONST_BITS; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 6; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 5x10 output block. + * + * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp10, tmp11, tmp12, tmp13, tmp14; + INT32 tmp20, tmp21, tmp22, tmp23, tmp24; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[5*10]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z3 += ONE << (CONST_BITS-PASS1_BITS-1); + z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ + z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ + tmp10 = z3 + z1; + tmp11 = z3 - z2; + + tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ + CONST_BITS-PASS1_BITS); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */ + tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */ + tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */ + + tmp20 = tmp10 + tmp12; + tmp24 = tmp10 - tmp12; + tmp21 = tmp11 + tmp13; + tmp23 = tmp11 - tmp13; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + tmp11 = z2 + z4; + tmp13 = z2 - z4; + + tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ + z5 = z3 << CONST_BITS; + + z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ + z4 = z5 + tmp12; + + tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */ + tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ + + z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ + z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); + + tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; + + tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ + tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ + + /* Final output stage */ + + wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS); + wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS); + wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS); + wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS); + wsptr[5*2] = (int) (tmp22 + tmp12); + wsptr[5*7] = (int) (tmp22 - tmp12); + wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS); + wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS); + wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS); + wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 10 rows from work array, store into output array. + * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10). + */ + wsptr = workspace; + for (ctr = 0; ctr < 10; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp12 <<= CONST_BITS; + tmp13 = (INT32) wsptr[2]; + tmp14 = (INT32) wsptr[4]; + z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */ + z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */ + z3 = tmp12 + z2; + tmp10 = z3 + z1; + tmp11 = z3 - z1; + tmp12 -= z2 << 2; + + /* Odd part */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */ + tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */ + tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 5; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 4x8 output block. + * + * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[4*8]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 4; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[4*0] = dcval; + wsptr[4*1] = dcval; + wsptr[4*2] = dcval; + wsptr[4*3] = dcval; + wsptr[4*4] = dcval; + wsptr[4*5] = dcval; + wsptr[4*6] = dcval; + wsptr[4*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865); + tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + z2 <<= CONST_BITS; + z3 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + z2 += ONE << (CONST_BITS-PASS1_BITS-1); + + tmp0 = z2 + z3; + tmp1 = z2 - z3; + + tmp10 = tmp0 + tmp2; + tmp13 = tmp0 - tmp2; + tmp11 = tmp1 + tmp3; + tmp12 = tmp1 - tmp3; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z2 = tmp0 + tmp2; + z3 = tmp1 + tmp3; + + z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */ + z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + z2 += z1; + z3 += z1; + + z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + tmp0 += z1 + z2; + tmp3 += z1 + z3; + + z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp1 += z1 + z3; + tmp2 += z1 + z2; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process 8 rows from work array, store into output array. + * 4-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16). + */ + wsptr = workspace; + for (ctr = 0; ctr < 8; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp2 = (INT32) wsptr[2]; + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = (INT32) wsptr[1]; + z3 = (INT32) wsptr[3]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 4; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 3x6 output block. + * + * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[3*6]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12). + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= CONST_BITS; + /* Add fudge factor here for final descale. */ + tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ + tmp1 = tmp0 + tmp10; + tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS); + tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */ + tmp10 = tmp1 + tmp0; + tmp12 = tmp1 - tmp0; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ + tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); + tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); + tmp1 = (z1 - z2 - z3) << PASS1_BITS; + + /* Final output stage */ + + wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS); + wsptr[3*1] = (int) (tmp11 + tmp1); + wsptr[3*4] = (int) (tmp11 - tmp1); + wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS); + } + + /* Pass 2: process 6 rows from work array, store into output array. + * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6). + */ + wsptr = workspace; + for (ctr = 0; ctr < 6; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); + tmp0 <<= CONST_BITS; + tmp2 = (INT32) wsptr[2]; + tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ + tmp10 = tmp0 + tmp12; + tmp2 = tmp0 - tmp12 - tmp12; + + /* Odd part */ + + tmp12 = (INT32) wsptr[1]; + tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += 3; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 2x4 output block. + * + * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + INT32 * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + INT32 workspace[2*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. + * 4-point IDCT kernel, + * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT]. + */ + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) { + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp10 = (tmp0 + tmp2) << CONST_BITS; + tmp12 = (tmp0 - tmp2) << CONST_BITS; + + /* Odd part */ + /* Same rotation as in the even part of the 8x8 LL&M IDCT */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */ + tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */ + tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */ + + /* Final output stage */ + + wsptr[2*0] = tmp10 + tmp0; + wsptr[2*3] = tmp10 - tmp0; + wsptr[2*1] = tmp12 + tmp2; + wsptr[2*2] = tmp12 - tmp2; + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + + /* Even part */ + + /* Add fudge factor here for final descale. */ + tmp10 = wsptr[0] + (ONE << (CONST_BITS+2)); + + /* Odd part */ + + tmp0 = wsptr[1]; + + /* Final output stage */ + + outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3) + & RANGE_MASK]; + + wsptr += 2; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a 1x2 output block. + * + * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows). + */ + +GLOBAL(void) +jpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* Process 1 column from input, store into output array. */ + + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + + /* Even part */ + + tmp10 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]); + /* Add fudge factor here for final descale. */ + tmp10 += ONE << 2; + + /* Odd part */ + + tmp0 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]); + + /* Final output stage */ + + output_buf[0][output_col] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, 3) + & RANGE_MASK]; + output_buf[1][output_col] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, 3) + & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jmemansi.c b/library/src/main/cpp/jpeg/src/jmemansi.c new file mode 100644 index 00000000..967e7e45 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jmemansi.c @@ -0,0 +1,188 @@ +/* + * jmemansi.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a simple generic implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that you have the ANSI-standard library routine tmpfile(). + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); + /* Since this implementation uses tmpfile() to create the file, + * no explicit file deletion is needed. + */ +} + + +/* + * Initial opening of a backing-store object. + * + * This version uses tmpfile(), which constructs a suitable file name + * behind the scenes. We don't have to use info->temp_name[] at all; + * indeed, we can't even find out the actual name of the temp file. + */ +//static char ANSI_TEMP_FOLDER_PATH[512]; +EXTERN(void) jpeg_set_temp_folder( const char *tempFolderPath) +{ + strncpy(ANSI_TEMP_FOLDER_PATH, tempFolderPath, sizeof(ANSI_TEMP_FOLDER_PATH)); +} + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + //IvanDebug + FILE *fp; + char path[512] = {0}; + + char tmpfile[] = "temp-XXXXXX"; + mktemp(tmpfile); + snprintf(path, sizeof(path), "%s%s", ANSI_TEMP_FOLDER_PATH, tmpfile); + + fp = fopen(path, "wb+"); + + if (fp == NULL) + { + ERREXITS(cinfo, JERR_TFILE_CREATE, path); + } + unlink(path); + + if ((info->temp_file = fp) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, "**"); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/library/src/main/cpp/jpeg/src/jmemmgr.c b/library/src/main/cpp/jpeg/src/jmemmgr.c new file mode 100644 index 00000000..f0e83fb9 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jmemmgr.c @@ -0,0 +1,1119 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray and barray routines, + * even though they are textually almost the same, because samples are + * usually stored as bytes while coefficients are shorts or ints. Thus, + * in machines where byte pointers have a different representation from + * word pointers, the resulting machine code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + long total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL(void) +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL(void) +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF(void *) +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + char * data_ptr; + size_t odd_bytes, min_request, slop; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF(void FAR *) +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF(JSAMPARRAY) +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + * SIZEOF(JSAMPLE))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JBLOCKARRAY) +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + * SIZEOF(JBLOCK))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF(jvirt_sarray_ptr) +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF(jvirt_barray_ptr) +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF(void) +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long space_per_minheight, maximum_space, avail_mem; + long minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) sptr->maxaccess * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + maximum_space += (long) sptr->rows_in_array * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) bptr->maxaccess * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + maximum_space += (long) bptr->rows_in_array * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL(void) +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL(void) +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF(JSAMPARRAY) +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF(JBLOCKARRAY) +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF(void) +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF(void) +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL(void) +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Make MAX_ALLOC_CHUNK accessible to other modules */ + mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = & mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/library/src/main/cpp/jpeg/src/jquant1.c b/library/src/main/cpp/jpeg/src/jquant1.c new file mode 100644 index 00000000..9d11f706 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jquant1.c @@ -0,0 +1,857 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL(int) +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL(int) +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL(int) +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL(void) +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL(void) +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL(ODITHER_MATRIX_PTR) +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL(void) +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + FMEMZERO((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + FMEMZERO((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL(void) +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) + (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF(void) +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) + FMEMZERO((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF(void) +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF(void) +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL(void) +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jquant2.c b/library/src/main/cpp/jpeg/src/jquant2.c new file mode 100644 index 00000000..38fc2af7 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jquant2.c @@ -0,0 +1,1311 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL(boxptr) +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL(boxptr) +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL(void) +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL(int) +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL(void) +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL(void) +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL(void) +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL(void) +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF(void) +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL(void) +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF(void) +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF(void) +finish_pass2 (j_decompress_ptr cinfo) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF(void) +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * SIZEOF(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + FMEMZERO((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + FMEMZERO((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF(void) +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL(void) +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/library/src/main/cpp/jpeg/src/jutils.c b/library/src/main/cpp/jpeg/src/jutils.c new file mode 100644 index 00000000..5b16b6d0 --- /dev/null +++ b/library/src/main/cpp/jpeg/src/jutils.c @@ -0,0 +1,227 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2009-2011 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +#if 0 /* This table is not actually needed in v6a */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +#endif + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order7[7*7+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 14, 21, 28, 35, + 42, 49, 50, 43, 36, 29, 22, 30, + 37, 44, 51, 52, 45, 38, 46, 53, + 54, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order6[6*6+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 41, 34, 27, + 20, 13, 21, 28, 35, 42, 43, 36, + 29, 37, 44, 45, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order5[5*5+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 12, + 19, 26, 33, 34, 27, 20, 28, 35, + 36, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order4[4*4+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 25, 18, 11, 19, 26, 27, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order3[3*3+16] = { + 0, 1, 8, 16, 9, 2, 10, 17, + 18, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + +const int jpeg_natural_order2[2*2+16] = { + 0, 1, 8, 9, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL(long) +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL(long) +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#else +/* This function is for use by the FMEMZERO macro defined in jpegint.h. + * Do not call this function directly, use the FMEMZERO macro instead. + */ +GLOBAL(void) +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +} +#endif +#endif + + +GLOBAL(void) +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); +#else + register JDIMENSION count; +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL(void) +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/contentstream/PDFStreamEngine.java b/library/src/main/java/com/tom_roush/pdfbox/contentstream/PDFStreamEngine.java index 050f5c61..12f8b200 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/contentstream/PDFStreamEngine.java +++ b/library/src/main/java/com/tom_roush/pdfbox/contentstream/PDFStreamEngine.java @@ -529,6 +529,8 @@ private void processStream(PDContentStream contentStream) throws IOException * @param contentStream to content stream to parse. * @throws IOException if there is an error reading or parsing the content stream. */ + + int test = 0; private void processStreamOperators(PDContentStream contentStream) throws IOException { List arguments = new ArrayList(); diff --git a/library/src/main/java/com/tom_roush/pdfbox/contentstream/operator/color/SetColor.java b/library/src/main/java/com/tom_roush/pdfbox/contentstream/operator/color/SetColor.java index 5928da48..3751582b 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/contentstream/operator/color/SetColor.java +++ b/library/src/main/java/com/tom_roush/pdfbox/contentstream/operator/color/SetColor.java @@ -27,6 +27,7 @@ import com.tom_roush.pdfbox.cos.COSNumber; import com.tom_roush.pdfbox.pdmodel.graphics.color.PDColor; import com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDPattern; /** * sc,scn,SC,SCN: Sets the color to use for stroking or non-stroking operations. @@ -39,7 +40,7 @@ public abstract class SetColor extends OperatorProcessor public void process(Operator operator, List arguments) throws IOException { PDColorSpace colorSpace = getColorSpace(); -// if (!(colorSpace instanceof PDPattern)) TODO: PdfBox-Android + if (!(colorSpace instanceof PDPattern)) //TODO: PdfBox-Android { if (arguments.size() < colorSpace.getNumberOfComponents()) { diff --git a/library/src/main/java/com/tom_roush/pdfbox/cos/COSArray.java b/library/src/main/java/com/tom_roush/pdfbox/cos/COSArray.java index a2fa8681..d387cf1c 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/cos/COSArray.java +++ b/library/src/main/java/com/tom_roush/pdfbox/cos/COSArray.java @@ -42,6 +42,25 @@ public COSArray() //default constructor } + /** + * Use the given list to initialize the COSArray. + * + * @param cosObjectables the initial list of COSObjectables + */ + public COSArray(List cosObjectables) + { + if (cosObjectables == null) + { + throw new IllegalArgumentException("List of COSObjectables cannot be null"); + } + for (COSObjectable objectable:cosObjectables) { + objects.add(objectable.getCOSObject()); + } +// updateState = new COSUpdateState(this); +// cosObjectables.forEach(cosObjectable -> +// objects.add(cosObjectable != null ? cosObjectable.getCOSObject() : null)); + } + /** * This will add an object to the array. * @@ -582,4 +601,17 @@ public List toList() { return new ArrayList(objects); } + + public List toCOSNameStringList() + { + List retList = new ArrayList(); + for (int i = 0; i < size(); i++) + { + COSBase base = get(i); + if (base instanceof COSName) { + retList.add(((COSName) base).getName()); + } + } + return retList; + } } diff --git a/library/src/main/java/com/tom_roush/pdfbox/filter/FilterFactory.java b/library/src/main/java/com/tom_roush/pdfbox/filter/FilterFactory.java index a22608b3..fe62b1df 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/filter/FilterFactory.java +++ b/library/src/main/java/com/tom_roush/pdfbox/filter/FilterFactory.java @@ -48,7 +48,7 @@ private FilterFactory() Filter runLength = new RunLengthDecodeFilter(); Filter crypt = new CryptFilter(); Filter jpx = new JPXFilter(); -// Filter jbig2 = new JBIG2Filter();TODO: PdfBox-Android + Filter jbig2 = new JBIG2Filter(); filters.put(COSName.FLATE_DECODE, flate); filters.put(COSName.FLATE_DECODE_ABBREVIATION, flate); @@ -66,7 +66,7 @@ private FilterFactory() filters.put(COSName.RUN_LENGTH_DECODE_ABBREVIATION, runLength); filters.put(COSName.CRYPT, crypt); filters.put(COSName.JPX_DECODE, jpx); -// filters.put(COSName.JBIG2_DECODE, jbig2);TODO: PdfBox-Android + filters.put(COSName.JBIG2_DECODE, jbig2); } /** diff --git a/library/src/main/java/com/tom_roush/pdfbox/filter/JBIG2Filter.java b/library/src/main/java/com/tom_roush/pdfbox/filter/JBIG2Filter.java new file mode 100644 index 00000000..b199c0fc --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/filter/JBIG2Filter.java @@ -0,0 +1,55 @@ +package com.tom_roush.pdfbox.filter; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.util.Log; + +import com.tom_roush.pdfbox.cos.COSDictionary; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.io.IOUtils; +import com.xsooy.jbig2.Jbig2Utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class JBIG2Filter extends Filter{ + + private static final int CACHE_SIZE = 1024; + + @Override + public DecodeResult decode(InputStream encoded, OutputStream decoded, COSDictionary parameters, int index) throws IOException { + +// int bits = parameters.getInt(COSName.BITS_PER_COMPONENT, 1); +// COSDictionary params = getDecodeParams(parameters, index); + + DecodeResult result = new DecodeResult(parameters); + result.getParameters().addAll(parameters); + Jbig2Utils jbig2Utils = new Jbig2Utils(); + byte[] data = new byte[encoded.available()]; + IOUtils.populateBuffer(encoded,data); + byte[] image = jbig2Utils.converData(data); + + int arrLen = image.length; + byte[] buffer = new byte[CACHE_SIZE]; + int pos = 0; + + for (int i = 0; i < arrLen; i++) + { + if (pos >= buffer.length) + { + decoded.write(buffer, 0, pos); + pos = 0; + } + buffer[pos] = image[i]; + pos++; + } + decoded.write(buffer, 0, pos); + return result; + } + + @Override + protected void encode(InputStream input, OutputStream encoded, COSDictionary parameters) throws IOException { + + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FileSystemFontProvider.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FileSystemFontProvider.java index c7690ded..b6a5ef76 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FileSystemFontProvider.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FileSystemFontProvider.java @@ -342,6 +342,24 @@ private FSIgnored(File file, FontFormat format, String postScriptName) addTrueTypeFont(new File("/system/fonts/DroidSansMono.ttf")); // addTrueTypeFont(new File("/system/fonts/DroidSansFallback.ttf")); // XXX: list may need to be expanded for other character sets + FontFileFinder fontFileFinder = new FontFileFinder(); + List fonts = fontFileFinder.find(); + for (URI font : fonts) + { + if (font.getPath().contains("NotoSansCJK")&&font.getPath().contains("Regular")) { + File file = new File(font); + if (file.getName().endsWith(".ttf")) { + addTrueTypeFont(file); + } else if (file.getName().endsWith(".otf")) { + addTrueTypeFont(file); + } else if (file.getName().endsWith(".ttc")) { + addTrueTypeCollection(file); + } else if (file.getName().endsWith(".otc")) { + addTrueTypeCollection(file); + } + } + } + return; } catch (IOException e) diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapper.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapper.java index f4b07377..ea8cd63c 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapper.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapper.java @@ -51,4 +51,5 @@ public interface FontMapper */ CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor, PDCIDSystemInfo cidSystemInfo); + } diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapperImpl.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapperImpl.java index 4ffd4432..505df2b5 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapperImpl.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/FontMapperImpl.java @@ -682,12 +682,12 @@ private boolean probablyBarcodeFont(PDFontDescriptor fontDescriptor) */ private boolean isCharSetMatch(PDCIDSystemInfo cidSystemInfo, FontInfo info) { - if (info.getCIDSystemInfo() != null) - { - return info.getCIDSystemInfo().getRegistry().equals(cidSystemInfo.getRegistry()) && - info.getCIDSystemInfo().getOrdering().equals(cidSystemInfo.getOrdering()); - } - else +// if (info.getCIDSystemInfo() != null) +// { +// return info.getCIDSystemInfo().getRegistry().equals(cidSystemInfo.getRegistry()) && +// info.getCIDSystemInfo().getOrdering().equals(cidSystemInfo.getOrdering()); +// } +// else { long codePageRange = info.getCodePageRange(); @@ -765,4 +765,5 @@ private FontMatch printMatches(PriorityQueue queue) System.out.println("-------"); return bestMatch; } + } diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType0.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType0.java index 15b6100c..0fa2b97f 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType0.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType0.java @@ -31,6 +31,10 @@ import com.tom_roush.fontbox.cff.CFFParser; import com.tom_roush.fontbox.cff.CFFType1Font; import com.tom_roush.fontbox.cff.Type2CharString; +import com.tom_roush.fontbox.ttf.CmapLookup; +import com.tom_roush.fontbox.ttf.GlyphData; +import com.tom_roush.fontbox.ttf.OpenTypeFont; +import com.tom_roush.fontbox.ttf.TrueTypeFont; import com.tom_roush.fontbox.util.BoundingBox; import com.tom_roush.harmony.awt.geom.AffineTransform; import com.tom_roush.pdfbox.cos.COSDictionary; @@ -61,6 +65,8 @@ public class PDCIDFontType0 extends PDCIDFont private BoundingBox fontBBox; private int[] cid2gid = null; + private final CmapLookup cmap; // may be null + /** * Constructor. * @@ -120,6 +126,7 @@ else if (bytes != null) cid2gid = readCIDToGIDMap(); isEmbedded = true; isDamaged = false; + cmap = null; } else { @@ -130,20 +137,27 @@ else if (bytes != null) FontBoxFont font; if (mapping.isCIDFont()) { - cffFont = mapping.getFont().getCFF().getFont(); - if (cffFont instanceof CFFCIDFont) - { - cidFont = (CFFCIDFont) cffFont; - t1Font = null; - font = cidFont; - } - else - { - // PDFBOX-3515: OpenType fonts are loaded as CFFType1Font - CFFType1Font f = (CFFType1Font) cffFont; + cmap = mapping.getFont().getUnicodeCmapLookup(false); + if (cmap !=null) { cidFont = null; - t1Font = f; - font = f; + font = (TrueTypeFont) mapping.getFont(); + t1Font = font; + } else { + cffFont = mapping.getFont().getCFF().getFont(); + if (cffFont instanceof CFFCIDFont) + { + cidFont = (CFFCIDFont) cffFont; + t1Font = null; + font = cidFont; + } + else + { + // PDFBOX-3515: OpenType fonts are loaded as CFFType1Font + CFFType1Font f = (CFFType1Font) cffFont; + cidFont = null; + t1Font = f; + font = f; + } } } else @@ -151,6 +165,7 @@ else if (bytes != null) cidFont = null; t1Font = mapping.getTrueTypeFont(); font = t1Font; + cmap = null; } if (mapping.isFallback()) @@ -338,6 +353,19 @@ else if (isEmbedded && t1Font instanceof CFFType1Font) } else { + try { + if (cmap!=null) { + String unicode = parent.toUnicode(code); + int gid = cmap.getGlyphId(unicode.codePointAt(0)); + if (t1Font instanceof OpenTypeFont && ((OpenTypeFont)t1Font).isPostScript()) + { + Type2CharString charstring2 = ((OpenTypeFont)t1Font).getCFF().getFont().getType2CharString(gid); + return charstring2.getPath(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } return t1Font.getPath(getGlyphName(code)); } } diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType2.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType2.java index f450bc43..980c3893 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType2.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDCIDFontType2.java @@ -130,6 +130,7 @@ public PDCIDFontType2(COSDictionary fontDictionary, PDType0Font parent, TrueType if (ttfFont == null) { ttfFont = findFontOrSubstitute(); + Log.w("ceshi","ttfFont::"+ttfFont.getClass().getSimpleName()); } ttf = ttfFont; } diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDFontFactory.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDFontFactory.java index 956a9949..19ee1fd0 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDFontFactory.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/font/PDFontFactory.java @@ -130,6 +130,21 @@ static PDCIDFont createDescendantFont(COSDictionary dictionary, PDType0Font pare COSName subType = dictionary.getCOSName(COSName.SUBTYPE); if (COSName.CID_FONT_TYPE0.equals(subType)) { +// COSBase base = dictionary.getDictionaryObject(COSName.CIDSYSTEMINFO); +// if (base instanceof COSDictionary) +// { +// PDCIDSystemInfo cidSystemInfo = new PDCIDSystemInfo((COSDictionary) base); +// String collection = cidSystemInfo.getRegistry() + "-" + cidSystemInfo.getOrdering(); +// if (collection.equals("Adobe-GB1") || collection.equals("Adobe-CNS1") || +// collection.equals("Adobe-Japan1") || collection.equals("Adobe-Korea1")) +// { +// COSDictionary fd = (COSDictionary) dictionary.getDictionaryObject(COSName.FONT_DESC); +// if (FontMappers.instance().getCIDFontDefault(dictionary.getNameAsString(COSName.BASE_FONT), new PDFontDescriptor(fd), cidSystemInfo)==null) { +// Log.w("ceshi","???==="+collection); +// return new PDCIDFontType2(dictionary, parent); +// } +// } +// } return new PDCIDFontType0(dictionary, parent); } else if (COSName.CID_FONT_TYPE2.equals(subType)) diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java new file mode 100644 index 00000000..c46d17a0 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +/** + * CIE-based colour spaces specify colours in a way that is independent of the characteristics + * of any particular output device. They are based on an international standard for colour + * specification created by the Commission Internationale de l'Éclairage (CIE). + * + * @author John Hewson + */ +public abstract class PDCIEBasedColorSpace extends PDColorSpace +{ + // + // WARNING: this method is performance sensitive, modify with care! + // +// @Override +// public BufferedImage toRGBImage(WritableRaster raster) throws IOException +// { +// // This method calls toRGB to convert images one pixel at a time. For matrix-based +// // CIE color spaces this is fast enough. However, it should not be used with any +// // color space which uses an ICC Profile as it will be far too slow. +// +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// +// BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// WritableRaster rgbRaster = rgbImage.getRaster(); +// +// // always three components: ABC +// float[] abc = new float[3]; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, abc); +// +// // 0..255 -> 0..1 +// abc[0] /= 255; +// abc[1] /= 255; +// abc[2] /= 255; +// +// float[] rgb = toRGB(abc); +// +// // 0..1 -> 0..255 +// rgb[0] *= 255; +// rgb[1] *= 255; +// rgb[2] *= 255; +// +// rgbRaster.setPixel(x, y, rgb); +// } +// } +// +// return rgbImage; +// } + +// @Override +// public BufferedImage toRawImage(WritableRaster raster) throws IOException +// { +// // There is no direct equivalent of a CIE colorspace in Java. So we can +// // not do anything here. +// return null; +// } + + @Override + public String toString() + { + return getName(); // TODO return more info + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDCIEDictionaryBasedColorSpace.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDCIEDictionaryBasedColorSpace.java new file mode 100644 index 00000000..553f522a --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDCIEDictionaryBasedColorSpace.java @@ -0,0 +1,177 @@ +/* + * Copyright 2014 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSDictionary; +import com.tom_roush.pdfbox.cos.COSFloat; +import com.tom_roush.pdfbox.cos.COSName; + + +/** + * CIE-based colour spaces that use a dictionary. + * + * @author Ben Litchfield + * @author John Hewson + */ +public abstract class PDCIEDictionaryBasedColorSpace extends PDCIEBasedColorSpace +{ + protected final COSDictionary dictionary; + +// private static final ColorSpace CIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + + // we need to cache whitepoint values, because using getWhitePoint() + // would create a new default object for each pixel conversion if the original + // PDF didn't have a whitepoint array + protected float wpX = 1; + protected float wpY = 1; + protected float wpZ = 1; + + protected PDCIEDictionaryBasedColorSpace(COSName cosName) + { + array = new COSArray(); + dictionary = new COSDictionary(); + array.add(cosName); + array.add(dictionary); + + fillWhitepointCache(getWhitepoint()); + } + + /** + * Creates a new CalRGB color space using the given COS array. + * + * @param rgb the cos array which represents this color space + */ + protected PDCIEDictionaryBasedColorSpace(COSArray rgb) + { + array = rgb; + dictionary = (COSDictionary) array.getObject(1); + + fillWhitepointCache(getWhitepoint()); + } + + /** + * Tests if the current point is the white point. + * + * @return true if the current point is the white point. + */ + protected boolean isWhitePoint() + { + return Float.compare(wpX, 1) == 0 && + Float.compare(wpY, 1) == 0 && + Float.compare(wpZ, 1) == 0; + } + + private void fillWhitepointCache(PDTristimulus whitepoint) + { + wpX = whitepoint.getX(); + wpY = whitepoint.getY(); + wpZ = whitepoint.getZ(); + } + + protected float[] convXYZtoRGB(float x, float y, float z) + { + // toRGB() malfunctions with negative values + // XYZ must be non-negative anyway: + // http://ninedegreesbelow.com/photography/icc-profile-negative-tristimulus.html + if (x < 0) + { + x = 0; + } + if (y < 0) + { + y = 0; + } + if (z < 0) + { + z = 0; + } + return xyzToRgb(new float[] + { + x, y, z + }); + } + + + + /** + * This will return the whitepoint tristimulus. As this is a required field + * this will never return null. A default of 1,1,1 will be returned if the + * pdf does not have any values yet. + * + * @return the whitepoint tristimulus + */ + public final PDTristimulus getWhitepoint() + { + COSArray wp = dictionary.getCOSArray(COSName.WHITE_POINT); + if (wp == null) + { + wp = new COSArray(); + wp.add(new COSFloat(1.0f)); + wp.add(new COSFloat(1.0f)); + wp.add(new COSFloat(1.0f)); + } + return new PDTristimulus(wp); + } + + /** + * This will return the BlackPoint tristimulus. This is an optional field + * but has defaults so this will never return null. A default of 0,0,0 will + * be returned if the pdf does not have any values yet. + * + * @return the blackpoint tristimulus + */ + public final PDTristimulus getBlackPoint() + { + COSArray bp = dictionary.getCOSArray(COSName.BLACK_POINT); + if (bp == null) + { + bp = new COSArray(); + bp.add(new COSFloat(0.0f)); + bp.add(new COSFloat(0.0f)); + bp.add(new COSFloat(0.0f)); + } + return new PDTristimulus(bp); + } + + /** + * This will set the whitepoint tristimulus. As this is a required field, null should not be + * passed into this function. + * + * @param whitepoint the whitepoint tristimulus. + * @throws IllegalArgumentException if null is passed as argument. + */ + public void setWhitePoint(PDTristimulus whitepoint) + { + if (whitepoint == null) + { + throw new IllegalArgumentException("Whitepoint may not be null"); + } + dictionary.setItem(COSName.WHITE_POINT, whitepoint); + fillWhitepointCache(whitepoint); + } + + /** + * This will set the BlackPoint tristimulus. + * + * @param blackpoint the BlackPoint tristimulus + */ + public void setBlackPoint(PDTristimulus blackpoint) + { + dictionary.setItem(COSName.BLACK_POINT, blackpoint); + } + +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDColorSpace.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDColorSpace.java index 01e732ff..262e320f 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDColorSpace.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDColorSpace.java @@ -39,6 +39,17 @@ */ public abstract class PDColorSpace implements COSObjectable { + + public static final int TYPE_XYZ = 0; + + public static final int TYPE_Lab = 1; + + public static final int TYPE_RGB = 5; + + public static final int TYPE_GRAY = 6; + + public static final int TYPE_CMYK = 9; + /** * Creates a color space given a name or array. * @param colorSpace the color space COS object @@ -121,9 +132,9 @@ else if (name.equals(COSName.DEVICEGRAY) && // built-in color spaces if (name == COSName.DEVICECMYK) { -// return PDDeviceCMYK.INSTANCE; - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return PDDeviceCMYK.INSTANCE; +// Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); +// return PDDeviceRGB.INSTANCE; } else if (name == COSName.DEVICERGB) { @@ -135,9 +146,9 @@ else if (name == COSName.DEVICEGRAY) } else if (name == COSName.PATTERN) { -// return new PDPattern(resources); - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return new PDPattern(resources); +// Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); +// return PDDeviceRGB.INSTANCE; } else if (resources != null) { @@ -182,33 +193,31 @@ else if (name == COSName.CALRGB) } else if (name == COSName.DEVICEN) { -// return new PDDeviceN(array); - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return new PDDeviceN(array); +// Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); +// return PDDeviceRGB.INSTANCE; } else if (name == COSName.INDEXED) { -// return new PDIndexed(array); - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return new PDIndexed(array); +// Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); +// return PDDeviceRGB.INSTANCE; } else if (name == COSName.SEPARATION) { -// return new PDSeparation(array); - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return new PDSeparation(array); +// Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); +// return PDDeviceRGB.INSTANCE; } else if (name == COSName.ICCBASED) { -// return PDICCBased.create(array, resources); - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return PDICCBased.create(array, resources); } else if (name == COSName.LAB) { -// return new PDLab(array); - Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); - return PDDeviceRGB.INSTANCE; + return new PDLab(array); +// Log.e("PdfBox-Android", "Unsupported color space kind: " + name + ". Will try DeviceRGB instead"); +// return PDDeviceRGB.INSTANCE; } else if (name == COSName.PATTERN) { @@ -331,4 +340,108 @@ public COSBase getCOSObject() { return array; } + + + public static float getMinValue(int colorType,int index) { + switch (colorType) { + case TYPE_XYZ: + return 0.0f; // X, Y, Z +// result[1] = 1.0f + (32767.0f / 32768.0f); +// break; + case TYPE_Lab: + switch (index) { + case 0: + return 0.0f; + case 1: + case 2: + return -128.0f; + } + default: + return 0.0f; + } + } + + public static float getMaxValue(int colorType,int index) { + switch (colorType) { + case TYPE_XYZ: +// return 0.0f; // X, Y, Z + return 1.0f + (32767.0f / 32768.0f); + case TYPE_Lab: + switch (index) { + case 0: + return 100.0f; + case 1: + case 2: + return 127.0f; + } + default: + return 1.0f; + } + } + + //x,y,z To r=[0],g=[1],b=[2] + public float[] xyzToRgb(float[] xyz) { + float[] rgb = new float[3]; + rgb[0] = (xyz[0] * 3.240479f) + (xyz[1] * -1.537150f) + (xyz[2] * -.498535f); + rgb[1] = (xyz[0] * -.969256f) + (xyz[1] * 1.875992f) + (xyz[2] * .041556f); + rgb[2] = (xyz[0] * .055648f) + (xyz[1] * -.204043f) + (xyz[2] * 1.057311f); + + for (int i = 0; i < 3; i++) + { + if (rgb[i] > .0031308f) + { + rgb[i] = (1.055f * (float)Math.pow(rgb[i], (1.0f / 2.4f))) - .055f; + } + else + { + rgb[i] = rgb[i] * 12.92f; + } + } + return rgb; + } + + public float[] toLab(float[] value) { + float[] lab = new float[3]; + for (int i=0;i<3;i++) { + lab[i] = (getMaxValue(TYPE_Lab,i)-getMinValue(TYPE_Lab,i))*value[i]+getMinValue(TYPE_Lab,i); + } +// lab[0] = value[0] * 100; +// float min = -128.0f; +// float max = 127.0f; +// lab[1] = (max-min)*value[1]+min; +// lab[2] = (max-min)*value[2]+min; + return lab; + } + + public float[] labToXyz(float[] value) { + float[] xyz = new float[3]; + xyz[1] = (value[0]+16.f)/116.f; + xyz[0] = value[1]/500.f+xyz[1]; + xyz[2] = xyz[1]-value[2]/200.f; + + for (int i = 0; i < 3; i++) + { + float pow = xyz[i] * xyz[i] * xyz[i]; + float ratio = (6.0f / 29.0f); + if (xyz[i] > ratio) + { + xyz[i] = pow; + } + else + { + xyz[i] = (3.0f * (6.0f / 29.0f) * (6.0f / 29.0f) * (xyz[i] - (4.0f / 29.0f))); + } + } + + xyz[0] = xyz[0] * (95.047f); + xyz[1] = xyz[1] * (100.0f); + xyz[2] = xyz[2] * (108.883f); + + xyz[0] = xyz[0] / 100f; + xyz[1] = xyz[1] / 100f; + xyz[2] = xyz[2] / 100f; + + return xyz; + } + } diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java new file mode 100644 index 00000000..1cfa789b --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java @@ -0,0 +1,187 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.opengl.Matrix; +import android.util.Log; + +import com.tom_roush.pdfbox.android.PDFBoxResourceLoader; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.io.IOUtils; +import com.xsooy.icc.IccUtils; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; + +public class PDDeviceCMYK extends PDDeviceColorSpace +{ + + private IccUtils iccUtils; + /** The single instance of this class. */ + public static PDDeviceCMYK INSTANCE; + static + { + INSTANCE = new PDDeviceCMYK(); + } + + private final PDColor initialColor = new PDColor(new float[] { 0, 0, 0, 1 }, this); + // private ICC_ColorSpace awtColorSpace; + public volatile boolean initDone = false; + + protected PDDeviceCMYK() + { + } + + /** + * Lazy load the ICC profile, because it's slow. + */ + protected void init() throws IOException + { + // no need to synchronize this check as it is atomic + if (initDone) + { + return; + } + synchronized (this) + { + // we might have been waiting for another thread, so check again + if (initDone) + { + return; + } + + InputStream inputStream = PDFBoxResourceLoader.getStream("com/tom_roush/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc"); + byte[] buff = new byte[inputStream.available()]; + IOUtils.populateBuffer(inputStream,buff); + iccUtils = new IccUtils(); + iccUtils.loadProfileByData(buff); + initDone = true; +// if (new File(IccUtils.iccProfileDir+"/ISOcoated_v2_300_bas.icc").exists()) { +// iccUtils = new IccUtils(); +// iccUtils.loadProfile(IccUtils.iccProfileDir+"/ISOcoated_v2_300_bas.icc"); +// } +// initDone = true; + } + } + +// protected ICC_Profile getICCProfile() throws IOException +// { +// // Adobe Acrobat uses "U.S. Web Coated (SWOP) v2" as the default +// // CMYK profile, however it is not available under an open license. +// // Instead, the "ISO Coated v2 300% (basICColor)" is used, which +// // is an open alternative to the "ISO Coated v2 300% (ECI)" profile. +// +// String resourceName = "/org/apache/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc"; +// InputStream resourceAsStream = PDDeviceCMYK.class.getResourceAsStream(resourceName); +// if (resourceAsStream == null) +// { +// throw new IOException("resource '" + resourceName + "' not found"); +// } +// try (InputStream is = new BufferedInputStream(resourceAsStream)) +// { +// return ICC_Profile.getInstance(is); +// } +// } + + @Override + public String getName() + { + return COSName.DEVICECMYK.getName(); + } + + @Override + public int getNumberOfComponents() + { + return 4; + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) + { + return new float[] { 0, 1, 0, 1, 0, 1, 0, 1 }; + } + + @Override + public PDColor getInitialColor() + { + return initialColor; + } + + @Override + public float[] toRGB(float[] value) throws IOException + { + init(); +// Log.w("ceshi",String.format("value:%f,%f,%f,%f",value[0],value[1],value[2],value[3])); + //cmyk to lab + if (iccUtils!=null) { + float[] data = new float[3]; + iccUtils.applyCmyk(value,data); +// float[] lab = toLab(data); +// float[] xyz = labToXyz(lab); +// return NormalColorSpace.xyzToRgb(xyz); + return data; + } + return new float[]{(1-value[0])*(1-value[3]),(1-value[1])*(1-value[3]),(1-value[2])*(1-value[3])}; + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + init(); + int width = raster.getWidth(); + int height = raster.getHeight(); + + ByteBuffer buffer = ByteBuffer.allocate(raster.getRowBytes() * height); + raster.copyPixelsToBuffer(buffer); + final byte[] output = buffer.array(); + + int[] src = new int[width]; + int[] out = new int[width]; + int numberOfComponents = getNumberOfComponents(); + float[] value = new float[numberOfComponents]; + for (int y = 0; y < height; y++) + { + raster.getPixels(src,0,width,0,y,width,1); + for (int x = 0; x < width; x++) + { + for (int i=0;i DEVICEN_ATTRIBUTES) + { + attributes = new PDDeviceNAttributes((COSDictionary)array.getObject(DEVICEN_ATTRIBUTES)); + } + initColorConversionCache(); + + // set initial color space + int n = getNumberOfComponents(); + float[] initial = new float[n]; + for (int i = 0; i < n; i++) + { + initial[i] = 1; + } + initialColor = new PDColor(initial, this); + } + + // initializes the color conversion cache + private void initColorConversionCache() throws IOException + { + // there's nothing to cache for non-attribute spaces + if (attributes == null) + { + return; + } + + // colorant names + List colorantNames = getColorantNames(); + numColorants = colorantNames.size(); + + // process components + colorantToComponent = new int[numColorants]; + for (int c = 0; c < numColorants; c++) + { + colorantToComponent[c] = -1; + } + + if (attributes.getProcess() != null) + { + List components = attributes.getProcess().getComponents(); + + // map each colorant to the corresponding process component (if any) + for (int c = 0; c < numColorants; c++) + { + colorantToComponent[c] = components.indexOf(colorantNames.get(c)); + } + + // process color space + processColorSpace = attributes.getProcess().getColorSpace(); + } + + // spot colorants + spotColorSpaces = new PDSeparation[numColorants]; + + // spot color spaces + Map spotColorants = attributes.getColorants(); + + // map each colorant to the corresponding spot color space + for (int c = 0; c < numColorants; c++) + { + String name = colorantNames.get(c); + PDSeparation spot = spotColorants.get(name); + if (spot != null) + { + // spot colorant + spotColorSpaces[c] = spot; + + // spot colors may replace process colors with same name + // providing that the subtype is not NChannel. + if (!isNChannel()) + { + colorantToComponent[c] = -1; + } + } + else + { + // process colorant + spotColorSpaces[c] = null; + } + } + } + +// @Override +// public BufferedImage toRGBImage(WritableRaster raster) throws IOException +// { +// if (attributes != null) +// { +// return toRGBWithAttributes(raster); +// } +// else +// { +// return toRGBWithTintTransform(raster); +// } +// } + + // + // WARNING: this method is performance sensitive, modify with care! + // +// private BufferedImage toRGBWithAttributes(WritableRaster raster) throws IOException +// { +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// +// BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// WritableRaster rgbRaster = rgbImage.getRaster(); +// +// // white background +// Graphics2D g = rgbImage.createGraphics(); +// g.setBackground(Color.WHITE); +// g.clearRect(0, 0, width, height); +// g.dispose(); +// +// // look up each colorant +// for (int c = 0; c < numColorants; c++) +// { +// PDColorSpace componentColorSpace; +// if (colorantToComponent[c] >= 0) +// { +// // process color +// componentColorSpace = processColorSpace; +// } +// else if (spotColorSpaces[c] == null) +// { +// // TODO this happens in the Altona Visual test, is there a better workaround? +// // missing spot color, fallback to using tintTransform +// return toRGBWithTintTransform(raster); +// } +// else +// { +// // spot color +// componentColorSpace = spotColorSpaces[c]; +// } +// +// // copy single-component to its own raster in the component color space +// WritableRaster componentRaster = Raster.createBandedRaster(DataBuffer.TYPE_BYTE, +// width, height, componentColorSpace.getNumberOfComponents(), new Point(0, 0)); +// +// int[] samples = new int[numColorants]; +// int[] componentSamples = new int[componentColorSpace.getNumberOfComponents()]; +// boolean isProcessColorant = colorantToComponent[c] >= 0; +// int componentIndex = colorantToComponent[c]; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, samples); +// if (isProcessColorant) +// { +// // process color +// componentSamples[componentIndex] = samples[c]; +// } +// else +// { +// // spot color +// componentSamples[0] = samples[c]; +// } +// componentRaster.setPixel(x, y, componentSamples); +// } +// } +// +// // convert single-component raster to RGB +// BufferedImage rgbComponentImage = componentColorSpace.toRGBImage(componentRaster); +// WritableRaster rgbComponentRaster = rgbComponentImage.getRaster(); +// +// // combine the RGB component with the RGB composite raster +// int[] rgbChannel = new int[3]; +// int[] rgbComposite = new int[3]; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// rgbComponentRaster.getPixel(x, y, rgbChannel); +// rgbRaster.getPixel(x, y, rgbComposite); +// +// // multiply (blend mode) +// rgbChannel[0] = rgbChannel[0] * rgbComposite[0] >> 8; +// rgbChannel[1] = rgbChannel[1] * rgbComposite[1] >> 8; +// rgbChannel[2] = rgbChannel[2] * rgbComposite[2] >> 8; +// +// rgbRaster.setPixel(x, y, rgbChannel); +// } +// } +// } +// +// return rgbImage; +// } + + // + // WARNING: this method is performance sensitive, modify with care! + // +// private BufferedImage toRGBWithTintTransform(WritableRaster raster) throws IOException +// { +// // cache color mappings +// Map map1 = new HashMap<>(); +// String key; +// StringBuilder keyBuilder = new StringBuilder(); +// +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// +// // use the tint transform to convert the sample into +// // the alternate color space (this is usually 1:many) +// BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// WritableRaster rgbRaster = rgbImage.getRaster(); +// int[] rgb = new int[3]; +// int numSrcComponents = getColorantNames().size(); +// float[] src = new float[numSrcComponents]; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, src); +// // use a string representation as key +// keyBuilder.append(src[0]); +// for (int s = 1; s < numSrcComponents; s++) +// { +// keyBuilder.append('#').append(src[s]); +// } +// key = keyBuilder.toString(); +// keyBuilder.setLength(0); +// int[] pxl = map1.get(key); +// if (pxl != null) +// { +// rgbRaster.setPixel(x, y, pxl); +// continue; +// } +// // scale to 0..1 +// for (int s = 0; s < numSrcComponents; s++) +// { +// src[s] = src[s] / 255; +// } +// +// // convert to alternate color space via tint transform +// float[] result = tintTransform.eval(src); +// +// // convert from alternate color space to RGB +// float[] rgbFloat = alternateColorSpace.toRGB(result); +// +// // scale to 0..255 +// rgb[0] = (int) (rgbFloat[0] * 255f); +// rgb[1] = (int) (rgbFloat[1] * 255f); +// rgb[2] = (int) (rgbFloat[2] * 255f); +// +// // must clone because rgb is reused +// map1.put(key, rgb.clone()); +// +// rgbRaster.setPixel(x, y, rgb); +// } +// } +// return rgbImage; +// } + + @Override + public float[] toRGB(float[] value) throws IOException + { + if (attributes != null) + { + return toRGBWithAttributes(value); + } + else + { + return toRGBWithTintTransform(value); + } + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + if (raster.getConfig() != Bitmap.Config.ALPHA_8) + { + Log.e("PdfBox-Android", "Raster in PDDeviceN was not ALPHA_8"); + } + + int width = raster.getWidth(); + int height = raster.getHeight(); + int[] imgPixels = new int[width]; + + Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int[] outPixels = new int[width]; + + int rgb; + float[] value = new float[1]; + for (int y = 0; y < height; y++) + { + raster.getPixels(imgPixels, 0, width, 0, y, width, 1); + for (int x = 0; x < width; x++) + { + value[0] = Color.alpha(imgPixels[x])/255.f; + float[] rgbList = toRGB(value); + rgb = Color.argb(255, (int)(rgbList[0]*255), (int)(rgbList[1]*255), (int)(rgbList[2]*255)); + outPixels[x] = rgb; + } + image.setPixels(outPixels, 0, width, 0, y, width, 1); + } + + return image; + } + + private float[] toRGBWithAttributes(float[] value) throws IOException + { +// Log.w("ceshi",String.format("value:%f, %f, %f",value[0],value[1],value[2])); + float[] rgbValue = new float[] { 1, 1, 1 }; + // look up each colorant + for (int c = 0; c < numColorants; c++) + { + PDColorSpace componentColorSpace; + boolean isProcessColorant = colorantToComponent[c] >= 0; + if (isProcessColorant) + { +// Log.w("ceshi","processColorSpace=="+processColorSpace.getClass().getSimpleName()); + // process color + componentColorSpace = processColorSpace; + } + else if (spotColorSpaces[c] == null) + { + // TODO this happens in the Altona Visual test, is there a better workaround? + // missing spot color, fallback to using tintTransform + return toRGBWithTintTransform(value); + } + else + { + // spot color + componentColorSpace = spotColorSpaces[c]; + } + + // get the single component + float[] componentSamples = new float[componentColorSpace.getNumberOfComponents()]; + + if (isProcessColorant) + { + // process color + int componentIndex = colorantToComponent[c]; + componentSamples[componentIndex] = value[c]; + } + else + { + // spot color + componentSamples[0] = value[c]; + } + + // convert single component to RGB +// float[] rgbComponent = new float[3]; +// rgbComponent[0] = 1-componentSamples[0]; +// rgbComponent[1] = 1-componentSamples[1]; +// rgbComponent[2] = 1-componentSamples[2]; +// Log.w("ceshi","componentColorSpace=="+componentColorSpace.getClass().getSimpleName()); + float[] rgbComponent = componentColorSpace.toRGB(componentSamples); + + // combine the RGB component value with the RGB composite value + + // multiply (blend mode) + rgbValue[0] *= rgbComponent[0]; + rgbValue[1] *= rgbComponent[1]; + rgbValue[2] *= rgbComponent[2]; + +// Log.w("ceshi",String.format("r:%f,g:%f,b:%f",rgbValue[0],rgbValue[1],rgbValue[2])); + } + + return rgbValue; + } + + private float[] toRGBWithTintTransform(float[] value) throws IOException + { + // use the tint transform to convert the sample into + // the alternate color space (this is usually 1:many) + float[] altValue = tintTransform.eval(value); + + // convert the alternate color space to RGB + return alternateColorSpace.toRGB(altValue); + } + +// @Override +// public BufferedImage toRawImage(WritableRaster raster) +// { +// // We don't know how to convert that. +// return null; +// } + + /** + * Returns true if this color space has the NChannel subtype. + * @return true if subtype is NChannel + */ + public boolean isNChannel() + { + return attributes != null && attributes.isNChannel(); + } + + @Override + public String getName() + { + return COSName.DEVICEN.getName(); + } + + @Override + public final int getNumberOfComponents() + { + return getColorantNames().size(); + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) + { + int n = getNumberOfComponents(); + float[] decode = new float[n * 2]; + for (int i = 0; i < n; i++) + { + decode[i * 2 + 1] = 1; + } + return decode; + } + + @Override + public PDColor getInitialColor() + { + return initialColor; + } + + /** + * Returns the list of colorants. + * @return the list of colorants + */ + public List getColorantNames() + { + return ((COSArray) array.getObject(COLORANT_NAMES)).toCOSNameStringList(); + } + + /** + * Returns the attributes associated with the DeviceN color space. + * @return the DeviceN attributes + */ + public PDDeviceNAttributes getAttributes() + { + return attributes; + } + + /** + * Sets the list of colorants + * @param names the list of colorants + */ + public void setColorantNames(List names) + { +// COSArray namesArray = COSArray.ofCOSNames(names); +// array.set(COLORANT_NAMES, namesArray); + } + + /** + * Sets the color space attributes. + * If null is passed in then all attribute will be removed. + * @param attributes the color space attributes, or null + */ + public void setAttributes(PDDeviceNAttributes attributes) + { + this.attributes = attributes; + if (attributes == null) + { + array.remove(DEVICEN_ATTRIBUTES); + } + else + { + // make sure array is large enough + while (array.size() <= DEVICEN_ATTRIBUTES) + { + array.add(COSNull.NULL); + } + array.set(DEVICEN_ATTRIBUTES, attributes.getCOSDictionary()); + } + } + + /** + * This will get the alternate color space for this separation. + * + * @return The alternate color space. + * + * @throws IOException If there is an error getting the alternate color + * space. + */ + public PDColorSpace getAlternateColorSpace() throws IOException + { + if (alternateColorSpace == null) + { + alternateColorSpace = PDColorSpace.create(array.getObject(ALTERNATE_CS)); + } + return alternateColorSpace; + } + + /** + * This will set the alternate color space. + * + * @param cs The alternate color space. + */ + public void setAlternateColorSpace(PDColorSpace cs) + { + alternateColorSpace = cs; + COSBase space = null; + if (cs != null) + { + space = cs.getCOSObject(); + } + array.set(ALTERNATE_CS, space); + } + + /** + * This will get the tint transform function. + * + * @return The tint transform function. + * + * @throws IOException if there is an error creating the function. + */ + public PDFunction getTintTransform() throws IOException + { + if (tintTransform == null) + { + tintTransform = PDFunction.create(array.getObject(TINT_TRANSFORM)); + } + return tintTransform; + } + + /** + * This will set the tint transform function. + * + * @param tint The tint transform function. + */ + public void setTintTransform(PDFunction tint) + { + tintTransform = tint; + array.set(TINT_TRANSFORM, tint); + } + + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(getName()); + sb.append('{'); + for (String col : getColorantNames()) + { + sb.append('\"'); + sb.append(col); + sb.append("\" "); + } + sb.append(alternateColorSpace.getName()); + sb.append(' '); + sb.append(tintTransform); + sb.append(' '); + if (attributes != null) + { + sb.append(attributes); + } + sb.append('}'); + return sb.toString(); + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java new file mode 100644 index 00000000..bcc9da95 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java @@ -0,0 +1,146 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import com.tom_roush.pdfbox.cos.COSBase; +import com.tom_roush.pdfbox.cos.COSDictionary; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.pdmodel.common.COSDictionaryMap; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public final class PDDeviceNAttributes +{ + /** + * Log instance. + */ +// private static final Log LOG = LogFactory.getLog(PDDeviceNAttributes.class); + + private final COSDictionary dictionary; + + /** + * Creates a new DeviceN colour space attributes dictionary. + */ + public PDDeviceNAttributes() + { + dictionary = new COSDictionary(); + } + + /** + * Creates a new DeviceN colour space attributes dictionary from the given dictionary. + * @param attributes a dictionary that has all of the attributes + */ + public PDDeviceNAttributes(COSDictionary attributes) + { + dictionary = attributes; + } + + /** + * Returns the underlying COS dictionary. + * @return the dictionary that this object wraps + */ + public COSDictionary getCOSDictionary() + { + return dictionary; + } + + /** + * Returns a map of colorants and their associated Separation color space. + * @return map of colorants to color spaces, never null. + * @throws IOException If there is an error reading a color space + */ + public Map getColorants() throws IOException + { + Map actuals = new HashMap<>(); + COSDictionary colorants = dictionary.getCOSDictionary(COSName.COLORANTS); + if(colorants == null) + { + colorants = new COSDictionary(); + dictionary.setItem(COSName.COLORANTS, colorants); + } + else + { + for (COSName name : colorants.keySet()) + { + COSBase value = colorants.getDictionaryObject(name); + actuals.put(name.getName(), (PDSeparation) PDColorSpace.create(value)); + } + } + return new COSDictionaryMap<>(actuals, colorants); + } + + /** + * Returns the DeviceN Process Dictionary, or null if it is missing. + * @return the DeviceN Process Dictionary, or null if it is missing. + */ + public PDDeviceNProcess getProcess() + { + COSDictionary process = dictionary.getCOSDictionary(COSName.PROCESS); + if (process == null) + { + return null; + } + return new PDDeviceNProcess(process); + } + + /** + * Returns true if this is an NChannel (PDF 1.6) color space. + * @return true if this is an NChannel color space. + */ + public boolean isNChannel() + { + return "NChannel".equals(dictionary.getNameAsString(COSName.SUBTYPE)); + } + + /** + * Sets the colorant map. + * @param colorants the map of colorants + */ + public void setColorants(Map colorants) + { + COSDictionary colorantDict = null; + if(colorants != null) + { + colorantDict = COSDictionaryMap.convert(colorants); + } + dictionary.setItem(COSName.COLORANTS, colorantDict); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(dictionary.getNameAsString(COSName.SUBTYPE)); + sb.append('{'); + PDDeviceNProcess process = getProcess(); + if (process != null) + { + sb.append(process); + sb.append(' '); + } + + Map colorants; + try + { + colorants = getColorants(); + sb.append("Colorants{"); + for (Map.Entry col : colorants.entrySet()) + { + sb.append('\"'); + sb.append(col.getKey()); + sb.append("\": "); + sb.append(col.getValue()); + sb.append(' '); + } + sb.append('}'); + } + catch (IOException e) + { +// LOG.debug("Couldn't get the colorants information - returning 'ERROR' instead'", e); + sb.append("ERROR"); + } + sb.append('}'); + return sb.toString(); + } + +} + diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceNProcess.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceNProcess.java new file mode 100644 index 00000000..e6eb17f8 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDDeviceNProcess.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSBase; +import com.tom_roush.pdfbox.cos.COSDictionary; +import com.tom_roush.pdfbox.cos.COSName; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +/** + * A DeviceN Process Dictionary + * + * @author John Hewson + */ +public class PDDeviceNProcess +{ + /** + * Log instance. + */ +// private static final Log LOG = LogFactory.getLog(PDDeviceNProcess.class); + + private final COSDictionary dictionary; + + /** + * Creates a new DeviceN Process Dictionary. + */ + public PDDeviceNProcess() + { + dictionary = new COSDictionary(); + } + + /** + * Creates a new DeviceN Process Dictionary from the given attributes. + * @param attributes a DeviceN attributes dictionary + */ + public PDDeviceNProcess(COSDictionary attributes) + { + dictionary = attributes; + } + + /** + * Returns the underlying COS dictionary. + * @return the underlying COS dictionary. + */ + public COSDictionary getCOSDictionary() + { + return dictionary; + } + + /** + * Returns the process color space + * @return the process color space + * @throws IOException if the color space cannot be read + */ + public PDColorSpace getColorSpace() throws IOException + { + COSBase cosColorSpace = dictionary.getDictionaryObject(COSName.COLORSPACE); + if (cosColorSpace == null) + { + return null; // TODO: return a default? + } + return PDColorSpace.create(cosColorSpace); + } + + /** + * Returns the names of the color components. + * @return the names of the color components + */ + public List getComponents() + { + COSArray cosComponents = dictionary.getCOSArray(COSName.COMPONENTS); + if (cosComponents == null) + { + return new ArrayList<>(0); + } + List components = new ArrayList<>(cosComponents.size()); + for (COSBase name : cosComponents) + { + components.add(((COSName)name).getName()); + } + return components; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder("Process{"); + try + { + sb.append(getColorSpace()); + for (String component : getComponents()) + { + sb.append(" \""); + sb.append(component); + sb.append('\"'); + } + } + catch (IOException e) + { +// LOG.debug("Couldn't get the colorants information - returning 'ERROR' instead'", e); + sb.append("ERROR"); + } + sb.append('}'); + return sb.toString(); + } + +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDICCBased.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDICCBased.java new file mode 100644 index 00000000..2dd6b818 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDICCBased.java @@ -0,0 +1,631 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.ColorSpace; +import android.util.Log; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSBase; +import com.tom_roush.pdfbox.cos.COSFloat; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.cos.COSObject; +import com.tom_roush.pdfbox.cos.COSStream; +import com.tom_roush.pdfbox.pdmodel.PDDocument; +import com.tom_roush.pdfbox.pdmodel.PDResources; +import com.tom_roush.pdfbox.pdmodel.common.PDRange; +import com.tom_roush.pdfbox.pdmodel.common.PDStream; +import com.xsooy.icc.IccUtils; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.List; + +/** + * ICCBased color spaces are based on a cross-platform color profile as defined by the + * International Color Consortium (ICC). + * + * @author Ben Litchfield + * @author John Hewson + */ +public final class PDICCBased extends PDCIEBasedColorSpace +{ + + private final PDStream stream; + private int numberOfComponents = -1; +// private ICC_Profile iccProfile; + private PDColorSpace alternateColorSpace; +// private ICC_ColorSpace awtColorSpace; + private PDColor initialColor; + private boolean isRGB = false; + // allows to force using alternate color space instead of ICC color space for performance + // reasons with LittleCMS (LCMS), see PDFBOX-4309 + // WARNING: do not activate this in a conforming reader + private boolean useOnlyAlternateColorSpace = false; +// private static final boolean IS_KCMS; + private IccUtils iccUtils; + private int colorType = TYPE_RGB; + +// static +// { +// String cmmProperty = System.getProperty("sun.java2d.cmm"); +// boolean result = false; +// if ("sun.java2d.cmm.kcms.KcmsServiceProvider".equals(cmmProperty)) +// { +// try +// { +// Class.forName("sun.java2d.cmm.kcms.KcmsServiceProvider"); +// result = true; +// } +// catch (ClassNotFoundException e) +// { +// // KCMS not available +// } +// } +// // else maybe KCMS was available, but not wished +// IS_KCMS = result; +// } + + /** + * Creates a new ICC color space with an empty stream. + * @param doc the document to store the ICC data + */ + public PDICCBased(PDDocument doc) + { + array = new COSArray(); + array.add(COSName.ICCBASED); + stream = new PDStream(doc); + array.add(stream); + } + + /** + * Creates a new ICC color space using the PDF array. + * + * @param iccArray the ICC stream object. + * @throws IOException if there is an error reading the ICC profile or if the parameter is + * invalid. + */ + private PDICCBased(COSArray iccArray) throws IOException + { + useOnlyAlternateColorSpace = System + .getProperty("org.apache.pdfbox.rendering.UseAlternateInsteadOfICCColorSpace") != null; + array = iccArray; + stream = new PDStream((COSStream) iccArray.getObject(1)); + loadICCProfile(); + } + + /** + * Creates a new ICC color space using the PDF array, optionally using a resource cache. + * + * @param iccArray the ICC stream object. + * @param resources resources to use as cache, or null for no caching. + * @return an ICC color space. + * @throws IOException if there is an error reading the ICC profile or if the parameter is + * invalid. + */ + public static PDICCBased create(COSArray iccArray, PDResources resources) throws IOException + { + checkArray(iccArray); + COSBase base = iccArray.get(1); + COSObject indirect = null; + if (base instanceof COSObject) + { + indirect = (COSObject) base; + } + if (indirect != null && resources != null && resources.getResourceCache() != null) + { + PDColorSpace space = resources.getResourceCache().getColorSpace(indirect); + if (space instanceof PDICCBased) + { + return (PDICCBased) space; + } + } + PDICCBased space = new PDICCBased(iccArray); + if (indirect != null && resources != null && resources.getResourceCache() != null) + { + resources.getResourceCache().put(indirect, space); + } + return space; + } + + private static void checkArray(COSArray iccArray) throws IOException + { + if (iccArray.size() < 2) + { + throw new IOException("ICCBased colorspace array must have two elements"); + } + if (!(iccArray.getObject(1) instanceof COSStream)) + { + throw new IOException("ICCBased colorspace array must have a stream as second element"); + } + } + + @Override + public String getName() + { + return COSName.ICCBASED.getName(); + } + + /** + * Get the underlying ICC profile stream. + * @return the underlying ICC profile stream + */ + public PDStream getPDStream() + { + return stream; + } + + private static int intFromBigEndian(byte[] array, int index) { + return (((array[index] & 0xff) << 24) | + ((array[index+1] & 0xff) << 16) | + ((array[index+2] & 0xff) << 8) | + (array[index+3] & 0xff)); + } + + private byte[] getProfileDataFromStream(InputStream s) throws IOException { + BufferedInputStream bis = new BufferedInputStream(s); + bis.mark(128); // 128 is the length of the ICC profile header + + int result = 0; + byte[] header = new byte[128]; + result = bis.read(header); +// byte[] header = bis.readNBytes(128); + if (result<128 || header[36] != 0x61 || header[37] != 0x63 || + header[38] != 0x73 || header[39] != 0x70) { + return null; /* not a valid profile */ + } + int profileSize = intFromBigEndian(header, 0); + bis.reset(); + byte[] profile = new byte[profileSize]; + try { + if (bis.read(profile) == profileSize) + return profile; + else + throw new IOException("profile load error"); + } catch (OutOfMemoryError e) { + throw new IOException("Color profile is too big"); + } + } + + /** + * Load the ICC profile, or init alternateColorSpace color space. + */ + private void loadICCProfile() throws IOException + { + if (useOnlyAlternateColorSpace) + { + try + { + fallbackToAlternateColorSpace(null); + return; + } + catch (IOException e) + { + Log.w("PdfBox-Android","Error initializing alternate color space: " + e.getLocalizedMessage()); + } + } + try + { + InputStream input = this.stream.createInputStream(); + // if the embedded profile is sRGB then we can use Java's built-in profile, which + // results in a large performance gain as it's our native color space, see PDFBOX-2587 +// ICC_Profile profile; + iccUtils = new IccUtils(); + PDDeviceCMYK.INSTANCE.initDone = false; + colorType = IccUtils.getIccColorType(iccUtils.loadProfileByData(getProfileDataFromStream(input))); + Log.w("ceshi","PDICCBased_colorType=="+colorType); + switch (colorType) { + case TYPE_GRAY: + numberOfComponents = 1; + break; + case TYPE_RGB: + numberOfComponents = 3; + isRGB = true; + break; + case TYPE_CMYK: + numberOfComponents = 4; + break; + } + + // set initial colour + float[] initial = new float[getNumberOfComponents()]; + for (int c = 0; c < initial.length; c++) + { + initial[c] = Math.max(0, getRangeForComponent(c).getMin()); + } + initialColor = new PDColor(initial, this); + + } + catch (IllegalArgumentException | + ArrayIndexOutOfBoundsException | IOException e) + { + fallbackToAlternateColorSpace(e); + } + } + + private void fallbackToAlternateColorSpace(Exception e) throws IOException + { + iccUtils = null; +// awtColorSpace = null; + alternateColorSpace = getAlternateColorSpace(); + if (alternateColorSpace.equals(PDDeviceRGB.INSTANCE)) + { + isRGB = true; + } + if (e != null) + { + Log.w("PdfBox-Android","Can't read embedded ICC profile (" + e.getLocalizedMessage() + + "), using alternate color space: " + alternateColorSpace.getName()); + } + initialColor = alternateColorSpace.getInitialColor(); + } + + /** + * Returns true if the given profile represents sRGB. + * (unreliable on the data of ColorSpace.CS_sRGB in openjdk) + */ +// private boolean is_sRGB(ICC_Profile profile) +// { +// byte[] bytes = Arrays.copyOfRange(profile.getData(ICC_Profile.icSigHead), +// ICC_Profile.icHdrModel, ICC_Profile.icHdrModel + 7); +// String deviceModel = new String(bytes, StandardCharsets.US_ASCII).trim(); +// return deviceModel.equals("sRGB"); +// } + + // PDFBOX-4114: fix profile that has the wrong display class, + // as done by Harald Kuhr in twelvemonkeys JPEGImageReader.ensureDisplayProfile() +// private static ICC_Profile ensureDisplayProfile(ICC_Profile profile) +// { +// if (profile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) +// { +// byte[] profileData = profile.getData(); // Need to clone entire profile, due to a OpenJDK bug +// +// if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) +// { +// LOG.warn("ICC profile is Perceptual, ignoring, treating as Display class"); +// intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); +// return ICC_Profile.getInstance(profileData); +// } +// } +// return profile; +// } + + private static void intToBigEndian(int value, byte[] array, int index) + { + array[index] = (byte) (value >> 24); + array[index + 1] = (byte) (value >> 16); + array[index + 2] = (byte) (value >> 8); + array[index + 3] = (byte) (value); + } + + @Override + public float[] toRGB(float[] value) throws IOException + { + if (isRGB) + { + return value; + } + if (iccUtils!=null) { + float[] rgb = new float[3]; + iccUtils.applyCmyk(value,rgb); + return rgb; + } +// if (awtColorSpace != null) +// { + // PDFBOX-2142: clamp bad values + // WARNING: toRGB is very slow when used with LUT-based ICC profiles +// return awtColorSpace.toRGB(clampColors(awtColorSpace, value)); +// } + else + { + return alternateColorSpace.toRGB(value); + } + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + if (isRGB) { + return raster; + } + int width = raster.getWidth(); + int height = raster.getHeight(); + Bitmap rgbImage; + if (raster.getConfig() == Bitmap.Config.ARGB_8888) { + rgbImage =raster; + } else { + rgbImage = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); + } + ByteBuffer buffer = ByteBuffer.allocate(raster.getRowBytes() * height); + raster.copyPixelsToBuffer(buffer); + final byte[] output = buffer.array(); + + int[] src = new int[width]; + int[] out = new int[width]; + int numberOfComponents = getNumberOfComponents(); + float[] value = new float[numberOfComponents]; + for (int y = 0; y < height; y++) + { + raster.getPixels(src,0,width,0,y,width,1); + for (int x = 0; x < width; x++) + { + int color; + if (colorType==TYPE_GRAY) { + color = Color.argb(255,output[(x+y*width)*numberOfComponents] & 0xff,output[(x+y*width)*numberOfComponents] & 0xff,output[(x+y*width)*numberOfComponents] & 0xff); + } else { + for (int i=0;i maxValue ? maxValue : value[i]); +// } +// return result; +// } + +// @Override +// public BufferedImage toRGBImage(WritableRaster raster) throws IOException +// { +// if (awtColorSpace != null) +// { +// return toRGBImageAWT(raster, awtColorSpace); +// } +// else +// { +// return alternateColorSpace.toRGBImage(raster); +// } +// } +// +// @Override +// public BufferedImage toRawImage(WritableRaster raster) throws IOException +// { +// if(awtColorSpace == null) +// { +// return alternateColorSpace.toRawImage(raster); +// } +// return toRawImage(raster, awtColorSpace); +// } + + @Override + public int getNumberOfComponents() + { + if (numberOfComponents < 0) + { + numberOfComponents = stream.getCOSObject().getInt(COSName.N); + + // PDFBOX-4801 correct wrong /N values +// if (iccProfile != null) +// { +// int numIccComponents = iccProfile.getNumComponents(); +// if (numIccComponents != numberOfComponents) +// { +// LOG.warn("Using " + numIccComponents + " components from ICC profile info instead of " + +// numberOfComponents + " components from /N entry"); +// numberOfComponents = numIccComponents; +// } +// } + } + return numberOfComponents; + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) + { + if (iccUtils != null) + { + int n = getNumberOfComponents(); + float[] decode = new float[n * 2]; + for (int i = 0; i < n; i++) + { + decode[i * 2] = getMinValue(colorType,i); + decode[i * 2 + 1] = getMaxValue(colorType,i); + } + return decode; + } + else + { + return alternateColorSpace.getDefaultDecode(bitsPerComponent); + } + } + + @Override + public PDColor getInitialColor() + { + return initialColor; + } + + /** + * Returns a list of alternate color spaces for non-conforming readers. + * WARNING: Do not use the information in a conforming reader. + * @return A list of alternateColorSpace color spaces. + * @throws IOException If there is an error getting the alternateColorSpace color spaces. + */ + public PDColorSpace getAlternateColorSpace() throws IOException + { + COSBase alternate = stream.getCOSObject().getDictionaryObject(COSName.ALTERNATE); + COSArray alternateArray; + if(alternate == null) + { + alternateArray = new COSArray(); + int numComponents = getNumberOfComponents(); + COSName csName; + switch (numComponents) + { + case 1: + csName = COSName.DEVICEGRAY; + break; + case 3: + csName = COSName.DEVICERGB; + break; + case 4: + csName = COSName.DEVICECMYK; + break; + default: + throw new IOException("Unknown color space number of components:" + numComponents); + } + alternateArray.add(csName); + } + else + { + if(alternate instanceof COSArray) + { + alternateArray = (COSArray)alternate; + } + else if(alternate instanceof COSName) + { + alternateArray = new COSArray(); + alternateArray.add(alternate); + } + else + { + throw new IOException("Error: expected COSArray or COSName and not " + + alternate.getClass().getName()); + } + } + return PDColorSpace.create(alternateArray); + } + + /** + * Returns the range for a certain component number. + * This will never return null. + * If it is not present then the range 0..1 will be returned. + * @param n the component number to get the range for + * @return the range for this component + */ + public PDRange getRangeForComponent(int n) + { + COSArray rangeArray = stream.getCOSObject().getCOSArray(COSName.RANGE); + if (rangeArray == null || rangeArray.size() < getNumberOfComponents() * 2) + { + return new PDRange(); // 0..1 + } + return new PDRange(rangeArray, n); + } + + /** + * Returns the metadata stream for this object, or null if there is no metadata stream. + * @return the metadata stream, or null if there is none + */ + public COSStream getMetadata() + { + return stream.getCOSObject().getCOSStream(COSName.METADATA); + } + + /** + * Returns the type of the color space in the ICC profile. If the ICC profile is invalid, the + * type of the alternate colorspace is returned, which will be one of + * {@link #TYPE_GRAY TYPE_GRAY}, {@link #TYPE_RGB TYPE_RGB}, + * {@link #TYPE_CMYK TYPE_CMYK}, or -1 if that one is invalid. + * + * @return an ICC color space type. and the static values of + * {@link ColorSpace} for more details. + */ + public int getColorSpaceType() + { + if (iccUtils!=null) { + return colorType; + } +// if (iccProfile != null) +// { +// return iccProfile.getColorSpaceType(); +// } + + // if the ICC Profile could not be read + switch (alternateColorSpace.getNumberOfComponents()) + { + case 1: + return TYPE_GRAY; + case 3: + return TYPE_RGB; + case 4: + return TYPE_CMYK; + default: + // should not happen as all ICC color spaces in PDF must have 1,3, or 4 components + return -1; + } + } + + /** + * Sets the list of alternateColorSpace color spaces. + * + * @param list the list of color space objects + */ + public void setAlternateColorSpaces(List list) + { + COSArray altArray = null; + if(list != null) + { + altArray = new COSArray(list); + } + stream.getCOSObject().setItem(COSName.ALTERNATE, altArray); + } + + /** + * Sets the range for this color space. + * @param range the new range for the a component + * @param n the component to set the range for + */ + public void setRangeForComponent(PDRange range, int n) + { + COSArray rangeArray = stream.getCOSObject().getCOSArray(COSName.RANGE); + if (rangeArray == null) + { + rangeArray = new COSArray(); + stream.getCOSObject().setItem(COSName.RANGE, rangeArray); + } + // extend range array with default values if needed + while (rangeArray.size() < (n + 1) * 2) + { + rangeArray.add(new COSFloat(0)); + rangeArray.add(new COSFloat(1)); + } + rangeArray.set(n*2, new COSFloat(range.getMin())); + rangeArray.set(n*2+1, new COSFloat(range.getMax())); + } + + /** + * Sets the metadata stream that is associated with this color space. + * @param metadata the new metadata stream + */ + public void setMetadata(COSStream metadata) + { + stream.getCOSObject().setItem(COSName.METADATA, metadata); + } + + /** + * Internal accessor to support indexed raw images. + * @return true if this colorspace is sRGB. + */ + boolean isSRGB() + { + return isRGB; + } + + @Override + public String toString() + { + return getName() + "{numberOfComponents: " + getNumberOfComponents() + "}"; + } +} + diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDIndexed.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDIndexed.java new file mode 100644 index 00000000..3f28e3fd --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDIndexed.java @@ -0,0 +1,384 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.util.Log; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSBase; +import com.tom_roush.pdfbox.cos.COSInteger; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.cos.COSNull; +import com.tom_roush.pdfbox.cos.COSNumber; +import com.tom_roush.pdfbox.cos.COSStream; +import com.tom_roush.pdfbox.cos.COSString; +import com.tom_roush.pdfbox.pdmodel.PDResources; +import com.tom_roush.pdfbox.pdmodel.common.PDStream; + +import java.io.IOException; + + +/** + * An Indexed colour space specifies that an area is to be painted using a colour table + * of arbitrary colours from another color space. + * + * @author John Hewson + * @author Ben Litchfield + */ +public final class PDIndexed extends PDSpecialColorSpace +{ + private final PDColor initialColor = new PDColor(new float[] { 0 }, this); + + private PDColorSpace baseColorSpace = null; + + // cached lookup data + private byte[] lookupData; + private float[][] colorTable; + private int actualMaxIndex; + private int[][] rgbColorTable; + + /** + * Creates a new Indexed color space. + * Default DeviceRGB, hival 255. + */ + public PDIndexed() + { + array = new COSArray(); + array.add(COSName.INDEXED); + array.add(COSName.DEVICERGB); + array.add(COSInteger.get(255)); + array.add(COSNull.NULL); + } + + /** + * Creates a new indexed color space from the given PDF array. + * @param indexedArray the array containing the indexed parameters + * @throws IOException + */ + public PDIndexed(COSArray indexedArray) throws IOException + { + this(indexedArray, null); + } + + /** + * Creates a new indexed color space from the given PDF array. + * @param indexedArray the array containing the indexed parameters + * @param resources the resources, can be null. Allows to use its cache for the colorspace. + * @throws IOException + */ + public PDIndexed(COSArray indexedArray, PDResources resources) throws IOException + { + array = indexedArray; + // don't call getObject(1), we want to pass a reference if possible + // to profit from caching (PDFBOX-4149) + baseColorSpace = PDColorSpace.create(array.get(1), resources); +// Log.w("ceshi","PDIndexed---baseColorSpace=="+baseColorSpace.getClass().getSimpleName()); + readColorTable(); + initRgbColorTable(); + } + + @Override + public String getName() + { + return COSName.INDEXED.getName(); + } + + @Override + public int getNumberOfComponents() + { + return 1; + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) + { + return new float[] { 0, (float)Math.pow(2, bitsPerComponent) - 1 }; + } + + @Override + public PDColor getInitialColor() + { + return initialColor; + } + + // + // WARNING: this method is performance sensitive, modify with care! + // + private void initRgbColorTable() throws IOException + { + int numBaseComponents = baseColorSpace.getNumberOfComponents(); + + // convert the color table into a 1-row BufferedImage in the base color space, + // using a writable raster for high performance +// WritableRaster baseRaster; +// try +// { +// baseRaster = Raster.createBandedRaster(DataBuffer.TYPE_BYTE, +// actualMaxIndex + 1, 1, numBaseComponents, new Point(0, 0)); +// } +// catch (IllegalArgumentException ex) +// { +// // PDFBOX-4503: when stream is empty or null +// throw new IOException(ex); +// } + +// int[] base = new int[numBaseComponents]; + rgbColorTable = new int[actualMaxIndex + 1][numBaseComponents]; + for (int i = 0, n = actualMaxIndex; i <= n; i++) + { + float[] rgb = baseColorSpace.toRGB(colorTable[i]); + for (int c = 0; c < 3; c++) + { + rgbColorTable[i][c] = (int)(rgb[c]*255); +// rgbColorTable[i][c] = (int)(colorTable[i][c] * 255f); +// base[c] = (int)(colorTable[i][c] * 255f); + } +// Log.w("ceshi",String.format("r:%d,g:%d,b:%d",rgbColorTable[i][0],rgbColorTable[i][1],rgbColorTable[i][2])); +// rgbColorTable[i][c] = base; +// baseRaster.setPixel(i, 0, base); + } + + // convert the base image to RGB +// BufferedImage rgbImage = baseColorSpace.toRGBImage(baseRaster); +// WritableRaster rgbRaster = rgbImage.getRaster(); + + // build an RGB lookup table from the raster + +// int[] nil = null; +// +// for (int i = 0, n = actualMaxIndex; i <= n; i++) +// { +// rgbColorTable[i] = rgbRaster.getPixel(i, 0, nil); +// } + } + + // + // WARNING: this method is performance sensitive, modify with care! + // + @Override + public float[] toRGB(float[] value) + { + if (value.length > 1) + { + throw new IllegalArgumentException("Indexed color spaces must have one color value"); + } + + // scale and clamp input value + int index = Math.round(value[0]); + index = Math.max(index, 0); + index = Math.min(index, actualMaxIndex); + + // lookup rgb + int[] rgb = rgbColorTable[index]; + return new float[] { rgb[0] / 255f, rgb[1] / 255f, rgb[2] / 255f }; + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + if (raster.getConfig() != Bitmap.Config.ALPHA_8) + { + Log.e("PdfBox-Android", "Raster in PDDeviceN was not ALPHA_8"); + } + + int width = raster.getWidth(); + int height = raster.getHeight(); + int[] imgPixels = new int[width]; + + Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int[] outPixels = new int[width]; + + for (int y = 0; y < height; y++) + { + raster.getPixels(imgPixels, 0, width, 0, y, width, 1); + for (int x = 0; x < width; x++) + { + int index = Math.min(Color.alpha(imgPixels[x]), actualMaxIndex); + int rgb = Color.argb(255, rgbColorTable[index][0],rgbColorTable[index][1], rgbColorTable[index][2]); + outPixels[x] = rgb; + } + image.setPixels(outPixels, 0, width, 0, y, width, 1); + } + + return image; + } + + public Bitmap toRGBImage(int[] raster,int width,int height) throws IOException { + Bitmap rgbImage = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + int index = Math.min(raster[x+y*width], actualMaxIndex); + int color = Color.alpha(0); + if (index>=0) { + color = Color.argb(255,rgbColorTable[index][0],rgbColorTable[index][1],rgbColorTable[index][2]); + } + rgbImage.setPixel(x,y,color); + } + } + return rgbImage; + } + // + // WARNING: this method is performance sensitive, modify with care! + // +// @Override +// public BufferedImage toRGBImage(WritableRaster raster) throws IOException +// { +// // use lookup table +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// +// BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// WritableRaster rgbRaster = rgbImage.getRaster(); +// +// int[] src = new int[1]; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, src); +// +// // lookup +// int index = Math.min(src[0], actualMaxIndex); +// rgbRaster.setPixel(x, y, rgbColorTable[index]); +// } +// } +// +// return rgbImage; +// } + +// @Override +// public BufferedImage toRawImage(WritableRaster raster) +// { +// // We can only convert sRGB index colorspaces, depending on the base colorspace +// if (baseColorSpace instanceof PDICCBased && ((PDICCBased) baseColorSpace).isSRGB()) +// { +// byte[] r = new byte[colorTable.length]; +// byte[] g = new byte[colorTable.length]; +// byte[] b = new byte[colorTable.length]; +// for (int i = 0; i < colorTable.length; i++) +// { +// r[i] = (byte) ((int) (colorTable[i][0] * 255) & 0xFF); +// g[i] = (byte) ((int) (colorTable[i][1] * 255) & 0xFF); +// b[i] = (byte) ((int) (colorTable[i][2] * 255) & 0xFF); +// } +// ColorModel colorModel = new IndexColorModel(8, colorTable.length, r, g, b); +// return new BufferedImage(colorModel, raster, false, null); +// } +// +// // We can't handle all other cases at the moment. +// return null; +// } + + /** + * Returns the base color space. + * @return the base color space. + */ + public PDColorSpace getBaseColorSpace() + { + return baseColorSpace; + } + + // returns "hival" array element + private int getHival() + { + return ((COSNumber) array.getObject(2)).intValue(); + } + + // reads the lookup table data from the array + private void readLookupData() throws IOException + { + if (lookupData == null) + { + COSBase lookupTable = array.getObject(3); + if (lookupTable instanceof COSString) + { + lookupData = ((COSString) lookupTable).getBytes(); + } + else if (lookupTable instanceof COSStream) + { + lookupData = new PDStream((COSStream)lookupTable).toByteArray(); + } + else if (lookupTable == null) + { + lookupData = new byte[0]; + } + else + { + throw new IOException("Error: Unknown type for lookup table " + lookupTable); + } + } + } + + // + // WARNING: this method is performance sensitive, modify with care! + // + private void readColorTable() throws IOException + { + readLookupData(); + + int maxIndex = Math.min(getHival(), 255); + int numComponents = baseColorSpace.getNumberOfComponents(); + + // some tables are too short + if (lookupData.length / numComponents < maxIndex + 1) + { + maxIndex = lookupData.length / numComponents - 1; + } + actualMaxIndex = maxIndex; // TODO "actual" is ugly, tidy this up + + colorTable = new float[maxIndex + 1][numComponents]; + for (int i = 0, offset = 0; i <= maxIndex; i++) + { + for (int c = 0; c < numComponents; c++) + { + colorTable[i][c] = (lookupData[offset] & 0xff) / 255f; + offset++; + } + } + } + + /** + * Sets the base color space. + * @param base the base color space + */ + public void setBaseColorSpace(PDColorSpace base) + { + array.set(1, base.getCOSObject()); + baseColorSpace = base; + } + + /** + * Sets the highest value that is allowed. This cannot be higher than 255. + * @param high the highest value for the lookup table + */ + public void setHighValue(int high) + { + array.set(2, high); + } + + @Override + public String toString() + { + return "Indexed{base:" + baseColorSpace + " " + + "hival:" + getHival() + " " + + "lookup:(" + colorTable.length + " entries)}"; + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDLab.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDLab.java new file mode 100644 index 00000000..f4bc2d75 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDLab.java @@ -0,0 +1,255 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import android.graphics.Bitmap; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSFloat; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.pdmodel.common.PDRange; + +import java.io.IOException; + +/** + * A Lab colour space is a CIE-based ABC colour space with two transformation stages. + * + * @author Ben Litchfield + * @author John Hewson + */ +public final class PDLab extends PDCIEDictionaryBasedColorSpace +{ + private PDColor initialColor; + + /** + * Creates a new Lab color space. + */ + public PDLab() + { + super(COSName.LAB); + } + + /** + * Creates a new Lab color space from a PDF array. + * @param lab the color space array + */ + public PDLab(COSArray lab) + { + super(lab); + } + + @Override + public String getName() + { + return COSName.LAB.getName(); + } + + // + // WARNING: this method is performance sensitive, modify with care! + // +// @Override +// public BufferedImage toRGBImage(WritableRaster raster) throws IOException +// { +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// +// BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// WritableRaster rgbRaster = rgbImage.getRaster(); +// +// PDRange aRange = getARange(); +// PDRange bRange = getBRange(); +// float minA = aRange.getMin(); +// float maxA = aRange.getMax(); +// float minB = bRange.getMin(); +// float maxB = bRange.getMax(); +// float deltaA = maxA - minA; +// float deltaB = maxB - minB; +// +// // always three components: ABC +// float[] abc = new float[3]; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, abc); +// +// // 0..255 -> 0..1 +// abc[0] /= 255; +// abc[1] /= 255; +// abc[2] /= 255; +// +// // scale to range +// abc[0] *= 100; +// abc[1] = minA + abc[1] * deltaA; +// abc[2] = minB + abc[2] * deltaB; +// +// float[] rgb = toRGB(abc); +// +// // 0..1 -> 0..255 +// rgb[0] *= 255; +// rgb[1] *= 255; +// rgb[2] *= 255; +// +// rgbRaster.setPixel(x, y, rgb); +// } +// } +// +// return rgbImage; +// } + +// @Override +// public BufferedImage toRawImage(WritableRaster raster) +// { +// // Not handled at the moment. +// return null; +// } + + @Override + public float[] toRGB(float[] value) + { + // CIE LAB to RGB, see http://en.wikipedia.org/wiki/Lab_color_space + + // L* + float lstar = (value[0] + 16f) * (1f / 116f); + + // TODO: how to use the blackpoint? scale linearly between black & white? + + // XYZ + float x = wpX * inverse(lstar + value[1] * (1f / 500f)); + float y = wpY * inverse(lstar); + float z = wpZ * inverse(lstar - value[2] * (1f / 200f)); + + return convXYZtoRGB(x, y, z); + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + return null; + } + + // reverse transformation (f^-1) + private float inverse(float x) + { + if (x > 6.0 / 29.0) + { + return x * x * x; + } + else + { + return (108f / 841f) * (x - (4f / 29f)); + } + } + + @Override + public int getNumberOfComponents() + { + return 3; + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) + { + PDRange a = getARange(); + PDRange b = getBRange(); + return new float[] { 0, 100, a.getMin(), a.getMax(), b.getMin(), b.getMax() }; + } + + @Override + public PDColor getInitialColor() + { + if (initialColor == null) + { + initialColor = new PDColor(new float[] { + 0, + Math.max(0, getARange().getMin()), + Math.max(0, getBRange().getMin()) }, + this); + } + return initialColor; + } + + /** + * creates a range array with default values (-100..100 -100..100). + * @return the new range array. + */ + private COSArray getDefaultRangeArray() + { + COSArray range = new COSArray(); + range.add(new COSFloat(-100)); + range.add(new COSFloat(100)); + range.add(new COSFloat(-100)); + range.add(new COSFloat(100)); + return range; + } + + /** + * This will get the valid range for the "a" component. + * If none is found then the default will be returned, which is -100..100. + * @return the "a" range. + */ + public PDRange getARange() + { + COSArray rangeArray = dictionary.getCOSArray(COSName.RANGE); + if (rangeArray == null) + { + rangeArray = getDefaultRangeArray(); + } + return new PDRange(rangeArray, 0); + } + + /** + * This will get the valid range for the "b" component. + * If none is found then the default will be returned, which is -100..100. + * @return the "b" range. + */ + public PDRange getBRange() + { + COSArray rangeArray = dictionary.getCOSArray(COSName.RANGE); + if (rangeArray == null) + { + rangeArray = getDefaultRangeArray(); + } + return new PDRange(rangeArray, 1); + } + + /** + * This will set the a range for the "a" component. + * @param range the new range for the "a" component, + * or null if defaults (-100..100) are to be set. + */ + public void setARange(PDRange range) + { + setComponentRangeArray(range, 0); + } + + /** + * This will set the "b" range for this color space. + * @param range the new range for the "b" component, + * or null if defaults (-100..100) are to be set. + */ + public void setBRange(PDRange range) + { + setComponentRangeArray(range, 2); + } + + private void setComponentRangeArray(PDRange range, int index) + { + COSArray rangeArray = dictionary.getCOSArray(COSName.RANGE); + if (rangeArray == null) + { + rangeArray = getDefaultRangeArray(); + } + if (range == null) + { + // reset to defaults + rangeArray.set(index, new COSFloat(-100)); + rangeArray.set(index + 1, new COSFloat(100)); + } + else + { + rangeArray.set(index, new COSFloat(range.getMin())); + rangeArray.set(index + 1, new COSFloat(range.getMax())); + } + dictionary.setItem(COSName.RANGE, rangeArray); + initialColor = null; + } + +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDPattern.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDPattern.java new file mode 100644 index 00000000..f31eb358 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDPattern.java @@ -0,0 +1,80 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import android.graphics.Bitmap; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.pdmodel.PDResources; +import com.tom_roush.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern; + +import java.io.IOException; + +public class PDPattern extends PDSpecialColorSpace{ + + private static final PDColor EMPTY_PATTERN = new PDColor(new float[] { }, null); + + private final PDResources resources; + + private PDColorSpace underlyingColorSpace; + /** + * Creates a new pattern color space. + * + * @param resources The current resources. + */ + public PDPattern(PDResources resources) + { + this.resources = resources; + array = new COSArray(); + array.add(COSName.PATTERN); + } + + + @Override + public String getName() { + return COSName.PATTERN.getName(); + } + + @Override + public int getNumberOfComponents() { + throw new UnsupportedOperationException(); + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) { + throw new UnsupportedOperationException(); + } + + @Override + public PDColor getInitialColor() { + return EMPTY_PATTERN; + } + + @Override + public float[] toRGB(float[] value) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + throw new UnsupportedOperationException(); + } + + public PDAbstractPattern getPattern(PDColor color) throws IOException + { + PDAbstractPattern pattern = resources.getPattern(color.getPatternName()); + if (pattern == null) + { + throw new IOException("pattern " + color.getPatternName() + " was not found"); + } + else + { + return pattern; + } + } + + @Override + public String toString() + { + return "Pattern"; + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDSeparation.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDSeparation.java new file mode 100644 index 00000000..603c22e8 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDSeparation.java @@ -0,0 +1,316 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.util.Log; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSBase; +import com.tom_roush.pdfbox.cos.COSName; +import com.tom_roush.pdfbox.cos.COSNull; +import com.tom_roush.pdfbox.pdmodel.common.function.PDFunction; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + + +/** + * A Separation color space used to specify either additional colorants or for isolating the + * control of individual colour components of a device colour space for a subtractive device. + * When such a space is the current colour space, the current colour shall be a single-component + * value, called a tint, that controls the given colorant or colour components only. + * + * @author Ben Litchfield + * @author John Hewson + */ +public class PDSeparation extends PDSpecialColorSpace +{ + private final PDColor initialColor = new PDColor(new float[] { 1 }, this); + + // array indexes + private static final int COLORANT_NAMES = 1; + private static final int ALTERNATE_CS = 2; + private static final int TINT_TRANSFORM = 3; + + // fields + private PDColorSpace alternateColorSpace = null; + private PDFunction tintTransform = null; + + /** + * Map used to speed up {@link #toRGB(float[])}. Note that this class contains three maps (this + * and the two in {@link #toRGBImage(java.awt.image.WritableRaster) } and {@link #toRGBImage2(java.awt.image.WritableRaster) + * }. The maps use different key intervals. This map here is needed for shading, which produce + * more than 256 different float values, which we cast to int so that the map can work. + */ + private Map toRGBMap = null; + + /** + * Creates a new Separation color space. + */ + public PDSeparation() + { + array = new COSArray(); + array.add(COSName.SEPARATION); + array.add(COSName.getPDFName("")); + // add some placeholder + array.add(COSNull.NULL); + array.add(COSNull.NULL); + } + + /** + * Creates a new Separation color space from a PDF color space array. + * @param separation an array containing all separation information. + * @throws IOException if the color space or the function could not be created. + */ + public PDSeparation(COSArray separation) throws IOException + { + array = separation; + alternateColorSpace = PDColorSpace.create(array.getObject(ALTERNATE_CS)); + tintTransform = PDFunction.create(array.getObject(TINT_TRANSFORM)); + int numberOfOutputParameters = tintTransform.getNumberOfOutputParameters(); + if (numberOfOutputParameters > 0 && + numberOfOutputParameters < alternateColorSpace.getNumberOfComponents()) + { + throw new IOException("The tint transform function has less output parameters (" + + tintTransform.getNumberOfOutputParameters() + ") than the alternate colorspace " + + alternateColorSpace + " (" + alternateColorSpace.getNumberOfComponents() + ")"); + } + } + + @Override + public String getName() + { + return COSName.SEPARATION.getName(); + } + + @Override + public int getNumberOfComponents() + { + return 1; + } + + @Override + public float[] getDefaultDecode(int bitsPerComponent) + { + return new float[] { 0, 1 }; + } + + @Override + public PDColor getInitialColor() + { + return initialColor; + } + + @Override + public float[] toRGB(float[] value) throws IOException + { + if (toRGBMap == null) + { + toRGBMap = new HashMap<>(); + } + int key = (int) (value[0] * 255); + float[] retval = toRGBMap.get(key); + if (retval != null) + { + return retval; + } + float[] altColor = tintTransform.eval(value); + retval = alternateColorSpace.toRGB(altColor); + toRGBMap.put(key, retval); + return retval; + } + + @Override + public Bitmap toRGBImage(Bitmap raster) throws IOException { + if (raster.getConfig() != Bitmap.Config.ALPHA_8) + { + Log.e("PdfBox-Android", "Raster in PDDevicGrey was not ALPHA_8"); + } + + int width = raster.getWidth(); + int height = raster.getHeight(); + int[] imgPixels = new int[width]; + + Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int[] outPixels = new int[width]; + + int rgb; + float[] value = new float[1]; + for (int y = 0; y < height; y++) + { + raster.getPixels(imgPixels, 0, width, 0, y, width, 1); + for (int x = 0; x < width; x++) + { + value[0] = Color.alpha(imgPixels[x])/255.f; + float[] rgbList = toRGB(value); + rgb = Color.argb(255, (int)(rgbList[0]*255), (int)(rgbList[1]*255), (int)(rgbList[2]*255)); + outPixels[x] = rgb; + } + image.setPixels(outPixels, 0, width, 0, y, width, 1); + } + + return image; + } + + // + // WARNING: this method is performance sensitive, modify with care! + // +// @Override +// public BufferedImage toRGBImage(WritableRaster raster) throws IOException +// { +// if (alternateColorSpace instanceof PDLab) +// { +// // PDFBOX-3622 - regular converter fails for Lab colorspaces +// return toRGBImage2(raster); +// } +// +// // use the tint transform to convert the sample into +// // the alternate color space (this is usually 1:many) +// WritableRaster altRaster = Raster.createBandedRaster(DataBuffer.TYPE_BYTE, +// raster.getWidth(), raster.getHeight(), +// alternateColorSpace.getNumberOfComponents(), +// new Point(0, 0)); +// +// int numAltComponents = alternateColorSpace.getNumberOfComponents(); +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// float[] samples = new float[1]; +// +// Map calculatedValues = new HashMap<>(); +// Integer hash; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, samples); +// hash = Float.floatToIntBits(samples[0]); +// int[] alt = calculatedValues.get(hash); +// if (alt == null) +// { +// alt = new int[numAltComponents]; +// tintTransform(samples, alt); +// calculatedValues.put(hash, alt); +// } +// altRaster.setPixel(x, y, alt); +// } +// } +// +// // convert the alternate color space to RGB +// return alternateColorSpace.toRGBImage(altRaster); +// } + + // converter that works without using super implementation of toRGBImage() +// private BufferedImage toRGBImage2(WritableRaster raster) throws IOException +// { +// int width = raster.getWidth(); +// int height = raster.getHeight(); +// BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// WritableRaster rgbRaster = rgbImage.getRaster(); +// float[] samples = new float[1]; +// +// Map calculatedValues = new HashMap<>(); +// Integer hash; +// for (int y = 0; y < height; y++) +// { +// for (int x = 0; x < width; x++) +// { +// raster.getPixel(x, y, samples); +// hash = Float.floatToIntBits(samples[0]); +// int[] rgb = calculatedValues.get(hash); +// if (rgb == null) +// { +// samples[0] /= 255; +// float[] altColor = tintTransform.eval(samples); +// float[] fltab = alternateColorSpace.toRGB(altColor); +// rgb = new int[3]; +// rgb[0] = (int) (fltab[0] * 255); +// rgb[1] = (int) (fltab[1] * 255); +// rgb[2] = (int) (fltab[2] * 255); +// calculatedValues.put(hash, rgb); +// } +// rgbRaster.setPixel(x, y, rgb); +// } +// } +// return rgbImage; +// } + + protected void tintTransform(float[] samples, int[] alt) throws IOException + { + samples[0] /= 255; // 0..1 + float[] result = tintTransform.eval(samples); + for (int s = 0; s < alt.length; s++) + { + // scale to 0..255 + alt[s] = (int) (result[s] * 255); + } + } + +// @Override +// public BufferedImage toRawImage(WritableRaster raster) +// { +// return toRawImage(raster, ColorSpace.getInstance(ColorSpace.CS_GRAY)); +// } + + /** + * Returns the colorant name. + * @return the name of the colorant + */ + public PDColorSpace getAlternateColorSpace() + { + return alternateColorSpace; + } + + /** + * Returns the colorant name. + * @return the name of the colorant + */ + public String getColorantName() + { + COSName name = (COSName)array.getObject(COLORANT_NAMES); + return name.getName(); + } + + /** + * Sets the colorant name. + * @param name the name of the colorant + */ + public void setColorantName(String name) + { + array.set(1, COSName.getPDFName(name)); + } + + /** + * Sets the alternate color space. + * @param colorSpace The alternate color space. + */ + public void setAlternateColorSpace(PDColorSpace colorSpace) + { + alternateColorSpace = colorSpace; + COSBase space = null; + if (colorSpace != null) + { + space = colorSpace.getCOSObject(); + } + array.set(ALTERNATE_CS, space); + } + + /** + * Sets the tint transform function. + * @param tint the tint transform function + */ + public void setTintTransform(PDFunction tint) + { + tintTransform = tint; + array.set(TINT_TRANSFORM, tint); + } + + @Override + public String toString() + { + return getName() + "{" + + "\"" + getColorantName() + "\"" + " " + + alternateColorSpace.getName() + " " + + tintTransform + "}"; + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDSpecialColorSpace.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDSpecialColorSpace.java new file mode 100644 index 00000000..3e67b5d5 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/color/PDSpecialColorSpace.java @@ -0,0 +1,12 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.color; + +import com.tom_roush.pdfbox.cos.COSBase; + +public abstract class PDSpecialColorSpace extends PDColorSpace +{ + @Override + public COSBase getCOSObject() + { + return array; + } +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/PDImageXObject.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/PDImageXObject.java index adf7be29..4ec88097 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/PDImageXObject.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/PDImageXObject.java @@ -27,6 +27,8 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -54,6 +56,7 @@ import com.tom_roush.pdfbox.pdmodel.graphics.color.PDDeviceGray; import com.tom_roush.pdfbox.util.filetypedetector.FileType; import com.tom_roush.pdfbox.util.filetypedetector.FileTypeDetector; +import com.xsooy.Glable; /** * An Image XObject. @@ -245,7 +248,7 @@ public static PDImageXObject createFromFileByExtension(File file, PDDocument doc throw new IllegalArgumentException("Image type not supported: " + name); } String ext = name.substring(dot + 1).toLowerCase(); - if ("jpg".equals(ext) || "jpeg".equals(ext)) + if ("jpg".equals(ext) || "cpp/jpeg".equals(ext)) { FileInputStream fis = null; try @@ -498,12 +501,14 @@ public Bitmap getImage(Rect region, int subsampling) throws IOException // soft mask (overrides explicit mask) if (softMask != null) { + Log.w("ceshi","applyMask11111"); image = applyMask(SampledImageReader.getRGBImage(this, region, subsampling, getColorKeyMask()), softMask.getOpaqueImage(), softMask.getInterpolate(), true, extractMatte(softMask)); } // explicit mask - to be applied only if /ImageMask true else if (mask != null && mask.isStencil()) { + Log.w("ceshi","applyMask2222"); image = applyMask(SampledImageReader.getRGBImage(this, region, subsampling, getColorKeyMask()), mask.getOpaqueImage(), mask.getInterpolate(), false, null); } @@ -597,6 +602,8 @@ private Bitmap applyMask(Bitmap image, Bitmap mask, boolean interpolateMask, final int width = Math.max(image.getWidth(), mask.getWidth()); final int height = Math.max(image.getHeight(), mask.getHeight()); + int[] maskPixels = new int[width]; + // scale mask to fit image, or image to fit mask, whichever is larger. // also make sure that mask is 8 bit gray and image is ARGB as this // is what needs to be returned. @@ -604,11 +611,25 @@ private Bitmap applyMask(Bitmap image, Bitmap mask, boolean interpolateMask, { mask = scaleImage(mask, width, height, interpolateMask); } - if (mask.getConfig() != Bitmap.Config.ALPHA_8 || !image.isMutable()) + if (mask.getConfig() != Bitmap.Config.ALPHA_8 ) + { + Bitmap clone = Bitmap.createBitmap(mask.getWidth(),mask.getHeight(),Bitmap.Config.ALPHA_8); + for (int y = 0; y < height; y++) + { + mask.getPixels(maskPixels, 0, width, 0, y, width, 1); + for (int x = 0; x < width; x++) + { + maskPixels[x] = Color.argb(maskPixels[x]&0xff,maskPixels[x]&0xff,maskPixels[x]&0xff,maskPixels[x]&0xff); + } + clone.setPixels(maskPixels, 0, width, 0, y, width, 1); + } + mask.recycle(); + mask = clone; + } + if (!mask.isMutable()) { mask = mask.copy(Bitmap.Config.ALPHA_8, true); } - if (image.getWidth() < width || image.getHeight() < height) { image = scaleImage(image, width, height, getInterpolate()); @@ -617,8 +638,10 @@ private Bitmap applyMask(Bitmap image, Bitmap mask, boolean interpolateMask, { image = image.copy(Bitmap.Config.ARGB_8888, true); } + if (!image.hasAlpha()) { + image.setHasAlpha(true); + } int[] pixels = new int[width]; - int[] maskPixels = new int[width]; // compose alpha into ARGB image, either: // - very fast by direct bit combination if not a soft mask and a 8 bit alpha source. @@ -649,7 +672,7 @@ else if (matte == null) { maskPixels[x] ^= -1; } - pixels[x] = pixels[x] & 0xffffff | maskPixels[x] & 0xff000000; + pixels[x] = pixels[x] & 0x00ffffff | (maskPixels[x] & 0xff000000); } image.setPixels(pixels, 0, width, 0, y, width, 1); } diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/SampledImageReader.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/SampledImageReader.java index fcb45983..5b499250 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/SampledImageReader.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/image/SampledImageReader.java @@ -24,6 +24,9 @@ import android.graphics.Rect; import android.util.Log; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; @@ -36,6 +39,13 @@ import com.tom_roush.pdfbox.filter.DecodeOptions; import com.tom_roush.pdfbox.io.IOUtils; import com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDDeviceGray; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDICCBased; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDIndexed; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDSeparation; +import com.xsooy.Glable; +import com.xsooy.jpeg.JpegUtils; /** * Reads a sampled image from a PDF file. @@ -87,13 +97,19 @@ public static Bitmap getStencilImage(PDImage pdImage, Paint paint) throws IOExce rowLen++; } byte[] buff = new byte[rowLen]; + int[] bank = new int[width]; for (int y = 0; y < height; y++) { int x = 0; int readLen = iis.read(buff); + if (readLen0) { + raster.copyPixelsFromBuffer(buffer); + } + +// Bitmap nn = pdImage.getColorSpace().toRGBImage(raster); +// File f = new File("/storage/emulated/0/Android/data/com.tom_roush.pdfbox.sample/files/temp_"+ Glable.jj +".png"); +// Glable.jj++; +// if (f.exists()) { +// f.delete(); +// } +// try { +// FileOutputStream out = new FileOutputStream(f); +// nn.compress(Bitmap.CompressFormat.JPEG, 80, out); +// out.flush(); +// out.close(); +// } catch (FileNotFoundException e) { +// e.printStackTrace(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// return nn; + return pdImage.getColorSpace().toRGBImage(raster); +// return raster; + } else if (numComponents == 4) { + Bitmap raster = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + ByteBuffer buffer = ByteBuffer.allocate(raster.getRowBytes() * height); + final byte[] output = buffer.array(); + if(input.read(output)>0) { + raster.copyPixelsFromBuffer(buffer); + } + + return pdImage.getColorSpace().toRGBImage(raster); + } return createBitmapFromRawStream(input, inputWidth, numComponents, currentSubsampling); } else { + Log.w("ceshi","走到这里了?"); Bitmap origin = createBitmapFromRawStream(input, inputWidth, numComponents, currentSubsampling); if (currentSubsampling > 1) @@ -433,9 +601,172 @@ else if (numComponents == 3) // slower, general-purpose image conversion from any image format // private static BufferedImage fromAny(PDImage pdImage, WritableRaster raster, COSArray colorKey, Rectangle clipped, // final int subsampling, final int width, final int height) TODO: Pdfbox-Android + private static Bitmap fromAny(PDImage pdImage, +// WritableRaster raster, + COSArray colorKey, Rect clipped, + final int subsampling, final int width, final int height) + throws IOException + { + int currentSubsampling = subsampling; + final PDColorSpace colorSpace = pdImage.getColorSpace(); + final int numComponents = colorSpace.getNumberOfComponents(); + final int bitsPerComponent = pdImage.getBitsPerComponent(); + final float[] decode = getDecodeArray(pdImage); + + DecodeOptions options = new DecodeOptions(currentSubsampling); + options.setSourceRegion(clipped); + // read bit stream + + try { + ImageInputStream input = new MemoryCacheImageInputStream(pdImage.createInputStream(options)); + final int inputWidth; + final int startx; + final int starty; + final int scanWidth; + final int scanHeight; + if (options.isFilterSubsampled()) { + // Decode options were honored, and so there is no need for additional clipping or subsampling + inputWidth = width; + startx = 0; + starty = 0; + scanWidth = width; + scanHeight = height; + currentSubsampling = 1; + } else { + // Decode options not honored, so we need to clip and subsample ourselves. + inputWidth = pdImage.getWidth(); + startx = clipped.left; + starty = clipped.top; + scanWidth = clipped.width(); + scanHeight = clipped.height(); + } + final float sampleMax = (float) Math.pow(2, bitsPerComponent) - 1f; + final boolean isIndexed = colorSpace instanceof PDIndexed; + + // init color key mask + float[] colorKeyRanges = null; +// BufferedImage colorKeyMask = null; + Bitmap colorKeyMask = null; + if (colorKey != null) { + colorKeyRanges = colorKey.toFloatArray(); + colorKeyMask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8); + } + + // calculate row padding + int padding = 0; + if (inputWidth * numComponents * bitsPerComponent % 8 > 0) { + padding = 8 - (inputWidth * numComponents * bitsPerComponent % 8); + } + + // read stream + int[] banks = new int[width * height]; + byte[] srcColorValues = new byte[numComponents]; + byte[] alpha = new byte[1]; +// byte[] tempBytes = new byte[numComponents * inputWidth]; + for (int y = 0; y < starty + scanHeight; y++) { + for (int x = 0; x < startx + scanWidth; x++) { + boolean isMasked = true; + for (int c = 0; c < numComponents; c++) { + int value = (int) input.readBits(bitsPerComponent); + + // color key mask requires values before they are decoded + if (colorKeyRanges != null) { + isMasked &= value >= colorKeyRanges[c * 2] && + value <= colorKeyRanges[c * 2 + 1]; + } + + // decode array + final float dMin = decode[c * 2]; + final float dMax = decode[(c * 2) + 1]; + + // interpolate to domain + float output = dMin + (value * ((dMax - dMin) / sampleMax)); + + if (isIndexed) { + // indexed color spaces get the raw value, because the TYPE_BYTE + // below cannot be reversed by the color space without it having + // knowledge of the number of bits per component + srcColorValues[c] = (byte) Math.round(output); + + } else { + // interpolate to TYPE_BYTE + int outputByte = Math.round(((output - Math.min(dMin, dMax)) / + Math.abs(dMax - dMin)) * 255f); + srcColorValues[c] = (byte) outputByte; + } + } + // only write to output if within requested region and subsample. + if (x >= startx && y >= starty && x % currentSubsampling == 0 && y % currentSubsampling == 0) { + if (numComponents == 1) { + banks[(y - starty) * scanWidth + (x - startx)] = Color.argb(srcColorValues[0],srcColorValues[0],srcColorValues[0],srcColorValues[0]); + } else { + banks[(y - starty) * scanWidth + (x - startx)] = Color.argb(isMasked ? 255 : 0, srcColorValues[0], srcColorValues[1], srcColorValues[2]); + } +// raster.setDataElements((x - startx) / currentSubsampling, (y - starty) / currentSubsampling, srcColorValues); +// +// // set alpha channel in color key mask, if any + if (colorKeyMask != null) + { + alpha[0] = (byte)(isMasked ? 255 : 0); + colorKeyMask.setPixel((x - startx) / currentSubsampling, (y - starty) / currentSubsampling,(int)alpha[0]); + } + } + } + // rows are padded to the nearest byte + input.readBits(padding); + } + + Bitmap raster; + if (pdImage.getColorSpace() instanceof PDIndexed) { + raster = Bitmap.createBitmap(width,height,Bitmap.Config.ALPHA_8); + raster.setPixels(banks, 0, width, 0 ,0, width, height); + raster = ((PDIndexed)pdImage.getColorSpace()).toRGBImage(raster); + } else { + raster = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888); + raster.setPixels(banks, 0, width, 0 ,0, width, height); + } + if (colorKeyMask != null) + { + return applyColorKeyMask(raster, colorKeyMask); + } + return raster; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + // color key mask: RGB + Binary -> ARGB // private static BufferedImage applyColorKeyMask(BufferedImage image, BufferedImage mask) TODO: PdfBox-Android + private static Bitmap applyColorKeyMask(Bitmap image, Bitmap mask) + { + int width = image.getWidth(); + int height = image.getHeight(); + + // compose to ARGB + Bitmap masked = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + +// WritableRaster src = image.getRaster(); +// WritableRaster dest = masked.getRaster(); +// WritableRaster alpha = mask.getRaster(); + + int[] src = new int[width]; + int[] alpha = new int[width]; + int[] dest = new int[width]; + for (int y = 0; y < height; y++) + { + image.getPixels(src,0,width,0 , y, width,1); + mask.getPixels(alpha,0,width,0, y, width,1); + for (int x = 0; x < width; x++) + { + dest[x] = Color.argb(255-Color.alpha(alpha[x]),Color.red(src[x]),Color.green(src[x]),Color.blue(src[x])); + } + masked.setPixels(dest,0,width,0,y,width,1); + } + + return masked; + } // gets decode array from dictionary or returns default private static float[] getDecodeArray(PDImage pdImage) throws IOException diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java new file mode 100644 index 00000000..6a1653b5 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java @@ -0,0 +1,226 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.shading; + +import android.graphics.Rect; +import android.util.Log; + +import com.tom_roush.harmony.awt.geom.AffineTransform; +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.cos.COSBoolean; +import com.tom_roush.pdfbox.util.Matrix; + +import java.io.IOException; + +public class AxialShadingContext extends ShadingContext { + + private PDShadingType2 axialShadingType; + private final float[] coords; + private final float[] domain; + private final boolean[] extend; + private final double x1x0; + private final double y1y0; + private final float d1d0; + private final double denom; + + private final int factor; + + private final int[] colorTable; + private AffineTransform rat; + + public AxialShadingContext(PDShadingType2 shading, Rect deviceBounds, Matrix matrix, AffineTransform xform) throws IOException { + super(shading); + this.axialShadingType = shading; + coords = shading.getCoords().toFloatArray(); + // domain values + if (shading.getDomain() != null) + { + domain = shading.getDomain().toFloatArray(); + } + else + { + // set default values + domain = new float[] { 0, 1 }; + } + // extend values + COSArray extendValues = shading.getExtend(); + if (extendValues != null) + { + extend = new boolean[2]; + extend[0] = ((COSBoolean) extendValues.getObject(0)).getValue(); + extend[1] = ((COSBoolean) extendValues.getObject(1)).getValue(); + } + else + { + // set default values + extend = new boolean[] { false, false }; + } + // calculate some constants to be used in getRaster + x1x0 = coords[2] - coords[0]; + y1y0 = coords[3] - coords[1]; + d1d0 = domain[1] - domain[0]; + denom = Math.pow(x1x0, 2) + Math.pow(y1y0, 2); + + try + { +// get inverse transform to be independent of current user / device space +// when handling actual pixels in getRaster() + rat = matrix.createAffineTransform().createInverse(); + rat.concatenate(xform.createInverse()); + } + catch (AffineTransform.NoninvertibleTransformException ex) + { +// LOG.error(ex.getMessage() + ", matrix: " + matrix, ex); + rat = new AffineTransform(); + } + + // shading space -> device space +// AffineTransform shadingToDevice = (AffineTransform)xform.clone(); +// shadingToDevice.concatenate(matrix.createAffineTransform()); + + // worst case for the number of steps is opposite diagonal corners, so use that + double dist = Math.sqrt(Math.pow(deviceBounds.right - deviceBounds.left, 2) + + Math.pow(deviceBounds.bottom - deviceBounds.top, 2)); + factor = (int) Math.ceil(dist); + + // build the color table for the given number of steps + colorTable = calcColorTable(); + } + + private int[] calcColorTable() throws IOException + { + + int[] map = new int[factor + 1]; + if (factor == 0 || Float.compare(d1d0, 0) == 0) + { + float[] values = axialShadingType.evalFunction(domain[0]); + + map[0] = convertToRGB(values); + } + else + { +// IccUtils iccUtils = new IccUtils(); +// iccUtils.loadProfile("/storage/emulated/0/Android/data/com.example.test/files/HFA_Eps15000_MK_Agave-Sisal.icc"); +// iccUtils.loadProfile2("/storage/emulated/0/Android/data/com.example.test/files/ISOcoated_v2_300_bas.icc","/storage/emulated/0/Android/data/com.example.test/files/HFA_Eps15000_MK_Agave-Sisal.icc"); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i <= factor; i++) + { + float t = domain[0] + d1d0 * i / factor; + float[] values = axialShadingType.evalFunction(t); +// builder.delete(0,builder.length()); +// for (float jj:values) +// builder.append(jj+","); +// Log.w("ceshi","calcColorTable:"+builder.toString()); +// int normRGBValues; +// normRGBValues = (int) (values[0] * 65535); +// normRGBValues |= (int) (values[1] * 65535) << 8; +// normRGBValues |= (int) (values[2] * 65535) << 16; +// normRGBValues |= (int) (values[3] * 65535) << 24; +// iccUtils.applyCmyk(values); +// builder.delete(0,builder.length()); +// for (float jj:values) +// builder.append(jj+","); +// Log.w("ceshi","转换结果:"+builder.toString()); +// float[] test = new float[] {(map[i]>>24&0xff)/255.f, (map[i]>>16&0xff)/255.f,(map[0]>>8&0xff)/255.f,(map[0]&0xff)/255.f}; + map[i] = convertToRGB(values); + +// Log.w("ceshi",String.format("r:%d,g:%d,b:%d",map[i]>>16&0xff,map[i]>>8&0xff,map[i]&0xff)); + } + } + return map; + } + + + public int[] getRaster(int x, int y, int w, int h) + { + // create writable raster +// Log.w("ceshi",String.format("x:%d,y:%d,w:%d,h:%h",x,y,w,h)); +// System.out.println(String.format("x:%d,y:%d,w:%d,h:%h",x,y,w,h)); + boolean useBackground; +// int[] data = new int[w * h * 4]; + int[] data = new int[w * h]; + float[] values = new float[2]; + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + useBackground = false; + values[0] = x + i; + values[1] = y + j; + rat.transform(values, 0, values, 0, 1); + double inputValue = x1x0 * (values[0] - coords[0]) + y1y0 * (values[1] - coords[1]); + // TODO this happens if start == end, see PDFBOX-1442 + if (Double.compare(denom, 0) == 0) + { + if (getBackground() == null) + { + continue; + } + useBackground = true; + } + else + { + inputValue /= denom; + } + // input value is out of range + if (inputValue < 0) + { + // the shading has to be extended if extend[0] == true + if (extend[0]) + { + inputValue = domain[0]; + } + else + { + if (getBackground() == null) + { + continue; + } + useBackground = true; + } + } + // input value is out of range + else if (inputValue > 1) + { + // the shading has to be extended if extend[1] == true + if (extend[1]) + { + inputValue = domain[1]; + } + else + { + if (getBackground() == null) + { + continue; + } + useBackground = true; + } + } + int value; + if (useBackground) + { + // use the given background color values + value = getRgbBackground(); + } + else + { + int key = (int) (inputValue * factor); + value = colorTable[key]; + } + int index = (j * w + i); + data[index] = value; +// int index = (j * w + i) * 4; +// data[index] = value & 255; +// value >>= 8; +// data[index + 1] = value & 255; +// value >>= 8; +// data[index + 2] = value & 255; +// data[index + 3] = 255; +// System.out.println(String.format("r:%d,g:%d,b:%d,a:%h",data[index],data[index+1],data[index+2],data[index+3])); + } + } +// raster.setPixels(0, 0, w, h, data); + return data; + } + + +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/shading/ShadingContext.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/shading/ShadingContext.java new file mode 100644 index 00000000..f045f637 --- /dev/null +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/shading/ShadingContext.java @@ -0,0 +1,66 @@ +package com.tom_roush.pdfbox.pdmodel.graphics.shading; + +import com.tom_roush.pdfbox.cos.COSArray; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace; + +import java.io.IOException; + +public class ShadingContext { + + private float[] background; + private int rgbBackground; + private final PDShading shading; +// private ColorModel outputColorModel; + private PDColorSpace shadingColorSpace; + + public ShadingContext(PDShading shading +// , +// ColorModel cm, AffineTransform xform, +// Matrix matrix + ) throws IOException + { + this.shading = shading; + shadingColorSpace = shading.getColorSpace(); + // create the output color model using RGB+alpha as color space +// shadingColorSpace = PDDeviceCMYK.INSTANCE; +// ColorSpace outputCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); +// outputColorModel = new ComponentColorModel(outputCS, true, false, Transparency.TRANSLUCENT, +// DataBuffer.TYPE_BYTE); + + // get background values if available + COSArray bg = shading.getBackground(); + if (bg != null) + { + background = bg.toFloatArray(); + rgbBackground = convertToRGB(background); + } + } + + final int convertToRGB(float[] values) throws IOException + { + int normRGBValues; + + float[] rgbValues = shadingColorSpace.toRGB(values); +// Log.w("ceshi","hadingColorSpace.toRGB::"+rgbValues[2]); + normRGBValues = (int) (rgbValues[2] * 255); + normRGBValues |= (int) (rgbValues[1] * 255) << 8; + normRGBValues |= (int) (rgbValues[0] * 255) << 16; +// StringBuilder builder = new StringBuilder(); +// for (float jj:rgbValues) +// builder.append(jj+","); +// Log.w("ceshi","转换结果:"+builder.toString()); + + return normRGBValues; + } + + float[] getBackground() + { + return background; + } + + int getRgbBackground() + { + return rgbBackground; + } + +} diff --git a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/state/PDGraphicsState.java b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/state/PDGraphicsState.java index 9bd74d5d..188c5ac4 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/state/PDGraphicsState.java +++ b/library/src/main/java/com/tom_roush/pdfbox/pdmodel/graphics/state/PDGraphicsState.java @@ -633,19 +633,20 @@ public void intersectClippingPath(Region area) * * @return The current clipping path. */ - public Region getCurrentClippingPath() + public Path getCurrentClippingPath() { if (clippingPaths.size() == 1) { // If there is just a single clipping path, no intersections are needed. Path path = clippingPaths.get(0); - Region area = clippingCache.get(path); - if (area == null) - { - area = GraphicsUtil.getPathRegion(path); - clippingCache.put(path, area); - } - return area; +// Region area = clippingCache.get(path); +// if (area == null) +// { +// area = GraphicsUtil.getPathRegion(path); +// clippingCache.put(path, area); +// } + return path; +// return area; } // If there are multiple clipping paths, combine them to a single area. Path clippingPath = new Path(clippingPaths.get(0)); @@ -653,12 +654,16 @@ public Region getCurrentClippingPath() { clippingPath.op(clippingPaths.get(i), Path.Op.INTERSECT); } - Region clippingRegion = GraphicsUtil.getPathRegion(clippingPath); +// android.graphics.Matrix matrix = new android.graphics.Matrix(); +// matrix.setScale(scaleX,scaleY); +// clippingPath.transform(matrix); +// Region clippingRegion = GraphicsUtil.getPathRegion(clippingPath); // Replace the list of individual clipping paths with the intersection, and add it to the cache. - clippingPaths = new ArrayList(1); - clippingPaths.add(clippingPath); - clippingCache.put(clippingPath, clippingRegion); - return clippingRegion; +// clippingPaths = new ArrayList(1); +// clippingPaths.add(clippingPath); +// clippingCache.put(clippingPath, clippingRegion); +// return clippingRegion; + return clippingPath; } /** diff --git a/library/src/main/java/com/tom_roush/pdfbox/rendering/PDFRenderer.java b/library/src/main/java/com/tom_roush/pdfbox/rendering/PDFRenderer.java index a3ced3c6..6e094f85 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/rendering/PDFRenderer.java +++ b/library/src/main/java/com/tom_roush/pdfbox/rendering/PDFRenderer.java @@ -20,6 +20,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.util.Log; import java.io.IOException; @@ -311,7 +312,7 @@ public Bitmap renderImage(int pageIndex, float scale, ImageType imageType, Rende // the end-user may provide a custom PageDrawer PageDrawerParameters parameters = new PageDrawerParameters(this, page, subsamplingAllowed, destination, - imageDownscalingOptimizationThreshold); + imageDownscalingOptimizationThreshold,scale,scale); PageDrawer drawer = createPageDrawer(parameters); drawer.drawPage(paint, canvas, cropBox); @@ -409,7 +410,7 @@ public void renderPageToGraphics(int pageIndex, Paint paint, Canvas canvas, floa // the end-user may provide a custom PageDrawer PageDrawerParameters parameters = new PageDrawerParameters(this, page, subsamplingAllowed, destination, - imageDownscalingOptimizationThreshold); + imageDownscalingOptimizationThreshold,scaleX,scaleY); PageDrawer drawer = createPageDrawer(parameters); drawer.drawPage(paint, canvas, cropBox); } diff --git a/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawer.java b/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawer.java index 6dc73e30..09032c5a 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawer.java +++ b/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawer.java @@ -23,10 +23,14 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.util.Log; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; @@ -61,6 +65,8 @@ import com.tom_roush.pdfbox.pdmodel.graphics.color.PDColor; import com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace; import com.tom_roush.pdfbox.pdmodel.graphics.color.PDDeviceGray; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDICCBased; +import com.tom_roush.pdfbox.pdmodel.graphics.color.PDPattern; import com.tom_roush.pdfbox.pdmodel.graphics.form.PDFormXObject; import com.tom_roush.pdfbox.pdmodel.graphics.form.PDTransparencyGroup; import com.tom_roush.pdfbox.pdmodel.graphics.image.PDImage; @@ -68,7 +74,11 @@ import com.tom_roush.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup; import com.tom_roush.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup.RenderState; import com.tom_roush.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentMembershipDictionary; +import com.tom_roush.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern; +import com.tom_roush.pdfbox.pdmodel.graphics.pattern.PDShadingPattern; +import com.tom_roush.pdfbox.pdmodel.graphics.shading.AxialShadingContext; import com.tom_roush.pdfbox.pdmodel.graphics.shading.PDShading; +import com.tom_roush.pdfbox.pdmodel.graphics.shading.PDShadingType2; import com.tom_roush.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; import com.tom_roush.pdfbox.pdmodel.graphics.state.PDGraphicsState; import com.tom_roush.pdfbox.pdmodel.graphics.state.PDSoftMask; @@ -79,6 +89,7 @@ import com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import com.tom_roush.pdfbox.util.Matrix; import com.tom_roush.pdfbox.util.Vector; +import com.xsooy.Glable; /** * Paints a page in a PDF document to a Canvas context. May be subclassed to provide custom @@ -102,6 +113,8 @@ public class PageDrawer extends PDFGraphicsStreamEngine // the graphics device to draw to, xform is the initial transform of the device (i.e. DPI) private Paint paint; + private float scaleX = 1; + private float scaleY = 1; private Canvas canvas; private AffineTransform xform; private float xformScalingFactorX; @@ -119,7 +132,7 @@ public class PageDrawer extends PDFGraphicsStreamEngine private Path linePath = new Path(); // last clipping path - private Region lastClip; + private Path lastClip; private int lastStackSize = 0; // clip when drawPage() is called, can be null, must be intersected when clipping @@ -162,6 +175,8 @@ public boolean accept(PDAnnotation annotation) public PageDrawer(PageDrawerParameters parameters) throws IOException { super(parameters.getPage()); + this.scaleX = parameters.getScaleX(); + this.scaleY = parameters.getScaleY(); this.renderer = parameters.getRenderer(); this.subsamplingAllowed = parameters.isSubsamplingAllowed(); this.destination = parameters.getDestination(); @@ -244,7 +259,6 @@ public void drawPage(Paint p, Canvas c, PDRectangle pageSize) throws IOException xformScalingFactorX = Math.abs(m.getScalingFactorX()); xformScalingFactorY = Math.abs(m.getScalingFactorY()); // backup init status - canvas.save(); this.pageSize = pageSize; setRenderingHints(); @@ -261,7 +275,6 @@ public void drawPage(Paint p, Canvas c, PDRectangle pageSize) throws IOException { showAnnotation(annotation); } - canvas.restore(); } // void drawTilingPattern(Graphics2D g, PDTilingPattern pattern, PDColorSpace colorSpace, @@ -296,7 +309,7 @@ private int getColor(PDColor color) throws IOException { */ protected final void setClip() { - Region clippingPath = getGraphicsState().getCurrentClippingPath(); + Path clippingPath = getGraphicsState().getCurrentClippingPath(); if (clippingPath != lastClip) { // android canvas manage clips with save/restore in a private stack, we can not @@ -309,7 +322,7 @@ protected final void setClip() lastStackSize = canvas.save(); if (!clippingPath.isEmpty()) { - canvas.clipPath(clippingPath.getBoundaryPath()); + canvas.clipPath(clippingPath); } if (initialClip != null) { @@ -415,32 +428,38 @@ private void drawGlyph2D(Glyph2D glyph2D, PDFont font, int code, Vector displace } // render glyph -// Shape glyph = at.createTransformedShape(path); - path.transform(at.toMatrix()); + Path clone = new Path(); + clone.addPath(path); + clone.transform(at.toMatrix()); if (isContentRendered()) { if (renderingMode.isFill()) { paint.setColor(getNonStrokingColor()); + paint.setAlpha((int)(getGraphicsState().getNonStrokeAlphaConstant()*255)); setClip(); paint.setStyle(Paint.Style.FILL); - canvas.drawPath(path, paint); + canvas.drawPath(clone, paint); + Log.w("ceshi","11111"); } if (renderingMode.isStroke()) { paint.setColor(getStrokingColor()); + paint.setAlpha((int)(getGraphicsState().getNonStrokeAlphaConstant()*255)); setStroke(); setClip(); paint.setStyle(Paint.Style.STROKE); - canvas.drawPath(path, paint); + canvas.drawPath(clone, paint); + Log.w("ceshi","22222"); } } if (renderingMode.isClip()) { -// textClippings.add(glyph); TODO: PdfBox-Android + Log.w("ceshi","33333"); + textClippings.add(clone); } } } @@ -659,18 +678,25 @@ public void strokePath() throws IOException setStroke(); paint.setStyle(Paint.Style.STROKE); paint.setColor(getStrokingColor()); + paint.setAlpha((int)(getGraphicsState().getNonStrokeAlphaConstant()*255)); setClip(); canvas.drawPath(linePath, paint); } linePath.reset(); } +// int test = 0; + @Override public void fillPath(Path.FillType windingRule) throws IOException { +// test++; +// if (test!=18) { +// Log.w("ceshi","fillPath----"+test); +// return; +// } PDGraphicsState graphicsState = getGraphicsState(); - paint.setColor(getNonStrokingColor()); - setClip(); + linePath.setFillType(windingRule); // disable anti-aliasing for rectangular paths, this is a workaround to avoid small stripes @@ -689,7 +715,43 @@ public void fillPath(Path.FillType windingRule) throws IOException if (isContentRendered()) { paint.setStyle(Paint.Style.FILL); - canvas.drawPath(linePath, paint); + if (getGraphicsState().getNonStrokingColor().getColorSpace() instanceof PDPattern) { + PDColorSpace colorSpace = getGraphicsState().getNonStrokingColor().getColorSpace(); + PDAbstractPattern pattern = ((PDPattern)colorSpace).getPattern(getGraphicsState().getNonStrokingColor()); + PDShadingPattern shadingPattern = (PDShadingPattern)pattern; + PDShading shading = shadingPattern.getShading(); + //轴向 + if (shading instanceof PDShadingType2) { +// getGraphicsState().intersectClippingPath(linePath); + setClip(); + canvas.save(); + canvas.clipPath(linePath, Region.Op.INTERSECT); + canvas.scale(1/scaleX,1/scaleY); + Rect rect = new Rect((int)(bounds.left*scaleX),(int)(bounds.top*scaleY),(int)(bounds.right*scaleX),(int)(bounds.bottom*scaleY)); + Rect rect2 = new Rect((int)(bounds.left*scaleX),(int)(canvas.getHeight()-(bounds.bottom*scaleY)),(int)(bounds.right*scaleX),(int)(canvas.getHeight()-(bounds.top*scaleY))); +// paint.setStrokeWidth(2f); + + Matrix ctm = getGraphicsState().getCurrentTransformationMatrix(); + AxialShadingContext axialShadingContext = new AxialShadingContext((PDShadingType2) shading,rect2,ctm,new AffineTransform(scaleX,0,0,-scaleY,0,canvas.getHeight())); +// axialShadingContext.setTransform(ctm,new AffineTransform(4.166666507720948,0.0, 0.0, -4.166666507720948, 0.0, 3507.874927220342)); + for (int y=rect.bottom;y>rect.top;y--) { + int[] data = axialShadingContext.getRaster(rect.left,canvas.getHeight()-y,rect.right-rect.left,1); + for (int i=0;irect.top;y--) { + int[] data = axialShadingContext.getRaster(rect.left,canvas.getHeight()-y,rect.right-rect.left,1); + paint.setStrokeWidth(2f); + for (int i=0;i()); + hasBlendMode(form, new HashSet()); Bitmap backdropImage = null; // Position of this group in parent group's coordinates int backdropX = 0; @@ -1300,22 +1411,16 @@ private TransparencyGroup(PDTransparencyGroup form, boolean isSoftMask, Matrix c { // Use the current page as the parent group. backdropImage = renderer.getPageImage(); - if (backdropImage == null) - { - needsBackdrop = false; - } - else - { -// backdropX = minX; -// backdropY = backdropImage.getHeight() - maxY; - } + needsBackdrop = backdropImage != null; + backdropX = minX; + backdropY = (backdropImage != null) ? (backdropImage.getHeight() - maxY) : 0; } else { TransparencyGroup parentGroup = transparencyGroupStack.peek(); -// backdropImage = parentGroup.image; -// backdropX = minX - parentGroup.minX; -// backdropY = parentGroup.maxY - maxY; + backdropImage = parentGroup.image; + backdropX = minX - parentGroup.minX; + backdropY = parentGroup.maxY - maxY; } } @@ -1323,9 +1428,10 @@ private TransparencyGroup(PDTransparencyGroup form, boolean isSoftMask, Matrix c if (needsBackdrop) { // backdropImage must be included in group image but not in group alpha. -// g.drawImage(backdropImage, 0, 0, width, height, -// backdropX, backdropY, backdropX + width, backdropY + height, null); -// g = new GroupGraphics(image, g); +// g = new Canvas(image); +// g.drawBitmap(backdropImage,new Rect(0,0,width,height),new Rect(backdropX, backdropY, backdropX + width, backdropY + height),paint); +// g.drawBitmap(backdropImage, 0, 0, width, height, +// backdropX, backdropY, backdropX + width, backdropY + height, paint); } if (isSoftMask && backdropColor != null) { @@ -1340,18 +1446,21 @@ private TransparencyGroup(PDTransparencyGroup form, boolean isSoftMask, Matrix c // g.translate(0, image.getHeight()); // g.scale(1, -1); - boolean savedFlipTG = flipTG; + boolean oldFlipTG = flipTG; flipTG = false; // apply device transform (DPI) // the initial translation is ignored, because we're not writing into the initial graphics device -// g.transform(xform); +// g.scale(scaleX,scaleY); +// g.tr(dpiTransform); + AffineTransform xformOriginal = xform; + xform = AffineTransform.getScaleInstance(scaleX, scaleY); PDRectangle pageSizeOriginal = pageSize; -// pageSize = new PDRectangle(minX / xformScalingFactorX, -// minY / xformScalingFactorY, -// (float) (bounds.getWidth() / xformScalingFactorX), -// (float) (bounds.getHeight() / xformScalingFactorY)); +// pageSize = new PDRectangle(minX / scaleX, +// minY / scaleY, +// (float) bounds.getWidth() / scaleX, +// (float) bounds.getHeight() / scaleY); Path.FillType clipWindingRuleOriginal = clipWindingRule; clipWindingRule = null; Path linePathOriginal = linePath; @@ -1359,7 +1468,9 @@ private TransparencyGroup(PDTransparencyGroup form, boolean isSoftMask, Matrix c // adjust the origin // g.translate(-clipRect.getX(), -clipRect.getY()); - + canvas = g; +// backdropImage = renderer.getPageImage(); +// canvas.drawBitmap(backdropImage,0,0,paint); // graphics = g; setRenderingHints(); try @@ -1377,23 +1488,23 @@ private TransparencyGroup(PDTransparencyGroup form, boolean isSoftMask, Matrix c transparencyGroupStack.pop(); } } - - if (needsBackdrop) - { -// ((GroupGraphics) graphics).removeBackdrop(backdropImage, backdropX, backdropY); - } } finally { - flipTG = savedFlipTG; -// lastClip = savedLastClip; + flipTG = oldFlipTG; +// lastClip = lastClipOriginal; // graphics.dispose(); -// graphics = savedGraphics; -// initialClip = savedInitialClip; +// image.recycle(); + canvas = savedCanvas; clipWindingRule = clipWindingRuleOriginal; linePath = linePathOriginal; pageSize = pageSizeOriginal; xform = xformOriginal; + + if (needsBackdrop) + { +// ((GroupGraphics) g).removeBackdrop(backdropImage, backdropX, backdropY); + } } } @@ -1420,11 +1531,27 @@ private boolean isGray(PDColorSpace colorSpace) return false; } -// Bitmap getImage() + public Bitmap getImage() + { + return image; + } -// PDRectangle getBBox() + public PDRectangle getBBox() + { + return bbox; + } -// RectF getBounds() +// public RectF getBounds() +// { +// PointF size = new PointF(pageSize.getWidth(), pageSize.getHeight()); +// // apply the underlying Graphics2D device's DPI transform and y-axis flip +// AffineTransform dpiTransform = AffineTransform.getScaleInstance(scaleX, scaleY); +// size = dpiTransform.transform(size, size); +// // Flip y +// return new RectF(minX - pageSize.getLowerLeftX() * scaleX, +// size.y - minY - height + pageSize.getLowerLeftY() * scaleY, +// width, height); +// } } private boolean hasBlendMode(PDTransparencyGroup group, Set groupsDone) diff --git a/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawerParameters.java b/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawerParameters.java index b3836c53..902ca32b 100644 --- a/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawerParameters.java +++ b/library/src/main/java/com/tom_roush/pdfbox/rendering/PageDrawerParameters.java @@ -33,19 +33,22 @@ public final class PageDrawerParameters private final boolean subsamplingAllowed; private final RenderDestination destination; private final float imageDownscalingOptimizationThreshold; + private final float scaleX,scaleY; /** * Package-private constructor. */ PageDrawerParameters(PDFRenderer renderer, PDPage page, boolean subsamplingAllowed, RenderDestination destination, - float imageDownscalingOptimizationThreshold) + float imageDownscalingOptimizationThreshold,float scaleX,float scaleY) { this.renderer = renderer; this.page = page; this.subsamplingAllowed = subsamplingAllowed; this.destination = destination; this.imageDownscalingOptimizationThreshold = imageDownscalingOptimizationThreshold; + this.scaleX = scaleX; + this.scaleY = scaleY; } /** @@ -89,4 +92,12 @@ public float getImageDownscalingOptimizationThreshold() { return imageDownscalingOptimizationThreshold; } + + public float getScaleX() { + return scaleX; + } + + public float getScaleY() { + return scaleY; + } } diff --git a/library/src/main/java/com/xsooy/Glable.java b/library/src/main/java/com/xsooy/Glable.java new file mode 100644 index 00000000..4c22415d --- /dev/null +++ b/library/src/main/java/com/xsooy/Glable.java @@ -0,0 +1,5 @@ +package com.xsooy; + +public class Glable { + public static int jj=0; +} diff --git a/library/src/main/java/com/xsooy/icc/IccProfile.java b/library/src/main/java/com/xsooy/icc/IccProfile.java new file mode 100644 index 00000000..5e1b12c3 --- /dev/null +++ b/library/src/main/java/com/xsooy/icc/IccProfile.java @@ -0,0 +1,24 @@ +package com.xsooy.icc; + +public class IccProfile { + + private long iccProfile; + private int colorSpaceCode; + + public long getIccProfile() { + return iccProfile; + } + + public void setIccProfile(long iccProfile) { + this.iccProfile = iccProfile; + } + + public int getColorSpaceCode() { + return colorSpaceCode; + } + + public void setColorSpaceCode(int colorSpaceCode) { + this.colorSpaceCode = colorSpaceCode; + } + +} diff --git a/library/src/main/java/com/xsooy/icc/IccUtils.java b/library/src/main/java/com/xsooy/icc/IccUtils.java new file mode 100644 index 00000000..fd0288be --- /dev/null +++ b/library/src/main/java/com/xsooy/icc/IccUtils.java @@ -0,0 +1,40 @@ +package com.xsooy.icc; + +import static com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace.TYPE_CMYK; +import static com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace.TYPE_GRAY; +import static com.tom_roush.pdfbox.pdmodel.graphics.color.PDColorSpace.TYPE_RGB; + +public class IccUtils { + + static { + System.loadLibrary("iccUse"); + } + + public native int loadProfile(String path); + + public native int loadProfileByData(byte[] data); + +// public native int loadProfile2(String path,String path2); + + public native float apply(float color); + + //gray to xyz +// public native void applyGray(float[] in,float[] out); + + //cmyk to lab + public native void applyCmyk(float[] in,float[] out); + + public static int getIccColorType(int code) { + switch (code) { + case 0x47524159: + return TYPE_GRAY; + case 0x434D594B: + return TYPE_CMYK; +// case 0x52474220: +// return TYPE_RGB; + default: + return TYPE_RGB; + } + } + +} diff --git a/library/src/main/java/com/xsooy/jbig2/Jbig2Utils.java b/library/src/main/java/com/xsooy/jbig2/Jbig2Utils.java new file mode 100644 index 00000000..cf0cbeae --- /dev/null +++ b/library/src/main/java/com/xsooy/jbig2/Jbig2Utils.java @@ -0,0 +1,13 @@ +package com.xsooy.jbig2; + +public class Jbig2Utils { + + static { + System.loadLibrary("jbig2Use"); + } + +// public native void init(); + + public native byte[] converData(byte[] data); + +} diff --git a/library/src/main/java/com/xsooy/jpeg/JpegUtils.java b/library/src/main/java/com/xsooy/jpeg/JpegUtils.java new file mode 100644 index 00000000..0dff9b7d --- /dev/null +++ b/library/src/main/java/com/xsooy/jpeg/JpegUtils.java @@ -0,0 +1,13 @@ +package com.xsooy.jpeg; + +public class JpegUtils { + + static { + System.loadLibrary("jpegUse"); + } + + public native byte[] converData(byte[] data); + + public native void converDataToArray(byte[] data,byte[] ouput); + +} diff --git a/sample/build.gradle b/sample/build.gradle index bc172014..957445d0 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -34,7 +34,7 @@ dependencies { // implementation "com.tom-roush:pdfbox-android:${project.VERSION_NAME}" implementation "androidx.multidex:multidex:2.0.1" implementation 'androidx.appcompat:appcompat:1.5.1' - + implementation 'com.google.android.material:material:1.5.0' // Optional dependencies // Read JPX images diff --git a/sample/src/main/java/com/tom_roush/pdfbox/sample/MainActivity.java b/sample/src/main/java/com/tom_roush/pdfbox/sample/MainActivity.java index 984c4b3e..9a20c4aa 100644 --- a/sample/src/main/java/com/tom_roush/pdfbox/sample/MainActivity.java +++ b/sample/src/main/java/com/tom_roush/pdfbox/sample/MainActivity.java @@ -1,9 +1,11 @@ package com.tom_roush.pdfbox.sample; import android.app.Activity; +import android.content.Intent; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.Menu; @@ -11,7 +13,11 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.documentfile.provider.DocumentFile; + import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -77,7 +83,7 @@ private void setup() { PDFBoxResourceLoader.init(getApplicationContext()); // Find the root of the external storage. - root = getApplicationContext().getCacheDir(); + root = getExternalFilesDir(null); assetManager = getAssets(); tv = (TextView) findViewById(R.id.statusTextView); } @@ -150,14 +156,89 @@ public void createPdf(View v) { } } + private String getPreviewDir() { + File storageDir = new File(getExternalFilesDir("").getAbsolutePath()+"/preview/"); + if (!storageDir.exists()) { + storageDir.mkdirs(); + } + return storageDir.getAbsolutePath()+"/"; + } + + public String getScanImageDir(){ + File storageDir = new File(getExternalFilesDir("").getAbsolutePath()+"/scanHistory/"); + if (!storageDir.exists()) { + storageDir.mkdirs(); + } + return storageDir.getAbsolutePath()+"/"; + } + + public void saveFileByPath(FileInputStream inputStream, String filePath) { + Log.w("ceshi","保存路径:"+filePath); +// Log.w("ceshi","目录:"+filePath.substring(0,filePath.lastIndexOf("/")+1)); + + File dirFile = new File(getScanImageDir()); + if (!dirFile.exists()) { + Log.w("ceshi","临时文件路径创建:"+dirFile.mkdirs()); + } + File target = new File(filePath); + Log.w("ceshi","saveFileByPath="+filePath); + try { + FileOutputStream outputStream = new FileOutputStream(target); + int temp = 0; + byte[] data = new byte[1024]; + while((temp = inputStream.read(data))!=-1) { + outputStream.write(data,0,temp); +// Log.w("ceshi","文件读取中"+temp); + } + inputStream.close(); + outputStream.close(); + } catch (Exception e) { + Log.w("ceshi","saveFileByPathException="+e.toString()); + } + } + + public void openFile(View v) { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + String [] mimeTypes = { +// "image/*", + "application/pdf" +// ,"text/plain","application/vnd.ms-powerpoint", +// "application/vnd.openxmlformats-officedocument.presentationml.presentation", +// "application/msword", +// "application/vnd.openxmlformats-officedocument.wordprocessingml.document", +// "application/vnd.ms-excel", +// "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + }; + intent.setType("*/*"); + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(intent,200); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Uri uri = data.getData(); + if (uri!= null) { + Log.w("ceshi","返回的路径:"+uri.getEncodedPath()); + try { + DocumentFile documentFile = DocumentFile.fromSingleUri(this,uri); + saveFileByPath((FileInputStream) getContentResolver().openInputStream(documentFile.getUri()),getScanImageDir()+documentFile.getName()); + renderFile(documentFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + /** * Loads an existing PDF and renders it to a Bitmap */ - public void renderFile(View v) { + public void renderFile(DocumentFile documentFile) { // Render the page and save it to an image file try { // Load in an already created PDF - PDDocument document = PDDocument.load(assetManager.open("Created.pdf")); + PDDocument document = PDDocument.load(new File(getScanImageDir()+documentFile.getName())); // Create a renderer for the document PDFRenderer renderer = new PDFRenderer(document); // Render the image to an RGB Bitmap diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 0079cc46..67f2ec6d 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -68,4 +68,4 @@ android:layout_alignLeft="@+id/statusTextView" android:layout_below="@+id/statusTextView" /> - \ No newline at end of file +