1731 lines
44 KiB
C
1731 lines
44 KiB
C
/*
|
|
libS2245ImageReProcess -- Re-implemented Image Processing library for
|
|
the Sinfonia CHC-S2245 printer family
|
|
|
|
Copyright (c) 2020 Solomon Peachy <pizza@shaftnet.org>
|
|
|
|
** ** ** ** Do NOT contact Sinfonia about this library! ** ** ** **
|
|
|
|
This is intended to be a drop-in replacement for Sinfonia's proprietary
|
|
libS225IP library, which is necessary in order to utilize their
|
|
CHC-S2245 printer family.
|
|
|
|
Sinfonia Inc was not involved in the creation of this library, and
|
|
is not responsible in any way for the library or any deficiencies in
|
|
its output. They will provide no support if it is used.
|
|
|
|
If you have the appropriate permission fron Sinfonia, we recommend
|
|
you use their official libS2245IP library instead, as it
|
|
will generate the highest quality output. However, it is only
|
|
available for x86/x86_64 targets on Windows. Please contact your local
|
|
Sinfonia distributor to obtain the official library.
|
|
|
|
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3 of the License, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
|
|
SPDX-License-Identifier: GPL-3.0+
|
|
|
|
*/
|
|
|
|
#define LIB_VERSION "0.1.1"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define USE_EXTRA_STUFF // For extensions made to the base library
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Exported Functions
|
|
|
|
bool ip_imageProc(uint16_t *destData, uint8_t *srcInRgb,
|
|
uint16_t width, uint16_t height, void *srcIpp);
|
|
|
|
bool ip_checkIpp(uint16_t width, uint16_t height, void *srcIpp);
|
|
|
|
bool ip_getMemorySize(uint32_t *szMemory,
|
|
uint16_t width, uint16_t height,
|
|
void *srcIpp);
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Endian Manipulation macros
|
|
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
|
#define le16_to_cpu(__x) __x
|
|
#define le32_to_cpu(__x) __x
|
|
#define be16_to_cpu(__x) __builtin_bswap16(__x)
|
|
#define be32_to_cpu(__x) __builtin_bswap32(__x)
|
|
#else
|
|
#define le16_to_cpu(__x) __builtin_bswap16(__x)
|
|
#define le32_to_cpu(__x) __builtin_bswap32(__x)
|
|
#define be16_to_cpu(__x) __x
|
|
#define be32_to_cpu(__x) __x
|
|
#endif
|
|
|
|
#define cpu_to_le16 le16_to_cpu
|
|
#define cpu_to_le32 le32_to_cpu
|
|
#define cpu_to_be16 be16_to_cpu
|
|
#define cpu_to_be32 be32_to_cpu
|
|
|
|
//-------------------------------------------------------------------------
|
|
// External data formats
|
|
|
|
struct ippHeatCorr {
|
|
int32_t tankDivisor[4];
|
|
int32_t tankRowInitVals[4];
|
|
int32_t tankRowOldInitVals[4];
|
|
int32_t tankCoef[5];
|
|
int32_t tankPlusParam;
|
|
int32_t tankMinusParam;
|
|
int32_t tankPlusLimit;
|
|
int32_t tankMinusLimit;
|
|
int32_t useHeatCorrection;
|
|
uint8_t pad_0x58[40];
|
|
} __attribute__((packed));
|
|
|
|
struct SIppData {
|
|
uint16_t field_0x0; // see getMaxPulse
|
|
uint16_t field_0x2; // see getMaxPulse
|
|
uint16_t maxLineSum;
|
|
uint16_t minRowSum;
|
|
uint16_t maxLineCorrectionFactor;
|
|
uint16_t nextWeight;
|
|
uint16_t prevWeight;
|
|
uint16_t mtfPreCalcCutoff;
|
|
uint16_t autoGenMode;
|
|
uint8_t autoGenBase[2];
|
|
uint8_t pad_0x14[6];
|
|
uint16_t pulseExMap[256];
|
|
uint8_t pad_0x21a[2];
|
|
struct ippHeatCorr heatCorrection;
|
|
int16_t heatCorrectionMinusTable[256];
|
|
int16_t heatCorrectionPlusTable[256];
|
|
uint16_t lineCorrection[256];
|
|
uint8_t sideEdgeCorrectionComp[64];
|
|
uint8_t sideEdgeCorrectionTable[256];
|
|
} __attribute__((packed));
|
|
|
|
struct ippHeader {
|
|
char model[16];
|
|
char ipp[4];
|
|
uint8_t version;
|
|
uint8_t pad_0x15[43];
|
|
} __attribute__((packed));
|
|
|
|
struct ippConf {
|
|
uint16_t width; /* Overridden at runtime */
|
|
uint16_t height; /* Overridden at runtime */
|
|
uint16_t headWidth; // Always 1920
|
|
uint8_t planes; // 3 or 4, can be up to 16!
|
|
uint8_t printmode; // Corresponds to corrdata_req field 1
|
|
uint8_t corrections1; // Corresponds to corrdata_req field 2
|
|
uint8_t corrections2; // B0,B1,B2
|
|
uint8_t borderCapable; // 0x02 if we can do 5x7-on-6x8
|
|
uint8_t pad_0xb[21];
|
|
uint8_t planeOrder[16];
|
|
uint8_t pad_0x30[16];
|
|
} __attribute__((packed));
|
|
|
|
struct ippData {
|
|
struct ippHeader header;
|
|
struct ippConf conf;
|
|
struct SIppData plane_rc;
|
|
struct SIppData plane_gm;
|
|
struct SIppData plane_by;
|
|
struct SIppData plane_oc;
|
|
// Can have up to 16 planes, think about this.
|
|
} __attribute__((packed));
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Private Structures
|
|
|
|
struct CHeatCorrProc {
|
|
struct SIppData ippData;
|
|
struct ippHeatCorr heatCorrection;
|
|
uint16_t width;
|
|
uint16_t height;
|
|
uint16_t headWidth;
|
|
// uint16_t pad_0xa62;
|
|
int32_t lineStartOffset; // always 0
|
|
uint16_t maxPulse;
|
|
uint16_t tankWidth;
|
|
// uint8_t pad_0xa6c[4];
|
|
int16_t *tankBuf;
|
|
int16_t *tankRowSrc;
|
|
int32_t *tankRowPtrs[2];
|
|
int32_t *tankRowBufs[5];
|
|
uint32_t curRow;
|
|
uint8_t initialized;
|
|
};
|
|
|
|
struct CIppMng {
|
|
struct ippHeader header;
|
|
struct ippConf conf;
|
|
struct SIppData *ippData;
|
|
uint8_t initialized;
|
|
};
|
|
|
|
struct CImageProc {
|
|
struct CIppMng *ippMng;
|
|
struct ippConf conf;
|
|
struct SIppData planeIPPdata;
|
|
uint32_t pixelsOCG; // width*height*3
|
|
uint32_t pixelsOCM; // width*height*4
|
|
// uint8_t pad_0xa2c[4];
|
|
uint16_t *imageScratchDataPtr;
|
|
uint32_t imageDataLen; // width*height*4planes*2bpp
|
|
// uint8_t pad_0xa3c[4];
|
|
uint16_t *imageDataPtr;
|
|
uint8_t planesOCG;
|
|
uint8_t planesOCM;
|
|
uint8_t currentPlane;
|
|
uint8_t correctMtf;
|
|
uint8_t correctHeat;
|
|
uint8_t correctLine;
|
|
uint8_t correctSideEdge;
|
|
// uint8_t pad_0xa4f;
|
|
uint32_t pixels; // width*height
|
|
int16_t mtfCorrPlaneTable[512];
|
|
uint16_t srcWidth;
|
|
uint16_t srcHeight;
|
|
};
|
|
|
|
struct CMidDataGen {
|
|
struct SIppData *planeIppData;
|
|
uint8_t *outDataPtr;
|
|
uint8_t plane;
|
|
uint8_t pad;
|
|
uint16_t width;
|
|
uint16_t height;
|
|
};
|
|
|
|
struct crop_conf {
|
|
uint16_t startCol;
|
|
uint16_t startRow;
|
|
uint16_t numCols;
|
|
uint16_t numRows;
|
|
};
|
|
|
|
struct pic_data {
|
|
uint8_t *srcPtr;
|
|
uint16_t inCols;
|
|
uint16_t inRows;
|
|
uint16_t outCols;
|
|
uint16_t outRows;
|
|
uint8_t bytes_pp;
|
|
};
|
|
|
|
// Data format Sanity checks
|
|
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
|
|
|
|
STATIC_ASSERT(sizeof(struct ippData) == 10224);
|
|
|
|
#undef STATIC_ASSERT
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Private data declarations
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Private Function declarations
|
|
|
|
/*** CIppMng ***/
|
|
static void CIppMng_Init(struct CIppMng *this)
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
static void CIppMng_Cleanup(struct CIppMng *this)
|
|
{
|
|
if (this->ippData) {
|
|
free(this->ippData);
|
|
this->ippData = NULL;
|
|
}
|
|
}
|
|
|
|
static const char s2245HeaderModel[] = "CHC-S2245 ";
|
|
static const char s2245IppStr[] = "IPP=";
|
|
|
|
static bool CIppMng_CheckHeader(struct CIppMng *this, struct ippData *ippData)
|
|
|
|
{
|
|
memcpy(&this->header, &ippData->header, sizeof(this->header));
|
|
|
|
if (memcmp(this->header.model, s2245HeaderModel, 16))
|
|
return 0;
|
|
if (memcmp(this->header.ipp, s2245IppStr, 4))
|
|
return 0;
|
|
if (this->header.version != 0x3)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_CheckConf(struct CIppMng *this, struct ippData *ippData)
|
|
|
|
{
|
|
uint8_t tmp;
|
|
|
|
#ifndef USE_EXTRA_STUFF
|
|
memcpy(&this->conf, &ippData->conf, sizeof(this->conf));
|
|
#else
|
|
(void)ippData;
|
|
#endif
|
|
|
|
if (!this->conf.headWidth || !this->conf.planes)
|
|
return 0;
|
|
|
|
/* OC mode, Glossy or matte */
|
|
tmp = this->conf.printmode & 0x07;
|
|
if (tmp != 1 && tmp != 2)
|
|
return 0;
|
|
|
|
/* Quality mode, 0 or 1*/
|
|
tmp = (this->conf.printmode >> 3) & 3;
|
|
if (tmp > 1)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_CheckIpp(struct CIppMng *this, struct ippData *ippData)
|
|
{
|
|
bool rval;
|
|
|
|
rval = CIppMng_CheckHeader(this, ippData);
|
|
|
|
if (rval)
|
|
rval = CIppMng_CheckConf(this, ippData);
|
|
|
|
return rval;
|
|
}
|
|
|
|
static bool CIppMng_SetConf(struct CIppMng *this, struct ippData *ippData,
|
|
uint16_t width, uint16_t height)
|
|
|
|
{
|
|
memcpy(&this->conf, &ippData->conf, sizeof(this->conf));
|
|
|
|
if (!width || !height)
|
|
return 0;
|
|
this->conf.width = width;
|
|
this->conf.height = height;
|
|
|
|
#if (__BYTE_ORDER != __LITTLE_ENDIAN)
|
|
this->conf.headWidth = le16_to_cpu(this->conf.headWidth);
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_SetData(struct CIppMng *this, struct ippData *ippData)
|
|
|
|
{
|
|
if (this->ippData)
|
|
free(this->ippData);
|
|
|
|
if (!this->conf.planes)
|
|
return 0;
|
|
|
|
this->ippData = malloc(this->conf.planes * sizeof(*this->ippData));
|
|
if (!this->ippData)
|
|
return 0;
|
|
|
|
memcpy(this->ippData, &ippData->plane_rc, this->conf.planes * sizeof(*this->ippData));
|
|
|
|
#if (__BYTE_ORDER != __LITTLE_ENDIAN)
|
|
#define SWAP16(__x) __x = le16_to_cpu(ippBlock->__x)
|
|
#define SWAP32(__x) __x = le32_to_cpu(ippBlock->__x)
|
|
int i, j;
|
|
for (i = 0 ; i < this->conf.planes ; i++) {
|
|
struct SIppData *ippBlock = &ippData->plane_rc + i;
|
|
swap16(field_0x0);
|
|
swap16(field_0x2);
|
|
swap16(maxLineSum);
|
|
swap16(minRowSum);
|
|
swap16(maxLineCorrecitonFactor);
|
|
swap16(nextWeight);
|
|
swap16(prevWeight);
|
|
swap16(mtfPreCalcCutoff);
|
|
swap16(autoGenMode);
|
|
for (j = 0 ; j < 256 ; j++) {
|
|
swap16(pulseExMap[j]);
|
|
swap16(heatCorrectionMinusTable[j]);
|
|
swap16(heatCorrectionPlusTable[j]);
|
|
swap16(lineCorrection);
|
|
}
|
|
for (j = 0 ; j < 4 ; j++) {
|
|
swap32(heatCorrection.tankDivisor[j]);
|
|
swap32(heatCorrection.tankRowInitVals[j]);
|
|
swap32(heatCorrection.tankRowOldInitVals[j]);
|
|
}
|
|
for (j = 0 ; j < 5 ; j++) {
|
|
swap32(heatCorrection.tankCoef[j]);
|
|
}
|
|
swap32(tankPlusParam);
|
|
swap32(tankMinusParam);
|
|
swap32(tankPlusLimit);
|
|
swap32(tankMinusLimit);
|
|
swap32(useHeatCorrection);
|
|
}
|
|
#undef SWAP16
|
|
#undef SWAP32
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_SetIPP(struct CIppMng *this, struct ippData *ippData,
|
|
uint16_t width, uint16_t height)
|
|
|
|
{
|
|
bool rval;
|
|
|
|
this->initialized = 0;
|
|
|
|
rval = CIppMng_SetConf(this, ippData, width, height);
|
|
if (rval)
|
|
rval = CIppMng_CheckIpp(this, ippData);
|
|
if (rval)
|
|
rval = CIppMng_SetData(this, ippData);
|
|
if (rval)
|
|
this->initialized = 1;
|
|
|
|
return rval;
|
|
}
|
|
|
|
static bool CIppMng_GetNumOfColor(struct CIppMng *this, uint8_t *planesOCG, uint8_t *planesOCM)
|
|
{
|
|
if (!this->initialized)
|
|
return 0;
|
|
|
|
*planesOCG = 3;
|
|
*planesOCM = 4;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_GetIppConf(struct CIppMng *this, struct ippConf *conf,
|
|
uint8_t *planesOCG, uint8_t *planesOCM)
|
|
|
|
{
|
|
if (!this->initialized)
|
|
return 0;
|
|
|
|
memcpy(conf, &this->conf, sizeof(*conf));
|
|
CIppMng_GetNumOfColor(this, planesOCG, planesOCM);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_GetIppNo(struct CIppMng *this, uint8_t *planeOffset, uint8_t plane)
|
|
{
|
|
if (!this->initialized || plane > 0x10)
|
|
return 0;
|
|
|
|
*planeOffset = this->conf.planeOrder[plane];
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CIppMng_GetIppData(struct CIppMng *this, struct SIppData *destPtr, uint8_t planeOffset)
|
|
|
|
{
|
|
if (!this->initialized || planeOffset >= this->conf.planes)
|
|
return 0;
|
|
|
|
memcpy(destPtr, &this->ippData[planeOffset], sizeof (*destPtr));
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*** CMidDataGen ***/
|
|
|
|
static void CMidDataGen_Init(struct CMidDataGen *this)
|
|
{
|
|
this->planeIppData = NULL;
|
|
}
|
|
|
|
static bool CMidDataGen_CheckAutoGenNo(struct CMidDataGen *this)
|
|
|
|
{
|
|
return (this->planeIppData->autoGenMode == 1 || // glossy
|
|
this->planeIppData->autoGenMode == 2); // matte
|
|
}
|
|
|
|
static void CMidDataGen_GD01Proc(struct CMidDataGen *this, uint8_t *outDataPtr,
|
|
uint16_t width, uint16_t height, uint8_t *autoGenBase)
|
|
{
|
|
memset(outDataPtr, *autoGenBase, height * width);
|
|
(void)this;
|
|
}
|
|
|
|
static const uint8_t GD_02_MIDDATA[288] = {
|
|
0xB3, 0xBD, 0x93, 0x27, 0xD6, 0x9F, 0xF6, 0xBD, 0xB3, 0x7D, 0xD6, 0x98, 0x36, 0xBD, 0x33, 0xBD,
|
|
0x5C, 0xE2, 0x66, 0xA9, 0x3A, 0x0D, 0x7D, 0xFE, 0x4C, 0xEB, 0xC4, 0xED, 0xCD, 0xEC, 0x5D, 0xEF,
|
|
0xD9, 0x8C, 0x9F, 0x89, 0x71, 0xAF, 0x5B, 0x4E, 0xB1, 0x1B, 0x31, 0xB9, 0xDB, 0x63, 0x36, 0x7A,
|
|
0x87, 0x33, 0x11, 0xF3, 0xFC, 0xDF, 0xEE, 0x7D, 0xB7, 0xBE, 0x5F, 0x0E, 0xED, 0x6C, 0x92, 0x9C,
|
|
0xDF, 0x78, 0xCD, 0xCE, 0xF1, 0x8C, 0xD1, 0x5F, 0x50, 0xEA, 0x9C, 0xFD, 0x5F, 0x53, 0x66, 0xFB,
|
|
0x9F, 0x9C, 0x76, 0xFB, 0x6E, 0x3B, 0x47, 0xCE, 0x4E, 0xF9, 0xBA, 0x53, 0xFE, 0xFF, 0x7A, 0x7D,
|
|
0x92, 0xD3, 0x7E, 0xF2, 0x73, 0x77, 0xD7, 0xD7, 0x36, 0xC7, 0x26, 0xC7, 0x57, 0xDC, 0x92, 0x99,
|
|
0xF6, 0x19, 0x72, 0xC8, 0xFB, 0xBC, 0xFE, 0x3C, 0x3E, 0xEB, 0xF8, 0xA6, 0x76, 0xFE, 0x26, 0x7B,
|
|
0xD8, 0xF6, 0x16, 0x63, 0xF2, 0xCA, 0xDF, 0x24, 0x16, 0x79, 0xF9, 0xCE, 0xD3, 0xEF, 0x93, 0x7D,
|
|
0x1F, 0xE6, 0xD8, 0xE7, 0xCF, 0x5B, 0xF2, 0xE3, 0x97, 0x35, 0xF8, 0x48, 0xF6, 0x69, 0x36, 0x9D,
|
|
0xF3, 0x47, 0x67, 0xCF, 0x76, 0x99, 0x13, 0xE7, 0x4F, 0x97, 0xF6, 0xF9, 0xCE, 0x27, 0x57, 0x94,
|
|
0xCE, 0x4D, 0xCE, 0x39, 0xE5, 0x90, 0xFF, 0x0C, 0x03, 0xBB, 0xEC, 0xF9, 0x32, 0x9E, 0x77, 0xB2,
|
|
0x8E, 0x79, 0x22, 0x87, 0xD1, 0xFE, 0xBA, 0x49, 0xCF, 0xE5, 0xCF, 0x7E, 0xFB, 0x8B, 0x09, 0x95,
|
|
0xEC, 0xE6, 0x43, 0x3B, 0xF3, 0x9D, 0x69, 0xEE, 0x7F, 0x6B, 0x13, 0xEB, 0x73, 0x08, 0x18, 0xF7,
|
|
0xF3, 0x67, 0xF8, 0x7F, 0xDF, 0x33, 0xFB, 0x65, 0xD1, 0xE3, 0x61, 0x7C, 0xBE, 0x79, 0xDF, 0xE1,
|
|
0x39, 0xDF, 0x33, 0xF3, 0xC7, 0xF8, 0x19, 0x17, 0x59, 0x46, 0xEE, 0x73, 0xFD, 0x2F, 0xDC, 0x3F,
|
|
0xAB, 0x77, 0x6E, 0xE6, 0x9C, 0x9F, 0x39, 0x67, 0xEC, 0xF4, 0xDC, 0xF9, 0x7C, 0x4C, 0x6E, 0x72,
|
|
0xDF, 0x44, 0xCE, 0xCE, 0xEC, 0x6D, 0xD9, 0x4D, 0xFA, 0xA6, 0x3F, 0xAD, 0xD9, 0x05, 0xD3, 0xB0
|
|
};
|
|
|
|
static void CMidDataGen_GD02Proc(struct CMidDataGen *this, uint8_t *outDataPtr,
|
|
uint16_t width, uint16_t height, uint8_t *autoGenBase)
|
|
|
|
{
|
|
const uint8_t *scratch = GD_02_MIDDATA;
|
|
uint16_t row;
|
|
uint8_t *outPtr = outDataPtr;
|
|
|
|
for (row = 0 ; row < height ; row++) {
|
|
uint16_t col;
|
|
for (col = 0 ; col < width ; col++) {
|
|
uint8_t outVal;
|
|
if ((scratch[(col % 0x30 + (row % 0x30) * 0x30) >> 3] &
|
|
(1 << (((col % 0x30) % 8) & 0x1f))) == 0) {
|
|
outVal = autoGenBase[0];
|
|
} else {
|
|
outVal = autoGenBase[1];
|
|
}
|
|
*outPtr = outVal;
|
|
outPtr++;
|
|
}
|
|
}
|
|
(void)this;
|
|
}
|
|
|
|
static void CMidDataGen_GenDataEx(struct CMidDataGen *this)
|
|
|
|
{
|
|
uint16_t autogen;
|
|
|
|
autogen = this->planeIppData->autoGenMode;
|
|
if (autogen == 1) { // glossy
|
|
CMidDataGen_GD01Proc(this, this->outDataPtr + this->width * this->height * this->plane,
|
|
this->width, this->height, this->planeIppData->autoGenBase);
|
|
} else if (autogen == 2) { // matte
|
|
CMidDataGen_GD02Proc(this, this->outDataPtr + this->width * this->height * this->plane,
|
|
this->width, this->height, this->planeIppData->autoGenBase);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static bool CMidDataGen_GenData(struct CMidDataGen *this, uint8_t *outDataPtr, uint8_t plane,
|
|
uint16_t width, uint16_t height, struct SIppData *ippData)
|
|
{
|
|
if (!outDataPtr || !width || !height || !ippData)
|
|
return 0;
|
|
|
|
this->outDataPtr = outDataPtr;
|
|
this->plane = plane;
|
|
this->width = width;
|
|
this->height = height;
|
|
this->planeIppData = ippData;
|
|
|
|
if (!CMidDataGen_CheckAutoGenNo(this))
|
|
return 0;
|
|
CMidDataGen_GenDataEx(this);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*** CHeatCorrProc ***/
|
|
static void CHeatCorrProc_Init(struct CHeatCorrProc *this)
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
static bool CHeatCorrProc_SetIppData(struct CHeatCorrProc *this, struct SIppData *ippData,
|
|
uint16_t width, uint16_t height, uint16_t headWidth,
|
|
uint16_t maxPulse)
|
|
|
|
{
|
|
memcpy(&this->ippData, ippData, sizeof(this->ippData));
|
|
memcpy(&this->heatCorrection, &this->ippData.heatCorrection, sizeof(this->heatCorrection));
|
|
this->width = width;
|
|
this->height = height;
|
|
this->headWidth = headWidth;
|
|
this->maxPulse = maxPulse;
|
|
|
|
if (this->width > this->headWidth)
|
|
return 0;
|
|
|
|
this->lineStartOffset = 0;
|
|
this->initialized = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CHeatCorrProc_InitTank(struct CHeatCorrProc *this)
|
|
|
|
{
|
|
bool rval = 0;
|
|
int i;
|
|
|
|
#ifdef USE_EXTRA_STUFF
|
|
this->tankWidth = this->width + 5; /* Sinfonia algorithms read 1 element past this buffer */
|
|
#else
|
|
this->tankWidth = this->width + 4;
|
|
#endif
|
|
if (!this->tankRowBufs[0]) {
|
|
this->tankRowBufs[0] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowBufs[0])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowBufs[0][i] = this->heatCorrection.tankRowInitVals[3];
|
|
}
|
|
if (!this->tankRowBufs[1]) {
|
|
this->tankRowBufs[1] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowBufs[1])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowBufs[1][i] = this->heatCorrection.tankRowInitVals[2];
|
|
}
|
|
if (!this->tankRowBufs[2]) {
|
|
this->tankRowBufs[2] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowBufs[2])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowBufs[2][i] = this->heatCorrection.tankRowInitVals[1];
|
|
}
|
|
if (!this->tankRowBufs[3]) {
|
|
this->tankRowBufs[3] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowBufs[3])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowBufs[3][i] = this->heatCorrection.tankRowInitVals[0];
|
|
}
|
|
if (!this->tankRowBufs[4]) {
|
|
this->tankRowBufs[4] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowBufs[4])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowBufs[4][i] = 0;
|
|
}
|
|
if (!this->tankRowPtrs[0]) {
|
|
this->tankRowPtrs[0] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowPtrs[0])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowPtrs[0][i] = 0;
|
|
}
|
|
if (!this->tankRowPtrs[1]) {
|
|
this->tankRowPtrs[1] = malloc(this->tankWidth * sizeof(uint32_t));
|
|
if (!this->tankRowPtrs[1])
|
|
goto done;
|
|
}
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowPtrs[1][i] = 0;
|
|
}
|
|
|
|
#ifdef USE_EXTRA_STUFF
|
|
this->tankWidth--;
|
|
#endif
|
|
|
|
rval = 1;
|
|
done:
|
|
return rval;
|
|
}
|
|
|
|
static void CHeatCorrProc_PreReadLine(struct CHeatCorrProc *this, uint16_t *tankSrc, uint16_t useHeatCorrection)
|
|
|
|
{
|
|
int i;
|
|
int heatStep;
|
|
int rowStep;
|
|
|
|
if (!useHeatCorrection)
|
|
return;
|
|
|
|
if (useHeatCorrection > 0xc)
|
|
useHeatCorrection = 0xc;
|
|
|
|
for (i = 0 ; i < this->tankWidth ; i++) {
|
|
this->tankRowBufs[4][i] = 0;
|
|
}
|
|
|
|
for (heatStep = useHeatCorrection, rowStep = 0 ; heatStep > 0 && ((rowStep + this->curRow) < this->height) ; heatStep--, rowStep++) {
|
|
int col;
|
|
|
|
int *rowBufPtr = this->tankRowBufs[4] + this->lineStartOffset + 2;
|
|
for (col = 0; col < this->width ; col++) {
|
|
*rowBufPtr += heatStep * *tankSrc;
|
|
tankSrc++;
|
|
rowBufPtr++;
|
|
}
|
|
}
|
|
/* If we stopped early, clean up! */
|
|
if (heatStep != useHeatCorrection) {
|
|
int col;
|
|
int local_50;
|
|
int local_48 = useHeatCorrection;
|
|
int divisor = 0;
|
|
int *rowBufPtr;
|
|
|
|
for (local_50 = useHeatCorrection - heatStep ; local_50 > 0 ; local_50--) {
|
|
divisor += local_48;
|
|
local_48--;
|
|
}
|
|
if (divisor == 0) {
|
|
divisor = 1;
|
|
}
|
|
rowBufPtr = this->tankRowBufs[4] + this->lineStartOffset + 2;
|
|
for (col = 0 ; col < this->width ; col++) {
|
|
*rowBufPtr /= divisor;
|
|
rowBufPtr++;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static uint16_t CHeatCorrProc_GetBitsOfPulse(struct CHeatCorrProc *this, uint16_t maxPulse)
|
|
|
|
{
|
|
uint16_t i;
|
|
|
|
for (i = 0 ; maxPulse != 0 ; i++) {
|
|
maxPulse >>= 1;
|
|
}
|
|
(void)this;
|
|
return i;
|
|
}
|
|
|
|
|
|
static int32_t CHeatCorrProc_GetCorrPulsePreRead(struct CHeatCorrProc *this, int srcVal, int param_2)
|
|
|
|
{
|
|
int32_t local_28;
|
|
int32_t local_24;
|
|
int32_t local_20;
|
|
|
|
if (this->heatCorrection.useHeatCorrection == 0)
|
|
return 0;
|
|
|
|
param_2 -= srcVal;
|
|
|
|
if (param_2 == 0)
|
|
return 0;
|
|
|
|
if (param_2 < 1) {
|
|
local_24 = (this->heatCorrection).tankMinusLimit;
|
|
local_28 = (this->heatCorrection).tankMinusParam;
|
|
local_20 = -param_2;
|
|
} else {
|
|
local_24 = (this->heatCorrection).tankPlusLimit;
|
|
local_28 = (this->heatCorrection).tankPlusParam;
|
|
local_20 = param_2;
|
|
}
|
|
if (local_20 < local_24) {
|
|
return 0;
|
|
}
|
|
|
|
return (local_28 * param_2 >> 10);
|
|
}
|
|
|
|
static void CHeatCorrProc_CorrectEx(struct CHeatCorrProc *this, uint16_t *tankBuf, uint16_t *tankRowSrc, uint8_t *scratchRowBuf)
|
|
{
|
|
uint16_t col;
|
|
uint8_t pulseBits;
|
|
int32_t tankDivisor;
|
|
|
|
int32_t pulsePreRead;
|
|
int32_t outPulse;
|
|
int32_t heatCorrection;
|
|
int32_t *local_48;
|
|
int32_t *local_40;
|
|
uint16_t *srcPixel;
|
|
uint8_t *scratchPtr;
|
|
|
|
pulseBits = CHeatCorrProc_GetBitsOfPulse(this,this->maxPulse);
|
|
tankDivisor = this->heatCorrection.tankDivisor[3];
|
|
|
|
local_40 = this->tankRowBufs[0] + (long)this->lineStartOffset + 2;
|
|
local_48 = this->tankRowBufs[4] + (long)this->lineStartOffset + 2;
|
|
srcPixel = tankRowSrc;
|
|
scratchPtr = scratchRowBuf;
|
|
for (col = this->width ; col != 0 ; col --) {
|
|
int iVar4 = *srcPixel -
|
|
((((0x100000 << (pulseBits & 0x1f)) / tankDivisor) * (*srcPixel + *local_40)) >> 0x14);
|
|
if (iVar4 == 0) {
|
|
heatCorrection = 0;
|
|
} else {
|
|
if (iVar4 < 1) {
|
|
heatCorrection = (this->ippData).heatCorrectionPlusTable[*scratchPtr];
|
|
} else {
|
|
heatCorrection = (this->ippData).heatCorrectionMinusTable[*scratchPtr];
|
|
}
|
|
}
|
|
pulsePreRead = CHeatCorrProc_GetCorrPulsePreRead(this, *srcPixel, *local_48);
|
|
outPulse = pulsePreRead + *srcPixel + ((iVar4 * heatCorrection) >> (pulseBits & 0x1f));
|
|
if (outPulse < 0) {
|
|
outPulse = 0;
|
|
} else {
|
|
if (this->maxPulse < outPulse) {
|
|
outPulse = this->maxPulse;
|
|
}
|
|
}
|
|
*tankBuf = outPulse;
|
|
*local_40 += outPulse;
|
|
srcPixel++;
|
|
tankBuf++;
|
|
scratchPtr++;
|
|
local_40++;
|
|
local_48++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void CHeatCorrProc_GetTankCoefTransfer(struct CHeatCorrProc *this, int32_t *param_1, int32_t *param_2, int32_t *param_3,
|
|
int32_t *param_4, int32_t *param_5, int32_t *param_6, int32_t *param_7, int32_t *param_8)
|
|
|
|
{
|
|
*param_1 = 0x10000;
|
|
*param_1 *= this->heatCorrection.tankCoef[4];
|
|
*param_1 /= this->heatCorrection.tankDivisor[3];
|
|
*param_2 = 0x10000;
|
|
*param_2 *= this->heatCorrection.tankCoef[3];
|
|
*param_2 /= this->heatCorrection.tankDivisor[3];
|
|
*param_3 = 0x10000;
|
|
*param_3 *= this->heatCorrection.tankCoef[3];
|
|
*param_3 /= this->heatCorrection.tankDivisor[2];
|
|
*param_4 = 0x10000;
|
|
*param_4 *= this->heatCorrection.tankCoef[2];
|
|
*param_4 /= this->heatCorrection.tankDivisor[2];
|
|
*param_5 = 0x10000;
|
|
*param_5 *= this->heatCorrection.tankCoef[2];
|
|
*param_5 /= this->heatCorrection.tankDivisor[1];
|
|
*param_6 = 0x10000;
|
|
*param_6 *= this->heatCorrection.tankCoef[1];
|
|
*param_6 /= this->heatCorrection.tankDivisor[1];
|
|
*param_7 = 0x10000;
|
|
*param_7 *= this->heatCorrection.tankCoef[1];
|
|
*param_7 /= this->heatCorrection.tankDivisor[0];
|
|
*param_8 = 0x10000;
|
|
*param_8 *= this->heatCorrection.tankCoef[0];
|
|
*param_8 /= this->heatCorrection.tankDivisor[0];
|
|
}
|
|
|
|
static void CHeatCorrProc_TankHeatTransferEx(struct CHeatCorrProc *this, int32_t *param_1, int32_t *param_2, int32_t *param_3,
|
|
int32_t param_4, int32_t param_5, int32_t param_6, int32_t param_7)
|
|
|
|
{
|
|
int local_54;
|
|
int local_50;
|
|
uint16_t col;
|
|
int *local_48 = NULL;
|
|
int *local_40;
|
|
int *local_38 = NULL;
|
|
|
|
if (0 < param_4) {
|
|
local_38 = param_1 + 2;
|
|
}
|
|
|
|
local_40 = param_2 + 2;
|
|
if (0 < param_7) {
|
|
local_48 = param_3 + 2;
|
|
}
|
|
|
|
for (col = this->width ; col != 0 ; col--) {
|
|
local_50 = *local_40 * param_5;
|
|
if (0 < param_4) {
|
|
local_50 -= *local_38 * param_4;
|
|
}
|
|
if (param_7 < 1) {
|
|
local_54 = 0;
|
|
} else {
|
|
local_54 = *local_48 * param_7;
|
|
}
|
|
*local_40 = ((local_54 - *local_40 * param_6) >> 0x10) + (*local_40 - (local_50 >> 0x10));
|
|
if (0 < param_4) {
|
|
local_38++;
|
|
}
|
|
local_40++;
|
|
if (0 < param_7) {
|
|
local_48++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Computes the heat transfer across a single horizontal scanline! */
|
|
static void CHeatCorrProc_DotHeatTransExRevOld(struct CHeatCorrProc *this, int32_t param_1, int32_t *tankRowBuf)
|
|
|
|
{
|
|
int i;
|
|
int32_t *outPtr;
|
|
int32_t local_50;
|
|
int32_t local_4c;
|
|
int32_t local_48;
|
|
int32_t pixelPlusTwo;
|
|
int32_t pixelPlusOne;
|
|
int32_t pixelCurrent;
|
|
int32_t *local_38;
|
|
|
|
/* Initialize shoulders at either side (-2/+2) */
|
|
for (i = 0 ; i < 2 ; i++) {
|
|
tankRowBuf[i] = tankRowBuf[2];
|
|
tankRowBuf[this->tankWidth - 1 - i] = tankRowBuf[this->tankWidth - 3];
|
|
}
|
|
#ifdef USE_EXTRA_STUFF
|
|
/* We allocated an extra element at the end; fill it in */
|
|
tankRowBuf[this->tankWidth] = tankRowBuf[this->tankWidth-1];
|
|
#endif
|
|
pixelCurrent = tankRowBuf[2];
|
|
|
|
param_1 /= 2;
|
|
local_48 = param_1 * (*tankRowBuf + tankRowBuf[1] * -2 + pixelCurrent);
|
|
pixelPlusOne = tankRowBuf[3];
|
|
local_4c = param_1 * (tankRowBuf[1] + pixelCurrent * -2 + pixelPlusOne);
|
|
local_50 = pixelCurrent + pixelPlusOne * -2 + tankRowBuf[4];
|
|
outPtr = tankRowBuf + 2;
|
|
pixelPlusTwo = tankRowBuf[4];
|
|
local_38 = tankRowBuf + 5; // NOTE: this overflows the buffer on the last element, as buffer is +- 2 but this is +3! We work around it with USE_EXTRA_STUFF.
|
|
|
|
for (i = this->width ; i > 0 ; i--) {
|
|
int32_t outPixel;
|
|
|
|
local_50 *= param_1;
|
|
outPixel = ((local_4c >> 6) + pixelCurrent) -
|
|
(param_1 * (((local_4c * 2 - local_48) - local_50) >> 7) >> 7);
|
|
if (outPixel < 0) {
|
|
outPixel = 0;
|
|
}
|
|
local_48 = local_4c;
|
|
local_4c = local_50;
|
|
local_50 = pixelPlusOne + pixelPlusTwo * -2 + *local_38;
|
|
pixelCurrent = pixelPlusOne;
|
|
pixelPlusOne = pixelPlusTwo;
|
|
pixelPlusTwo = *local_38;
|
|
*outPtr = outPixel;
|
|
outPtr++;
|
|
local_38++;
|
|
}
|
|
}
|
|
|
|
static void CHeatCorrProc_HeatTransferProc(struct CHeatCorrProc *this)
|
|
|
|
{
|
|
int32_t local_48;
|
|
int32_t local_44;
|
|
int32_t local_40;
|
|
int32_t local_3c;
|
|
int32_t local_38;
|
|
int32_t local_34;
|
|
int32_t local_30;
|
|
int32_t local_2c;
|
|
|
|
CHeatCorrProc_GetTankCoefTransfer(this, &local_2c, &local_30, &local_34, &local_38,
|
|
&local_3c, &local_40, &local_44, &local_48);
|
|
memcpy(this->tankRowPtrs[0], this->tankRowBufs[0], this->tankWidth * 4);
|
|
|
|
CHeatCorrProc_TankHeatTransferEx(this, NULL, this->tankRowBufs[0], this->tankRowBufs[1],
|
|
0, local_2c, local_30, local_34);
|
|
memcpy(this->tankRowPtrs[1], this->tankRowBufs[1], this->tankWidth * 4);
|
|
|
|
CHeatCorrProc_TankHeatTransferEx(this, this->tankRowPtrs[0], this->tankRowBufs[1], this->tankRowBufs[2],
|
|
local_30, local_34, local_38, local_3c);
|
|
memcpy(this->tankRowPtrs[0], this->tankRowBufs[2], this->tankWidth * 4);
|
|
|
|
CHeatCorrProc_TankHeatTransferEx(this, this->tankRowPtrs[1], this->tankRowBufs[2], this->tankRowBufs[3],
|
|
local_38, local_3c, local_40, local_44);
|
|
CHeatCorrProc_TankHeatTransferEx(this, this->tankRowPtrs[0], this->tankRowBufs[3], NULL,
|
|
local_40, local_44, local_48, 0);
|
|
|
|
CHeatCorrProc_DotHeatTransExRevOld(this, this->heatCorrection.tankRowOldInitVals[3], this->tankRowBufs[0]);
|
|
CHeatCorrProc_DotHeatTransExRevOld(this, this->heatCorrection.tankRowOldInitVals[2], this->tankRowBufs[1]);
|
|
CHeatCorrProc_DotHeatTransExRevOld(this, this->heatCorrection.tankRowOldInitVals[1], this->tankRowBufs[2]);
|
|
CHeatCorrProc_DotHeatTransExRevOld(this, this->heatCorrection.tankRowOldInitVals[0], this->tankRowBufs[3]);
|
|
}
|
|
|
|
static bool CHeatCorrProc_Correction(struct CHeatCorrProc *this,
|
|
uint16_t *destData, uint16_t *srcData,
|
|
uint8_t *scratchData)
|
|
{
|
|
bool rval = 0;
|
|
uint32_t pixels;
|
|
int i;
|
|
|
|
if (!this->initialized || !this->width || !this->height)
|
|
goto done;
|
|
|
|
pixels = this->width * this->height;
|
|
|
|
this->tankBuf = malloc(pixels * 2);
|
|
if (!this->tankBuf)
|
|
goto done;
|
|
|
|
CHeatCorrProc_InitTank(this);
|
|
this->tankRowSrc = (int16_t*) srcData;
|
|
|
|
for (this->curRow = 0 ; this->curRow < this->height ; this->curRow++) {
|
|
uint16_t width;
|
|
uint16_t tankWidth;
|
|
uint16_t scratchWidth;
|
|
uint32_t row;
|
|
uint32_t tankRow;
|
|
uint32_t scratchRow;
|
|
|
|
row = this->curRow;
|
|
width = this->width;
|
|
tankRow = this->curRow;
|
|
tankWidth = this->width;
|
|
scratchRow = this->curRow;
|
|
scratchWidth = this->width;
|
|
|
|
CHeatCorrProc_PreReadLine(this, (uint16_t *)(this->tankRowSrc + (tankRow * tankWidth)),
|
|
this->heatCorrection.useHeatCorrection);
|
|
CHeatCorrProc_CorrectEx(this,(uint16_t *)(this->tankBuf + (row * width)),
|
|
(uint16_t *)(this->tankRowSrc + (tankRow * tankWidth)),
|
|
scratchData + (scratchRow * scratchWidth));
|
|
CHeatCorrProc_HeatTransferProc(this);
|
|
}
|
|
|
|
memcpy(destData, this->tankBuf, pixels * 2);
|
|
rval = 1;
|
|
done:
|
|
|
|
if (this->tankBuf) {
|
|
free(this->tankBuf);
|
|
this->tankBuf = NULL;
|
|
}
|
|
for (i = 0 ; i < 2 ; i++) {
|
|
if (this->tankRowPtrs[i]) {
|
|
free(this->tankRowPtrs[i]);
|
|
this->tankRowPtrs[i] = NULL;
|
|
}
|
|
}
|
|
for (i = 0 ; i < 5 ; i++) {
|
|
if (this->tankRowBufs[i]) {
|
|
free(this->tankRowBufs[i]);
|
|
this->tankRowBufs[i] = NULL;
|
|
}
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
/*** CImageProc ***/
|
|
|
|
static void CImageProc_Init(struct CImageProc *this, struct CIppMng *ippMng)
|
|
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
this->ippMng = ippMng;
|
|
return;
|
|
}
|
|
|
|
static bool CImageProc_Initialize(struct CImageProc *this)
|
|
{
|
|
this->pixels = 0;
|
|
|
|
CIppMng_GetIppConf(this->ippMng, &this->conf, &this->planesOCG, &this->planesOCM);
|
|
|
|
/* Sanity checks */
|
|
if (!this->conf.width || !this->conf.height || !this->conf.headWidth ||
|
|
!this->planesOCG || !this->planesOCM)
|
|
return 0;
|
|
|
|
/* If this is a 5x7 print.. */
|
|
if (this->conf.borderCapable == 0x02 &&
|
|
this->conf.width == 1548 &&
|
|
this->conf.height == 2140) {
|
|
this->srcWidth = this->conf.width;
|
|
this->srcHeight = this->conf.height;
|
|
this->conf.width = 1844;
|
|
this->conf.height = 2434;
|
|
}
|
|
this->correctMtf = this->conf.corrections1 & 1;
|
|
this->correctHeat = this->conf.corrections2 & 1;
|
|
this->correctLine = (this->conf.corrections2 & 2) >> 1;
|
|
this->correctSideEdge = (this->conf.corrections2 & 4) >> 2;
|
|
|
|
this->pixelsOCG = this->conf.width * this->conf.height * this->planesOCG;
|
|
this->pixelsOCM = this->conf.width * this->conf.height * this->planesOCM;
|
|
|
|
this->imageScratchDataPtr = malloc(this->pixelsOCM);
|
|
if (!this->imageScratchDataPtr)
|
|
return 0;
|
|
|
|
this->pixels = this->conf.width * this->conf.height;
|
|
this->imageDataLen = this->pixels * this->planesOCM * 2;
|
|
this->imageDataPtr = malloc(this->imageDataLen);
|
|
if (!this->imageDataPtr) {
|
|
free(this->imageScratchDataPtr);
|
|
this->imageScratchDataPtr = NULL;
|
|
return 0;
|
|
}
|
|
memset(this->imageDataPtr, 0, this->imageDataLen);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int CImageProc_CropPicDotSeq(struct CImageProc *this, uint8_t *destPtr,
|
|
struct pic_data *picData, struct crop_conf *cropConf)
|
|
|
|
{
|
|
uint16_t cols, rows;
|
|
uint8_t bypp;
|
|
uint8_t *scratch;
|
|
int row;
|
|
int offset;
|
|
|
|
cols = cropConf->numCols;
|
|
rows = cropConf->numRows;
|
|
bypp = picData->bytes_pp;
|
|
|
|
scratch = malloc(cols * rows * bypp);
|
|
if (!scratch)
|
|
return -1;
|
|
|
|
for (row = cropConf->startRow, offset = 0; row < (cropConf->startRow + cropConf->numRows) ; row++) {
|
|
int col;
|
|
for (col = cropConf->startCol; col < (cropConf->startCol + cropConf->numCols) ; col++) {
|
|
uint32_t srcOffset = picData->bytes_pp * (col + row * picData->outCols);
|
|
int p;
|
|
for (p = 0 ; p < picData->bytes_pp ; p ++) {
|
|
scratch[offset] = picData->srcPtr[srcOffset];
|
|
srcOffset++;
|
|
offset++;
|
|
}
|
|
}
|
|
}
|
|
|
|
memcpy(destPtr, scratch, cols * rows * bypp);
|
|
if (scratch)
|
|
free(scratch);
|
|
|
|
(void)this; /* Shut up, compiler */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int CImageProc_AddBorderEx(struct CImageProc *this, uint8_t *destPtr, uint8_t *srcPtr,
|
|
struct pic_data *picData)
|
|
|
|
{
|
|
uint32_t outBufLen;
|
|
uint8_t *outBuf;
|
|
uint32_t outOffset, srcOffset;
|
|
int row;
|
|
|
|
if (picData->outCols < picData->inCols ||
|
|
picData->outRows < picData->inRows)
|
|
return -2;
|
|
|
|
outBufLen = picData->outCols * picData->outRows * picData->bytes_pp;
|
|
outBuf = malloc(outBufLen);
|
|
if (!outBuf)
|
|
return -1;
|
|
|
|
memset(outBuf, 0xff, outBufLen);
|
|
|
|
srcOffset = 0;
|
|
for (row = 0; row < picData->inRows ; row++) {
|
|
int col;
|
|
for (col = 0 ; col < picData->inCols ; col++) {
|
|
int j;
|
|
|
|
outOffset = picData->bytes_pp *
|
|
(col + ((picData->outCols - picData->inCols) / 2) +
|
|
((row + ((picData->outRows - picData->inRows) / 2)) *
|
|
picData->outCols));
|
|
|
|
for (j = 0 ; j < picData->bytes_pp ; j++) {
|
|
outBuf[outOffset] = srcPtr[srcOffset];
|
|
outOffset++;
|
|
srcOffset++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(destPtr, outBuf, outBufLen);
|
|
free(outBuf);
|
|
|
|
(void)this; /* Shut up, compiler */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool CImageProc_AddBorder(struct CImageProc *this, uint8_t *destPtr, uint8_t *srcRGBPtr)
|
|
|
|
{
|
|
/* If this is a 5x7 print.. */
|
|
if (this->conf.borderCapable == 0x02 &&
|
|
this->srcWidth == 1548 &&
|
|
this->srcHeight == 2140) {
|
|
struct pic_data borderPicData;
|
|
struct crop_conf cropConf;
|
|
struct pic_data cropPicData;
|
|
|
|
cropPicData.inCols = 1548;
|
|
cropPicData.inRows = 2140;
|
|
cropPicData.outCols = 1548;
|
|
cropPicData.outRows = 2140;
|
|
cropPicData.bytes_pp = 3;
|
|
cropPicData.srcPtr = srcRGBPtr;
|
|
|
|
cropConf.startCol = 24;
|
|
cropConf.startRow = 18;
|
|
cropConf.numCols = 1504;
|
|
cropConf.numRows = 2104;
|
|
|
|
if (CImageProc_CropPicDotSeq(this, destPtr, &cropPicData, &cropConf))
|
|
return 0;
|
|
|
|
borderPicData.inCols = 1504;
|
|
borderPicData.inRows = 2104;
|
|
borderPicData.outCols = 1844;
|
|
borderPicData.outRows = 2434;
|
|
borderPicData.bytes_pp = 3;
|
|
borderPicData.srcPtr = destPtr;
|
|
if (CImageProc_AddBorderEx(this, destPtr, destPtr, &borderPicData))
|
|
return 0;
|
|
|
|
} else {
|
|
memcpy(destPtr, srcRGBPtr, this->pixelsOCG);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CImageProc_TransDotToPlane(struct CImageProc *this, uint8_t *destPtr, uint8_t *srcPtr)
|
|
{
|
|
uint8_t *workBuf;
|
|
uint32_t offset;
|
|
|
|
workBuf = malloc(this->pixelsOCG);
|
|
if (!workBuf)
|
|
return 0;
|
|
|
|
for (offset = 0 ; offset < this->pixelsOCG ; offset++) {
|
|
workBuf[((this->planesOCG - 1) - offset % this->planesOCG) *
|
|
(this->pixelsOCG / this->planesOCG) + offset / this->planesOCG] = srcPtr[offset] ^ 0xff;
|
|
}
|
|
|
|
memcpy(destPtr, workBuf, this->pixelsOCG);
|
|
free(workBuf);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CImageProc_GetIppData(struct CImageProc *this, uint8_t plane)
|
|
|
|
{
|
|
return CIppMng_GetIppData(this->ippMng, &this->planeIPPdata, plane);
|
|
}
|
|
|
|
static bool CImageProc_SetProcConfig(struct CImageProc *this, uint8_t plane)
|
|
|
|
{
|
|
bool rval;
|
|
uint8_t planeOffset;
|
|
|
|
this->currentPlane = plane;
|
|
rval = CIppMng_GetIppNo(this->ippMng, &planeOffset, this->currentPlane);
|
|
if (rval)
|
|
rval = CImageProc_GetIppData(this, planeOffset);
|
|
|
|
return rval;
|
|
}
|
|
|
|
|
|
static bool CImageProc_MiddleDataGen(struct CImageProc *this, uint8_t plane)
|
|
|
|
{
|
|
struct CMidDataGen midData;
|
|
|
|
CMidDataGen_Init(&midData);
|
|
|
|
return CMidDataGen_GenData(&midData, (uint8_t *)this->imageScratchDataPtr, plane,
|
|
this->conf.width, this->conf.height, &this->planeIPPdata);
|
|
}
|
|
|
|
|
|
static void CImageProc_MtfPreCalcTableGen(struct CImageProc *this)
|
|
|
|
{
|
|
uint16_t uVar1;
|
|
int16_t i;
|
|
|
|
uVar1 = (this->planeIPPdata).mtfPreCalcCutoff;
|
|
for (i = -0x100 ; i < 0x100 ; i++) { // XXX this is a 512 element array!
|
|
if (i * i < uVar1 * uVar1) {
|
|
this->mtfCorrPlaneTable[i + 0x100] = -i;
|
|
} else {
|
|
this->mtfCorrPlaneTable[i + 0x100] = i;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static bool CImageProc_MtfCorrPlaneEx(struct CImageProc *this, uint8_t *outData, uint8_t *inData)
|
|
|
|
{
|
|
uint32_t planeSize;
|
|
uint8_t *workBuf;
|
|
int16_t *mtfCorrPlaneTable;
|
|
uint16_t row;
|
|
|
|
CImageProc_MtfPreCalcTableGen(this);
|
|
planeSize = this->conf.width * this->conf.height;
|
|
|
|
workBuf = malloc(planeSize);
|
|
if (!workBuf)
|
|
return 0;
|
|
|
|
mtfCorrPlaneTable = &this->mtfCorrPlaneTable[256]; /* Mid-point of array */
|
|
memcpy(workBuf, inData, planeSize);
|
|
|
|
for (row = 1 ; row < (this->conf.height - 1) ; row++) {
|
|
uint16_t col;
|
|
for (col = 1 ; col < (this->conf.width - 1) ; col++) {
|
|
uint32_t rowOffset = col + row * this->conf.width;
|
|
uint8_t *inPixel = inData + rowOffset;
|
|
|
|
int outVal;
|
|
uint8_t outPixel;
|
|
|
|
// (curPixel + ((diff_prevRowPixel + diff_prevColPixel) * prevWeight) + ((diff_nextRowPixel + diff_nextColPixel) * nextWeight) / 128
|
|
|
|
outVal = *inPixel +
|
|
(((mtfCorrPlaneTable[*inPixel - inPixel[-this->conf.width]]
|
|
+ mtfCorrPlaneTable[*inPixel - inPixel[this->conf.width]]) * (this->planeIPPdata).prevWeight
|
|
+ (mtfCorrPlaneTable[(*inPixel - inPixel[-1])]
|
|
+ mtfCorrPlaneTable[(*inPixel - inPixel[1])]) * this->planeIPPdata.nextWeight) >> 7);
|
|
|
|
outPixel = outVal;
|
|
if (outVal < 0x100) {
|
|
if (outVal < 1) {
|
|
outPixel = 1;
|
|
}
|
|
} else {
|
|
outPixel = 0xff;
|
|
}
|
|
workBuf[rowOffset] = outPixel;
|
|
}
|
|
}
|
|
|
|
|
|
memcpy(outData, workBuf, planeSize);
|
|
free(workBuf);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static bool CImageProc_MtfCorrPlane(struct CImageProc *this)
|
|
{
|
|
uint32_t offset;
|
|
|
|
if (!this->correctMtf)
|
|
return 1;
|
|
|
|
offset = this->pixels * this->currentPlane;
|
|
|
|
return CImageProc_MtfCorrPlaneEx(this, ((uint8_t *)this->imageScratchDataPtr) + offset,
|
|
((uint8_t *)this->imageScratchDataPtr) + offset);
|
|
}
|
|
|
|
static int32_t CImageProc_TransPlaneToPulseEx(struct CImageProc *this, uint16_t *outPtr, uint8_t *inPtr)
|
|
|
|
{
|
|
int32_t offset;
|
|
|
|
for (offset = 0 ; offset < this->conf.width * this->conf.height ; offset++) {
|
|
outPtr[offset] = this->planeIPPdata.pulseExMap[inPtr[offset]];
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
static void CImageProc_TransPlaneToPulse(struct CImageProc *this)
|
|
|
|
{
|
|
uint32_t offset = this->pixels * this->currentPlane;
|
|
|
|
CImageProc_TransPlaneToPulseEx(this,this->imageDataPtr + offset,
|
|
((uint8_t *)this->imageScratchDataPtr) + offset);
|
|
return;
|
|
|
|
}
|
|
|
|
static uint16_t CImageProc_GetMaxPulse(struct CImageProc *this)
|
|
|
|
{
|
|
return (this->planeIPPdata.field_0x0 * (this->planeIPPdata.field_0x2 + 1)) + this->planeIPPdata.field_0x2;
|
|
}
|
|
|
|
static bool CImageProc_HeatCorrection(struct CImageProc *this)
|
|
|
|
{
|
|
struct CHeatCorrProc heatProc;
|
|
uint32_t offset;
|
|
uint16_t maxPulse;
|
|
bool rval;
|
|
|
|
/* Don't correct heat transfer if so requested */
|
|
if (!this->correctHeat)
|
|
return 1;
|
|
|
|
CHeatCorrProc_Init(&heatProc);
|
|
|
|
offset = this->pixels * this->currentPlane;
|
|
maxPulse = CImageProc_GetMaxPulse(this);
|
|
|
|
rval = CHeatCorrProc_SetIppData(&heatProc, &this->planeIPPdata,
|
|
this->conf.width, this->conf.height,
|
|
this->conf.headWidth, maxPulse);
|
|
if (!rval)
|
|
return 0;
|
|
|
|
|
|
CHeatCorrProc_Correction(&heatProc,
|
|
this->imageDataPtr + offset,
|
|
this->imageDataPtr + offset,
|
|
((uint8_t *)this->imageScratchDataPtr) + offset);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CImageProc_LineCorrEx(struct CImageProc *this, uint16_t *outDataPtr, uint16_t *inData, uint8_t *scratchData)
|
|
|
|
{
|
|
uint32_t pixels;
|
|
uint16_t *workBuf;
|
|
uint16_t minRowSum;
|
|
uint16_t maxPulse;
|
|
int32_t pageSum;
|
|
uint32_t lineCorrectionFactor;
|
|
uint16_t *workPtr;
|
|
uint8_t *scratchPtr;
|
|
uint16_t *inPtr;
|
|
int32_t maxLineSum;
|
|
int32_t rowSum;
|
|
|
|
uint16_t row;
|
|
|
|
pixels = this->conf.width * this->conf.height;
|
|
|
|
workBuf = malloc(pixels * 2);
|
|
if (!workBuf)
|
|
return 0;
|
|
|
|
pageSum = 0;
|
|
lineCorrectionFactor = 0;
|
|
maxLineSum = this->conf.width * this->planeIPPdata.maxLineSum;
|
|
minRowSum = this->planeIPPdata.minRowSum;
|
|
maxPulse = CImageProc_GetMaxPulse(this);
|
|
workPtr = workBuf;
|
|
scratchPtr = scratchData;
|
|
inPtr = inData;
|
|
|
|
for (row = 0 ; row < this->conf.height ; row ++) {
|
|
uint16_t col;
|
|
uint16_t local_54;
|
|
int32_t iVar3;
|
|
|
|
rowSum = 0;
|
|
for (col = 0 ; col < this->conf.width ; col++) {
|
|
rowSum = *inPtr + rowSum;
|
|
iVar3 = *inPtr - (((this->planeIPPdata).lineCorrection[*scratchPtr] * lineCorrectionFactor) >> 10);
|
|
if (iVar3 < 0) {
|
|
local_54 = 0;
|
|
} else {
|
|
local_54 = iVar3;
|
|
if (maxPulse < iVar3) {
|
|
local_54 = maxPulse;
|
|
}
|
|
}
|
|
*workPtr = local_54;
|
|
workPtr++;
|
|
inPtr++;
|
|
scratchPtr++;
|
|
}
|
|
|
|
if ((this->conf.width * minRowSum) < rowSum) {
|
|
pageSum = rowSum + pageSum;
|
|
if (maxLineSum < pageSum) {
|
|
pageSum -= maxLineSum;
|
|
lineCorrectionFactor++;
|
|
if (this->planeIPPdata.maxLineCorrectionFactor < lineCorrectionFactor) {
|
|
lineCorrectionFactor = this->planeIPPdata.maxLineCorrectionFactor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
memcpy(outDataPtr, workBuf, pixels * 2);
|
|
free(workBuf);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool CImageProc_LineCorrection(struct CImageProc *this)
|
|
{
|
|
uint32_t offset;
|
|
|
|
if (!this->correctLine)
|
|
return 1;
|
|
|
|
offset = this->pixels * this->currentPlane;
|
|
|
|
return CImageProc_LineCorrEx(this, this->imageDataPtr + offset, this->imageDataPtr + offset,
|
|
(uint8_t*)this->imageScratchDataPtr + offset);
|
|
}
|
|
|
|
static bool CImageProc_SideEdgeCorrEx(struct CImageProc *this, uint16_t *outDataPtr, uint16_t *inDataPtr, uint8_t *scratchDataPtr)
|
|
|
|
{
|
|
uint32_t pixels = this->conf.width * this->conf.height;
|
|
uint16_t *workBuf, *workPtr;
|
|
uint16_t maxPulse;
|
|
uint8_t *scratchPtr;
|
|
uint16_t *inPtr;
|
|
|
|
int col;
|
|
int row;
|
|
|
|
workBuf = malloc(pixels * 2);
|
|
if (!workBuf)
|
|
return 0;
|
|
|
|
maxPulse = CImageProc_GetMaxPulse(this);
|
|
|
|
workPtr = workBuf;
|
|
scratchPtr = scratchDataPtr;
|
|
inPtr = inDataPtr;
|
|
|
|
for (row = 0 ; row < this->conf.height ; row++) {
|
|
for (col = 0 ; col < this->conf.width ; col++) {
|
|
uint32_t corrVal;
|
|
uint16_t inPixel;
|
|
int32_t iVar3;
|
|
|
|
if (col < 0x40) {
|
|
corrVal = this->planeIPPdata.sideEdgeCorrectionComp[col];
|
|
} else {
|
|
if ((this->conf.width - 0x40) < col) {
|
|
corrVal = this->planeIPPdata.sideEdgeCorrectionComp[(this->conf.width - col) -1];
|
|
} else {
|
|
corrVal = 0;
|
|
}
|
|
}
|
|
inPixel = *inPtr;
|
|
if (corrVal != 0) {
|
|
iVar3 = *inPtr - (((this->planeIPPdata).sideEdgeCorrectionTable[*scratchPtr] * corrVal) >> 7);
|
|
if (iVar3 < 0) {
|
|
inPixel = 0;
|
|
} else {
|
|
inPixel = iVar3;
|
|
if (maxPulse < iVar3) {
|
|
inPixel = maxPulse;
|
|
}
|
|
}
|
|
}
|
|
*workPtr = inPixel;
|
|
workPtr++;
|
|
inPtr++;
|
|
scratchPtr++;
|
|
}
|
|
}
|
|
|
|
memcpy(outDataPtr, workBuf, pixels * 2);
|
|
free(workBuf);
|
|
return 1;
|
|
}
|
|
|
|
static bool CImageProc_SideEdgeCorrection(struct CImageProc *this)
|
|
|
|
{
|
|
uint32_t offset;
|
|
|
|
if (!this->correctSideEdge)
|
|
return 1;
|
|
|
|
offset = this->pixels * this->currentPlane;
|
|
|
|
return CImageProc_SideEdgeCorrEx(this, this->imageDataPtr + offset, this->imageDataPtr + offset,
|
|
((uint8_t*)this->imageScratchDataPtr + offset));
|
|
}
|
|
|
|
static bool CImageProc_PulseGenEx(struct CImageProc *this)
|
|
|
|
{
|
|
bool rval;
|
|
|
|
rval = CImageProc_MtfCorrPlane(this);
|
|
if (rval) {
|
|
CImageProc_TransPlaneToPulse(this);
|
|
rval = CImageProc_HeatCorrection(this);
|
|
}
|
|
if (rval)
|
|
rval = CImageProc_LineCorrection(this);
|
|
if (rval)
|
|
rval = CImageProc_SideEdgeCorrection(this);
|
|
|
|
return rval;
|
|
}
|
|
|
|
|
|
static bool CImageProc_PulseGen(struct CImageProc *this, uint16_t *outImgPtr, uint8_t *srcRGB)
|
|
{
|
|
bool rval;
|
|
uint32_t i;
|
|
|
|
rval = CImageProc_Initialize(this);
|
|
if (rval)
|
|
rval = CImageProc_AddBorder(this, (uint8_t*)this->imageScratchDataPtr, srcRGB);
|
|
if (rval)
|
|
rval = CImageProc_TransDotToPlane(this, (uint8_t*)this->imageScratchDataPtr,
|
|
(uint8_t*)this->imageScratchDataPtr);
|
|
if (!rval)
|
|
goto done;
|
|
|
|
for (i = 0 ; i < this->planesOCM ; i++) {
|
|
rval = CImageProc_SetProcConfig(this, i);
|
|
if (!rval)
|
|
goto done;
|
|
|
|
/* Generate the lamination plane as needed */
|
|
if ((this->planesOCG <= i) &&
|
|
!(rval = CImageProc_MiddleDataGen(this, i)))
|
|
goto done;
|
|
if (!(rval = CImageProc_PulseGenEx(this)))
|
|
goto done;
|
|
}
|
|
|
|
#if (__BYTE_ORDER != __LITTLE_ENDIAN)
|
|
for (i = 0 ; i < this->imageDataLen / 2 ; i++) {
|
|
outImgPtr[i] = cpu_to_le16(this->imageDataPtr[i]);
|
|
}
|
|
#else
|
|
memcpy(outImgPtr, this->imageDataPtr, this->imageDataLen);
|
|
#endif
|
|
|
|
done:
|
|
if (this->imageScratchDataPtr) {
|
|
free(this->imageScratchDataPtr);
|
|
this->imageScratchDataPtr = NULL;
|
|
}
|
|
if (this->imageDataPtr) {
|
|
free(this->imageDataPtr);
|
|
this->imageDataPtr = NULL;
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Exported Functions
|
|
|
|
void dump_announce(FILE *fp)
|
|
{
|
|
fprintf(fp, "INFO: libS2245ImageReProcess version '%s'\n", LIB_VERSION);
|
|
fprintf(fp, "INFO: Copyright (c) 2020 Solomon Peachy\n");
|
|
fprintf(fp, "INFO: This free software comes with ABSOLUTELY NO WARRANTY!\n");
|
|
fprintf(fp, "INFO: Licensed under the GNU GPLv3.\n");
|
|
fprintf(fp, "INFO: *** This code is NOT supported or endorsed by Sinfonia! ***\n");
|
|
}
|
|
|
|
bool ip_imageProc(uint16_t *destData, uint8_t *srcInRgb,
|
|
uint16_t width, uint16_t height, void *srcIpp)
|
|
{
|
|
bool rval = 0;
|
|
struct CIppMng ippMng;
|
|
struct CImageProc imageProc;
|
|
|
|
CIppMng_Init(&ippMng);
|
|
CImageProc_Init(&imageProc, &ippMng);
|
|
|
|
if (!width || !height || !srcIpp || !srcInRgb || !destData)
|
|
goto done;
|
|
|
|
rval = CIppMng_SetIPP(&ippMng, srcIpp, width, height);
|
|
if (rval)
|
|
rval = CImageProc_PulseGen(&imageProc, destData, srcInRgb);
|
|
|
|
done:
|
|
CIppMng_Cleanup(&ippMng);
|
|
|
|
return rval;
|
|
}
|
|
|
|
bool ip_checkIpp(uint16_t width, uint16_t height, void *srcIpp)
|
|
{
|
|
bool rval = 0;
|
|
struct CIppMng ippMng;
|
|
|
|
if (!width || !height || !srcIpp)
|
|
goto done;
|
|
|
|
CIppMng_Init(&ippMng);
|
|
#ifdef USE_EXTRA_STUFF
|
|
rval = CIppMng_SetConf(&ippMng, srcIpp, width, height);
|
|
if (!rval)
|
|
goto done;
|
|
#endif
|
|
rval = CIppMng_CheckIpp(&ippMng, srcIpp);
|
|
|
|
CIppMng_Cleanup(&ippMng);
|
|
|
|
done:
|
|
return rval;
|
|
}
|
|
|
|
bool ip_getMemorySize(uint32_t *szMemory,
|
|
uint16_t width, uint16_t height,
|
|
void *srcIpp)
|
|
{
|
|
struct ippData *ippData;
|
|
uint32_t pixels;
|
|
|
|
if (!width || !height || !szMemory || !srcIpp)
|
|
return 0;
|
|
|
|
ippData = srcIpp;
|
|
|
|
if ((ippData->conf.borderCapable == 0x02) &&
|
|
(width == 1548) && (height == 2140)) {
|
|
pixels = 2434*1844; /* ie 8x6 */
|
|
} else {
|
|
pixels = height * width;
|
|
}
|
|
|
|
*szMemory = pixels * 2 * ippData->conf.planes;
|
|
|
|
if (!*szMemory)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|