fd19c4eedf
* Small changes, for some reason VS 2015 can't link cprintf and they added a second function std::map::count and bind couldn't resolve the function. Substituted with a lambda-expression. * Created all 64bit version of the 3rd party libs. * Cleanup popup opens CleanupSettings instead of CleanupSettingsPane. Not finished, panel is wrong now (also uses CleanupSettings). * Tried to get Twain working, failed. * When there are more then 3 peg holes create additional holes. * When a hole touches the boundary it should still be considered a hole. * Do not compare dot size against fixed size. Will not work in some scan resolutions. Used the same value (PERCENT * max dot size) as later in the code in compare_dots. * When there are more than three peg holes the code looked for the best fit and used that. The problem was, that the middle hole was used as center for auto center. For three peg holes that is correct, but does not work for more than three. Now the best fit is calculated and from there the offset of the middle of the three best fit holes is calculated and applied. * One of the last changes broke VS2015 compatibility, it chocked on a missing include. * fix for msvs2013 * revert autopos.cpp * apply clang-format * use GIT-LFS
2670 lines
73 KiB
C++
2670 lines
73 KiB
C++
#include <memory>
|
|
|
|
#include "tmachine.h"
|
|
#include "pli_io.h"
|
|
#include "tcommon.h"
|
|
#include "timage_io.h"
|
|
#include "tvectorimage.h"
|
|
//#include "tstrokeoutline.h"
|
|
#include "tsimplecolorstyles.h"
|
|
#include "tcontenthistory.h"
|
|
#include "tfilepath_io.h"
|
|
//#include <fstream.h>
|
|
#include "../compatibility/tfile_io.h"
|
|
#include "tenv.h"
|
|
|
|
/*=====================================================================*/
|
|
|
|
#if defined(MACOSX)
|
|
#include <architecture/i386/io.h>
|
|
#elif defined(_WIN32)
|
|
#include <io.h>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
typedef TVectorImage::IntersectionBranch IntersectionBranch;
|
|
|
|
#if !defined(TNZ_LITTLE_ENDIAN)
|
|
TNZ_LITTLE_ENDIAN undefined !!
|
|
#endif
|
|
|
|
static const int c_majorVersionNumber = 71;
|
|
static const int c_minorVersionNumber = 0;
|
|
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
|
|
inline void ulongFromDouble1(double x, TUINT32 &hi, TUINT32 &lo) {
|
|
assert(x < 1.0);
|
|
// x+=1.0;
|
|
TUINT32 *l = (TUINT32 *)&x;
|
|
#if TNZ_LITTLE_ENDIAN
|
|
hi = l[1], lo = l[0];
|
|
#else
|
|
hi = l[0], lo = l[1];
|
|
#endif
|
|
|
|
// return (hi&0XFFFFF)<<12 | ((lo&0xFFE00000)>>20);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline double doubleFromUlong1(TUINT32 hi, TUINT32 lo) {
|
|
// assert((lo&0X00000001)==0);
|
|
TUINT32 l[2];
|
|
#if TNZ_LITTLE_ENDIAN
|
|
l[1] = hi;
|
|
l[0] = lo;
|
|
#else
|
|
l[0] = hi;
|
|
l[1] = lo;
|
|
#endif
|
|
|
|
return *(double *)l; // - 1;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TThickPoint operator*(const TAffine &aff, const TThickPoint &p) {
|
|
TPointD p1(p.x, p.y);
|
|
return TThickPoint(aff * p1, p.thick);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
class MyOfstream final : public Tofstream {
|
|
public:
|
|
MyOfstream(const TFilePath &path) : Tofstream(path) {}
|
|
|
|
MyOfstream &operator<<(TUINT32 n) {
|
|
TUINT32 app;
|
|
|
|
#if TNZ_LITTLE_ENDIAN
|
|
app = n;
|
|
#else
|
|
UCHAR *uc = (UCHAR *)&n;
|
|
app = *(uc) | (*(uc + 1)) << 8 | (*(uc + 2)) << 16 | (*(uc + 3)) << 24;
|
|
#endif
|
|
write((char *)&app, sizeof(TUINT32));
|
|
return *this;
|
|
}
|
|
|
|
MyOfstream &operator<<(USHORT n) {
|
|
USHORT app;
|
|
|
|
#if TNZ_LITTLE_ENDIAN
|
|
app = n;
|
|
#else
|
|
UCHAR *uc = (UCHAR *)&n;
|
|
app = *(uc) | (*(uc + 1)) << 8;
|
|
#endif
|
|
|
|
write((char *)&app, sizeof(USHORT));
|
|
return *this;
|
|
}
|
|
|
|
MyOfstream &operator<<(UCHAR un) {
|
|
write((char *)&un, sizeof(UCHAR));
|
|
return *this;
|
|
}
|
|
MyOfstream &operator<<(char un) {
|
|
write((char *)&un, sizeof(char));
|
|
return *this;
|
|
}
|
|
MyOfstream &operator<<(const TRaster32P &r);
|
|
MyOfstream &operator<<(const std::string &r);
|
|
MyOfstream &writeBuf(void *un, UINT s) {
|
|
write((char *)un, s);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
/*=====================================================================*/
|
|
|
|
MyOfstream &MyOfstream::operator<<(const TRaster32P &r) {
|
|
assert(r->getLx() == r->getWrap());
|
|
|
|
(*this) << (USHORT)r->getLx();
|
|
(*this) << (USHORT)r->getLy();
|
|
r->lock();
|
|
MyOfstream &ret =
|
|
writeBuf(r->getRawData(), r->getLx() * r->getLy() * r->getPixelSize());
|
|
r->unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
MyOfstream &MyOfstream::operator<<(const std::string &s) {
|
|
(*this) << (USHORT)s.size();
|
|
for (UINT i = 0; i < s.size(); i++) (*this) << (UCHAR)(s[i]);
|
|
return *this;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
class MyIfstream // The input is done without stl; it was crashing in release
|
|
// version loading textures!!
|
|
{
|
|
private:
|
|
bool m_isIrixEndian;
|
|
FILE *m_fp;
|
|
|
|
public:
|
|
MyIfstream() : m_isIrixEndian(false) { m_fp = 0; }
|
|
~MyIfstream() {
|
|
if (m_fp) fclose(m_fp);
|
|
}
|
|
void setEndianess(bool isIrixEndian) { m_isIrixEndian = isIrixEndian; }
|
|
MyIfstream &operator>>(TUINT32 &un);
|
|
MyIfstream &operator>>(string &un);
|
|
MyIfstream &operator>>(USHORT &un);
|
|
MyIfstream &operator>>(UCHAR &un);
|
|
MyIfstream &operator>>(char &un);
|
|
void open(const TFilePath &filename);
|
|
void close() {
|
|
if (m_fp) fclose(m_fp);
|
|
m_fp = 0;
|
|
}
|
|
TUINT32 tellg() { return (TUINT32)ftell(m_fp); }
|
|
// void seekg(TUINT32 pos, ios_base::seek_dir type);
|
|
void seekg(TUINT32 pos, int type);
|
|
void read(char *m_buf, int length) {
|
|
fread((void *)m_buf, sizeof(char), length, m_fp);
|
|
}
|
|
};
|
|
|
|
/*=====================================================================*/
|
|
|
|
void MyIfstream::open(const TFilePath &filename) {
|
|
try {
|
|
m_fp = fopen(filename, "rb");
|
|
} catch (TException &) {
|
|
throw TImageException(filename, "File not found");
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void MyIfstream::seekg(TUINT32 pos, int type) {
|
|
if (type == ios_base::beg)
|
|
fseek(m_fp, pos, SEEK_SET);
|
|
else if (type == ios_base::cur)
|
|
fseek(m_fp, pos, SEEK_CUR);
|
|
else
|
|
assert(false);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline MyIfstream &MyIfstream::operator>>(UCHAR &un) {
|
|
int ret = fread((void *)&un, sizeof(UCHAR), 1, m_fp);
|
|
if (ret < 1) throw TException("corrupted pli file: unexpected end of file");
|
|
// read((char *)&un, sizeof(UCHAR));
|
|
return *this;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline MyIfstream &MyIfstream::operator>>(char &un) {
|
|
int ret = fread((void *)&un, sizeof(char), 1, m_fp);
|
|
if (ret < 1) throw TException("corrupted pli file: unexpected end of file");
|
|
// read((char *)&un, sizeof(char));
|
|
return *this;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline MyIfstream &MyIfstream::operator>>(USHORT &un) {
|
|
int ret = fread((void *)&un, sizeof(USHORT), 1, m_fp);
|
|
if (ret < 1) throw TException("corrupted pli file: unexpected end of file");
|
|
// read((char *)&un, sizeof(USHORT));
|
|
|
|
if (m_isIrixEndian) un = ((un & 0xff00) >> 8) | ((un & 0x00ff) << 8);
|
|
return *this;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline MyIfstream &MyIfstream::operator>>(TUINT32 &un) {
|
|
int ret = fread((void *)&un, sizeof(TUINT32), 1, m_fp);
|
|
if (ret < 1) throw TException("corrupted pli file: unexpected end of file");
|
|
// read((char *)&un, sizeof(TUINT32));
|
|
|
|
if (m_isIrixEndian)
|
|
un = ((un & 0xff000000) >> 24) | ((un & 0x00ff0000) >> 8) |
|
|
((un & 0x0000ff00) << 8) | ((un & 0x000000ff) << 24);
|
|
return *this;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline MyIfstream &MyIfstream::operator>>(string &un) {
|
|
string s = "";
|
|
USHORT lenght;
|
|
(*this) >> lenght;
|
|
for (UINT i = 0; i < lenght; i++) {
|
|
UCHAR ch;
|
|
(*this) >> ch;
|
|
s.append(1, ch);
|
|
}
|
|
un = s;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
UINT TStyleParam::getSize() {
|
|
switch (m_type) {
|
|
case SP_BYTE:
|
|
return 1;
|
|
case SP_INT:
|
|
return 4;
|
|
case SP_DOUBLE:
|
|
return 4;
|
|
case SP_USHORT:
|
|
return 2;
|
|
case SP_RASTER:
|
|
return 2 + 2 + m_r->getLx() * m_r->getLy() * m_r->getPixelSize();
|
|
case SP_STRING:
|
|
return (m_string.size() + sizeof(USHORT));
|
|
default:
|
|
assert(false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
#define CHECK_FOR_READ_ERROR(filePath)
|
|
|
|
#define CHECK_FOR_WRITE_ERROR(filePath) \
|
|
{ \
|
|
if (m_oChan->fail() /*m_oChan.flags()&(ios::failbit)*/) { \
|
|
m_lastError = WRITE_ERROR; \
|
|
throw TImageException(filePath, "Error on writing file"); \
|
|
} \
|
|
}
|
|
|
|
const TUINT32 c_magicNt = 0x4D494C50;
|
|
const TUINT32 c_magicIrix = 0x504C494D;
|
|
|
|
class TagElem {
|
|
public:
|
|
PliTag *m_tag;
|
|
TUINT32 m_offset;
|
|
TagElem *m_next;
|
|
|
|
TagElem(PliTag *tag, TUINT32 offset, TagElem *next = NULL)
|
|
: m_tag(tag), m_offset(offset), m_next(next) {}
|
|
|
|
TagElem(const TagElem &elem)
|
|
: m_tag(elem.m_tag), m_offset(elem.m_offset), m_next(NULL) {}
|
|
|
|
~TagElem() {
|
|
if (m_tag) delete m_tag;
|
|
}
|
|
};
|
|
|
|
/*=====================================================================*/
|
|
class TContentHistory;
|
|
|
|
class ParsedPliImp {
|
|
public:
|
|
UCHAR m_majorVersionNumber;
|
|
UCHAR m_minorVersionNumber;
|
|
USHORT m_framesNumber;
|
|
double m_thickRatio;
|
|
double m_maxThickness;
|
|
double m_autocloseTolerance;
|
|
bool m_isIrixEndian;
|
|
TFilePath m_filePath;
|
|
UCHAR m_currDinamicTypeBytesNum;
|
|
TUINT32 m_tagLength;
|
|
TUINT32 m_bufLength;
|
|
std::unique_ptr<UCHAR[]> m_buf;
|
|
TAffine m_affine;
|
|
int m_precisionScale;
|
|
std::map<TFrameId, int> m_frameOffsInFile;
|
|
|
|
PliTag *readTextTag();
|
|
PliTag *readPaletteTag();
|
|
PliTag *readPaletteWithAlphaTag();
|
|
PliTag *readThickQuadraticChainTag(bool isLoop);
|
|
PliTag *readColorTag();
|
|
PliTag *readStyleTag();
|
|
PliTag *readGroupTag();
|
|
PliTag *readImageTag();
|
|
PliTag *readGeometricTransformationTag();
|
|
PliTag *readDoublePairTag();
|
|
PliTag *readBitmapTag();
|
|
PliTag *readIntersectionDataTag();
|
|
PliTag *readOutlineOptionsTag();
|
|
PliTag *readPrecisionScaleTag();
|
|
|
|
inline void readDinamicData(TUINT32 &val, TUINT32 &bufOffs);
|
|
inline bool readDinamicData(TINT32 &val, TUINT32 &bufOffs);
|
|
inline void readFloatData(double &val, TUINT32 &bufOffs);
|
|
|
|
inline UINT readRasterData(TRaster32P &r, TUINT32 &bufOffs);
|
|
inline void writeFloatData(double val);
|
|
inline void readUShortData(USHORT &val, TUINT32 &bufOffs);
|
|
inline void readTUINT32Data(TUINT32 &val, TUINT32 &bufOffs);
|
|
|
|
TUINT32 writeTagHeader(UCHAR type, UINT tagLength);
|
|
TUINT32 writeTextTag(TextTag *tag);
|
|
TUINT32 writePaletteTag(PaletteTag *tag);
|
|
TUINT32 writePaletteWithAlphaTag(PaletteWithAlphaTag *tag);
|
|
TUINT32 writeThickQuadraticChainTag(ThickQuadraticChainTag *tag);
|
|
TUINT32 writeGroupTag(GroupTag *tag);
|
|
TUINT32 writeImageTag(ImageTag *tag);
|
|
TUINT32 writeColorTag(ColorTag *tag);
|
|
TUINT32 writeStyleTag(StyleTag *tag);
|
|
TUINT32 writeGeometricTransformationTag(GeometricTransformationTag *tag);
|
|
TUINT32 writeDoublePairTag(DoublePairTag *tag);
|
|
TUINT32 writeBitmapTag(BitmapTag *tag);
|
|
TUINT32 writeIntersectionDataTag(IntersectionDataTag *tag);
|
|
TUINT32 writeOutlineOptionsTag(StrokeOutlineOptionsTag *tag);
|
|
TUINT32 writePrecisionScaleTag(PrecisionScaleTag *tag);
|
|
|
|
inline void writeDinamicData(TUINT32 val);
|
|
inline void writeDinamicData(TINT32 val, bool isNegative);
|
|
|
|
inline void setDinamicTypeBytesNum(int minval, int maxval);
|
|
|
|
PliTag *findTagFromOffset(UINT tagOffs);
|
|
UINT findOffsetFromTag(PliTag *tag);
|
|
TagElem *findTag(PliTag *tag);
|
|
USHORT readTagHeader();
|
|
|
|
public:
|
|
enum errorType {
|
|
NO__ERROR = 0,
|
|
NO_FILE,
|
|
BAD_MAGIC,
|
|
PREMATURE_EOF,
|
|
WRITE_ERROR,
|
|
ERRORTYPE_HOW_MANY
|
|
};
|
|
|
|
errorType m_lastError;
|
|
string m_creator;
|
|
|
|
TagElem *m_firstTag;
|
|
TagElem *m_lastTag;
|
|
TagElem *m_currTag;
|
|
|
|
MyIfstream m_iChan;
|
|
MyOfstream *m_oChan;
|
|
|
|
ParsedPliImp();
|
|
ParsedPliImp(UCHAR majorVersionNumber, UCHAR minorVersionNumber,
|
|
USHORT framesNumber, UCHAR precision, UCHAR maxThickness,
|
|
double autocloseTolerance);
|
|
ParsedPliImp(const TFilePath &filename, bool readInfo);
|
|
~ParsedPliImp();
|
|
|
|
void setFrameCount(int frameCount);
|
|
int getFrameCount();
|
|
|
|
void loadInfo(bool readPalette, TPalette *&palette,
|
|
TContentHistory *&history);
|
|
ImageTag *loadFrame(const TFrameId &frameNumber);
|
|
|
|
TagElem *readTag();
|
|
void writeTag(TagElem *tag);
|
|
|
|
bool addTag(PliTag *tag, bool addFront = false);
|
|
bool addTag(const TagElem &tag, bool addFront = false);
|
|
bool writePli(const TFilePath &filename);
|
|
inline void WRITE_UCHAR_FROM_DOUBLE(double dval);
|
|
inline void WRITE_SHORT_FROM_DOUBLE(double dval);
|
|
};
|
|
|
|
/*=====================================================================*/
|
|
double ParsedPli::getMaxThickness() const { return imp->m_maxThickness; };
|
|
void ParsedPli::setMaxThickness(double maxThickness) {
|
|
imp->m_maxThickness = maxThickness;
|
|
};
|
|
|
|
/* indirect inclusion of <math.h> causes 'abs' to return double on Linux */
|
|
#ifdef LINUX
|
|
template <typename T>
|
|
T abs_workaround(T a) {
|
|
return (a > 0) ? a : -a;
|
|
}
|
|
#define abs abs_workaround
|
|
#endif
|
|
|
|
/*=====================================================================*/
|
|
|
|
static inline UCHAR complement1(char val, bool isNegative = false) {
|
|
if (val == 0) return isNegative ? 0x80 : 0;
|
|
|
|
return (UCHAR)(abs(val) | (val & 0x80));
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
static inline USHORT complement1(short val, bool isNegative = false) {
|
|
if (val == 0) return isNegative ? 0x8000 : 0;
|
|
|
|
return (USHORT)(abs(val) | (val & 0x8000));
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
static inline TUINT32 complement1(TINT32 val, bool isNegative = false) {
|
|
if (val == 0) return isNegative ? 0x80000000 : 0;
|
|
|
|
return (TUINT32)(abs(val) | (val & 0x80000000));
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
static inline short complement2(USHORT val) {
|
|
return (val & 0x8000) ? -(val & 0x7fff) : (val & 0x7fff);
|
|
}
|
|
|
|
#ifdef LINUX
|
|
#undef abs
|
|
#endif
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPliImp::ParsedPliImp()
|
|
: m_majorVersionNumber(0)
|
|
, m_minorVersionNumber(0)
|
|
, m_framesNumber(0)
|
|
, m_thickRatio(1.0)
|
|
, m_maxThickness(0.0)
|
|
, m_firstTag(NULL)
|
|
, m_lastTag(NULL)
|
|
, m_currTag(NULL)
|
|
, m_iChan()
|
|
, m_oChan(0)
|
|
, m_bufLength(0)
|
|
, m_affine()
|
|
, m_precisionScale(REGION_COMPUTING_PRECISION)
|
|
, m_creator("") {}
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPliImp::ParsedPliImp(UCHAR majorVersionNumber, UCHAR minorVersionNumber,
|
|
USHORT framesNumber, UCHAR precision,
|
|
UCHAR maxThickness, double autocloseTolerance)
|
|
: m_majorVersionNumber(majorVersionNumber)
|
|
, m_minorVersionNumber(minorVersionNumber)
|
|
, m_framesNumber(framesNumber)
|
|
, m_maxThickness(maxThickness)
|
|
, m_autocloseTolerance(autocloseTolerance)
|
|
, m_thickRatio(maxThickness / 255.0)
|
|
, m_firstTag(NULL)
|
|
, m_lastTag(NULL)
|
|
, m_currTag(NULL)
|
|
, m_iChan()
|
|
, m_oChan(0)
|
|
, m_bufLength(0)
|
|
, m_affine(TScale(1.0 / pow(10.0, precision)))
|
|
, m_precisionScale(REGION_COMPUTING_PRECISION)
|
|
, m_creator("") {}
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPliImp::ParsedPliImp(const TFilePath &filename, bool readInfo)
|
|
: m_majorVersionNumber(0)
|
|
, m_minorVersionNumber(0)
|
|
, m_framesNumber(0)
|
|
, m_thickRatio(1.0)
|
|
, m_maxThickness(0)
|
|
, m_firstTag(NULL)
|
|
, m_lastTag(NULL)
|
|
, m_currTag(NULL)
|
|
, m_iChan()
|
|
, m_oChan(0)
|
|
, m_bufLength(0)
|
|
, m_precisionScale(REGION_COMPUTING_PRECISION)
|
|
, m_creator("") {
|
|
TUINT32 magic;
|
|
// TUINT32 fileLenght;
|
|
TagElem *tagElem;
|
|
UCHAR maxThickness;
|
|
|
|
// cerr<<m_filePath<<endl;
|
|
|
|
//#ifdef _WIN32
|
|
m_iChan.open(filename);
|
|
|
|
// m_iChan.exceptions( ios::failbit | ios::badbit);
|
|
//#else
|
|
// m_iChan.open(filename.c_str(), ios::in);
|
|
//#endif
|
|
|
|
m_iChan >> magic;
|
|
|
|
CHECK_FOR_READ_ERROR(filename);
|
|
|
|
if (magic == c_magicNt) {
|
|
#if TNZ_LITTLE_ENDIAN
|
|
m_isIrixEndian = false;
|
|
#else
|
|
m_isIrixEndian = true;
|
|
#endif
|
|
m_iChan.setEndianess(false);
|
|
} else if (magic == c_magicIrix) {
|
|
#if TNZ_LITTLE_ENDIAN
|
|
m_isIrixEndian = true;
|
|
#else
|
|
m_isIrixEndian = false;
|
|
#endif
|
|
m_iChan.setEndianess(true);
|
|
} else {
|
|
m_lastError = BAD_MAGIC;
|
|
throw TImageException(filename, "Error on reading magic number");
|
|
}
|
|
|
|
m_iChan >> m_majorVersionNumber;
|
|
m_iChan >> m_minorVersionNumber;
|
|
|
|
// Loading pli versions AFTER current one is NOT SUPPORTED. This means that an
|
|
// exception is directly called at this point.
|
|
if (m_majorVersionNumber > c_majorVersionNumber ||
|
|
(m_majorVersionNumber == c_majorVersionNumber &&
|
|
m_minorVersionNumber > c_minorVersionNumber))
|
|
throw TImageVersionException(filename, m_majorVersionNumber,
|
|
m_minorVersionNumber);
|
|
|
|
if (m_majorVersionNumber > 5 ||
|
|
m_majorVersionNumber == 5 && m_minorVersionNumber >= 8)
|
|
m_iChan >> m_creator;
|
|
|
|
if (m_majorVersionNumber < 5) {
|
|
TUINT32 fileLenght;
|
|
|
|
m_iChan >> fileLenght;
|
|
m_iChan >> m_framesNumber;
|
|
m_iChan >> maxThickness;
|
|
m_thickRatio = maxThickness / 255.0;
|
|
|
|
if (readInfo) return;
|
|
|
|
CHECK_FOR_READ_ERROR(filename);
|
|
|
|
m_currDinamicTypeBytesNum = 2;
|
|
|
|
while ((tagElem = readTag())) {
|
|
if (!m_firstTag)
|
|
m_firstTag = m_lastTag = tagElem;
|
|
else {
|
|
m_lastTag->m_next = tagElem;
|
|
m_lastTag = m_lastTag->m_next;
|
|
}
|
|
}
|
|
|
|
for (tagElem = m_firstTag; tagElem; tagElem = tagElem->m_next)
|
|
tagElem->m_offset = 0;
|
|
|
|
m_iChan.close();
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
extern TPalette *readPalette(GroupTag *paletteTag, int majorVersion,
|
|
int minorVersion);
|
|
|
|
/*=====================================================================*/
|
|
|
|
const TFrameId &ParsedPli::getFrameNumber(int index) {
|
|
assert(imp->m_frameOffsInFile.size() == imp->m_framesNumber);
|
|
|
|
std::map<TFrameId, int>::iterator it = imp->m_frameOffsInFile.begin();
|
|
|
|
std::advance(it, index);
|
|
|
|
return it->first;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::loadInfo(bool readPlt, TPalette *&palette,
|
|
TContentHistory *&history) {
|
|
TUINT32 fileLenght;
|
|
|
|
m_iChan >> fileLenght;
|
|
m_iChan >> m_framesNumber;
|
|
if (!((m_majorVersionNumber == 5 && m_minorVersionNumber >= 7) ||
|
|
(m_majorVersionNumber > 5))) {
|
|
UCHAR maxThickness;
|
|
m_iChan >> maxThickness;
|
|
m_thickRatio = maxThickness / 255.0;
|
|
} else
|
|
m_thickRatio = 0;
|
|
|
|
UCHAR ii, d, s = 2;
|
|
if (m_majorVersionNumber > 6 ||
|
|
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 5))
|
|
m_iChan >> s;
|
|
m_iChan >> ii;
|
|
m_iChan >> d;
|
|
m_autocloseTolerance = ((double)(s - 1)) * (ii + 0.01 * d);
|
|
|
|
m_currDinamicTypeBytesNum = 2;
|
|
|
|
// m_frameOffsInFile = new int[m_framesNumber];
|
|
// for (int i=0; i<m_framesNumber; i++)
|
|
// m_frameOffsInFile[i] = -1;
|
|
|
|
TUINT32 pos = m_iChan.tellg();
|
|
USHORT type;
|
|
while ((type = readTagHeader()) != PliTag::END_CNTRL) {
|
|
if (type == PliTag::IMAGE_BEGIN_GOBJ) {
|
|
USHORT frame;
|
|
m_iChan >> frame;
|
|
|
|
char letter = 0;
|
|
if (m_majorVersionNumber > 6 ||
|
|
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6))
|
|
m_iChan >> letter;
|
|
|
|
m_frameOffsInFile[TFrameId(frame, letter)] = m_iChan.tellg();
|
|
|
|
// m_iChan.seekg(m_tagLength, ios::cur);
|
|
m_iChan.seekg(m_tagLength - 2, ios::cur);
|
|
} else if (type == PliTag::STYLE_NGOBJ) {
|
|
m_iChan.seekg(pos, ios::beg);
|
|
TagElem *tagElem = readTag();
|
|
addTag(*tagElem);
|
|
tagElem->m_tag = 0;
|
|
delete tagElem;
|
|
} else if (type == PliTag::TEXT) {
|
|
m_iChan.seekg(pos, ios::beg);
|
|
TagElem *tagElem = readTag();
|
|
TextTag *textTag = (TextTag *)tagElem->m_tag;
|
|
history = new TContentHistory(true);
|
|
history->deserialize(QString::fromStdString(textTag->m_text));
|
|
delete tagElem;
|
|
}
|
|
|
|
else if (type == PliTag::GROUP_GOBJ && readPlt) // la paletta!!!
|
|
{
|
|
m_iChan.seekg(pos, ios::beg);
|
|
TagElem *tagElem = readTag();
|
|
GroupTag *grouptag = (GroupTag *)tagElem->m_tag;
|
|
if (grouptag->m_type == (UCHAR)GroupTag::PALETTE) {
|
|
readPlt = false;
|
|
palette = readPalette((GroupTag *)tagElem->m_tag, m_majorVersionNumber,
|
|
m_minorVersionNumber);
|
|
} else
|
|
assert(grouptag->m_type == (UCHAR)GroupTag::STROKE);
|
|
delete tagElem;
|
|
} else {
|
|
m_iChan.seekg(m_tagLength, ios::cur);
|
|
switch (type) {
|
|
case PliTag::SET_DATA_8_CNTRL:
|
|
m_currDinamicTypeBytesNum = 1;
|
|
break;
|
|
case PliTag::SET_DATA_16_CNTRL:
|
|
m_currDinamicTypeBytesNum = 2;
|
|
break;
|
|
case PliTag::SET_DATA_32_CNTRL:
|
|
m_currDinamicTypeBytesNum = 4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
pos = m_iChan.tellg();
|
|
}
|
|
|
|
assert(m_frameOffsInFile.size() == m_framesNumber);
|
|
// palette = new TPalette();
|
|
// for (int i=0; i<256; i++)
|
|
// palette->getPage(0)->addStyle(TPixel::Black);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
USHORT ParsedPliImp::readTagHeader() {
|
|
UCHAR ucharTagType, tagLengthId;
|
|
USHORT tagType;
|
|
|
|
// unused variable
|
|
#if 0
|
|
TUINT32 tagOffset = m_iChan.tellg();
|
|
#endif
|
|
|
|
m_iChan >> ucharTagType;
|
|
|
|
if (ucharTagType == 0xFF) {
|
|
m_iChan >> tagType;
|
|
tagLengthId = tagType >> 14;
|
|
tagType &= 0x3FFF;
|
|
} else {
|
|
tagType = ucharTagType;
|
|
tagLengthId = tagType >> 6;
|
|
tagType &= 0x3F;
|
|
}
|
|
|
|
m_tagLength = 0;
|
|
|
|
switch (tagLengthId) {
|
|
case 0x0:
|
|
m_tagLength = 0;
|
|
break;
|
|
case 0x1: {
|
|
UCHAR clength;
|
|
m_iChan >> clength;
|
|
m_tagLength = clength;
|
|
break;
|
|
}
|
|
case 0x2: {
|
|
USHORT slength;
|
|
m_iChan >> slength;
|
|
m_tagLength = slength;
|
|
break;
|
|
}
|
|
case 0x3:
|
|
m_iChan >> m_tagLength;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
return tagType;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
ImageTag *ParsedPliImp::loadFrame(const TFrameId &frameNumber) {
|
|
m_currDinamicTypeBytesNum = 2;
|
|
|
|
TagElem *tagElem = m_firstTag;
|
|
while (tagElem) {
|
|
TagElem *auxTag = tagElem;
|
|
tagElem = tagElem->m_next;
|
|
delete auxTag;
|
|
}
|
|
m_firstTag = 0;
|
|
|
|
// PliTag *tag;
|
|
USHORT type = PliTag::IMAGE_BEGIN_GOBJ;
|
|
USHORT frame;
|
|
char letter;
|
|
TFrameId frameId;
|
|
|
|
// cerco il frame
|
|
std::map<TFrameId, int>::iterator it;
|
|
|
|
it = m_frameOffsInFile.find(frameNumber);
|
|
|
|
if (it != m_frameOffsInFile.end()) {
|
|
m_iChan.seekg(it->second, ios::beg);
|
|
frameId = it->first;
|
|
} else
|
|
while ((type = readTagHeader()) != PliTag::END_CNTRL) {
|
|
if (type == PliTag::IMAGE_BEGIN_GOBJ) {
|
|
m_iChan >> frame;
|
|
if (m_majorVersionNumber > 6 ||
|
|
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6))
|
|
m_iChan >> letter;
|
|
else
|
|
letter = 0;
|
|
|
|
frameId = TFrameId(frame, letter);
|
|
m_frameOffsInFile[frameId] = m_iChan.tellg();
|
|
if (frameId == frameNumber) break;
|
|
} else
|
|
m_iChan.seekg(m_tagLength, ios::cur);
|
|
}
|
|
|
|
if (type == PliTag::END_CNTRL) {
|
|
throw TImageException(TFilePath(), "Pli: frame not found");
|
|
return 0;
|
|
}
|
|
|
|
// trovato; leggo i suoi tag
|
|
while ((tagElem = readTag())) {
|
|
if (!m_firstTag)
|
|
m_firstTag = m_lastTag = tagElem;
|
|
else {
|
|
m_lastTag->m_next = tagElem;
|
|
m_lastTag = m_lastTag->m_next;
|
|
}
|
|
if (tagElem->m_tag->m_type == PliTag::IMAGE_GOBJ) {
|
|
assert(((ImageTag *)(tagElem->m_tag))->m_numFrame == frameId);
|
|
return (ImageTag *)tagElem->m_tag;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TagElem *ParsedPliImp::readTag() {
|
|
UCHAR ucharTagType, tagLengthId;
|
|
USHORT tagType;
|
|
|
|
TUINT32 tagOffset = m_iChan.tellg();
|
|
|
|
m_iChan >> ucharTagType;
|
|
|
|
if (ucharTagType == 0xFF) {
|
|
m_iChan >> tagType;
|
|
tagLengthId = tagType >> 14;
|
|
tagType &= 0x3FFF;
|
|
} else {
|
|
tagType = ucharTagType;
|
|
tagLengthId = tagType >> 6;
|
|
tagType &= 0x3F;
|
|
}
|
|
|
|
m_tagLength = 0;
|
|
|
|
switch (tagLengthId) {
|
|
case 0x0:
|
|
m_tagLength = 0;
|
|
break;
|
|
case 0x1: {
|
|
UCHAR clength;
|
|
m_iChan >> clength;
|
|
m_tagLength = clength;
|
|
break;
|
|
}
|
|
case 0x2: {
|
|
USHORT slength;
|
|
m_iChan >> slength;
|
|
m_tagLength = slength;
|
|
break;
|
|
}
|
|
case 0x3:
|
|
m_iChan >> m_tagLength;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
if (m_bufLength < m_tagLength) {
|
|
m_bufLength = m_tagLength;
|
|
m_buf.reset(new UCHAR[m_bufLength]);
|
|
}
|
|
|
|
if (m_tagLength) {
|
|
m_iChan.read((char *)m_buf.get(), (int)m_tagLength);
|
|
CHECK_FOR_READ_ERROR(m_filePath);
|
|
}
|
|
|
|
PliTag *newTag = NULL;
|
|
|
|
switch (tagType) {
|
|
case PliTag::SET_DATA_8_CNTRL:
|
|
m_currDinamicTypeBytesNum = 1;
|
|
break;
|
|
case PliTag::SET_DATA_16_CNTRL:
|
|
m_currDinamicTypeBytesNum = 2;
|
|
break;
|
|
case PliTag::SET_DATA_32_CNTRL:
|
|
m_currDinamicTypeBytesNum = 4;
|
|
break;
|
|
case PliTag::TEXT:
|
|
newTag = readTextTag();
|
|
break;
|
|
case PliTag::PALETTE:
|
|
newTag = readPaletteTag();
|
|
break;
|
|
case PliTag::PALETTE_WITH_ALPHA:
|
|
newTag = readPaletteWithAlphaTag();
|
|
break;
|
|
case PliTag::THICK_QUADRATIC_CHAIN_GOBJ:
|
|
case PliTag::THICK_QUADRATIC_LOOP_GOBJ:
|
|
newTag = readThickQuadraticChainTag(tagType ==
|
|
PliTag::THICK_QUADRATIC_LOOP_GOBJ);
|
|
break;
|
|
case PliTag::GROUP_GOBJ:
|
|
newTag = readGroupTag();
|
|
break;
|
|
case PliTag::IMAGE_GOBJ:
|
|
newTag = readImageTag();
|
|
break;
|
|
case PliTag::COLOR_NGOBJ:
|
|
newTag = readColorTag();
|
|
break;
|
|
case PliTag::STYLE_NGOBJ:
|
|
newTag = readStyleTag();
|
|
break;
|
|
case PliTag::GEOMETRIC_TRANSFORMATION_GOBJ:
|
|
newTag = readGeometricTransformationTag();
|
|
break;
|
|
case PliTag::DOUBLEPAIR_OBJ:
|
|
newTag = readDoublePairTag();
|
|
break;
|
|
case PliTag::BITMAP_GOBJ:
|
|
newTag = readBitmapTag();
|
|
break;
|
|
case PliTag::INTERSECTION_DATA_GOBJ:
|
|
newTag = readIntersectionDataTag();
|
|
break;
|
|
case PliTag::OUTLINE_OPTIONS_GOBJ:
|
|
newTag = readOutlineOptionsTag();
|
|
break;
|
|
case PliTag::PRECISION_SCALE_GOBJ:
|
|
newTag = readPrecisionScaleTag();
|
|
break;
|
|
case PliTag::END_CNTRL:
|
|
return 0;
|
|
}
|
|
|
|
if (newTag)
|
|
return new TagElem(newTag, tagOffset);
|
|
else
|
|
return readTag();
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::findTagFromOffset(UINT tagOffs) {
|
|
for (TagElem *elem = m_firstTag; elem; elem = elem->m_next)
|
|
if (elem->m_offset == tagOffs) return elem->m_tag;
|
|
return NULL;
|
|
}
|
|
/*=====================================================================*/
|
|
|
|
UINT ParsedPliImp::findOffsetFromTag(PliTag *tag) {
|
|
for (TagElem *elem = m_firstTag; elem; elem = elem->m_next)
|
|
if (elem->m_tag == tag) return elem->m_offset;
|
|
|
|
return 0;
|
|
}
|
|
/*=====================================================================*/
|
|
|
|
TagElem *ParsedPliImp::findTag(PliTag *tag) {
|
|
for (TagElem *elem = m_firstTag; elem; elem = elem->m_next)
|
|
if (elem->m_tag == tag) return elem;
|
|
|
|
return NULL;
|
|
}
|
|
/*=====================================================================*/
|
|
|
|
inline void ParsedPliImp::readDinamicData(TUINT32 &val, TUINT32 &bufOffs) {
|
|
switch (m_currDinamicTypeBytesNum) {
|
|
case 1:
|
|
val = m_buf[bufOffs++];
|
|
break;
|
|
case 2:
|
|
if (m_isIrixEndian)
|
|
val = m_buf[bufOffs + 1] | (m_buf[bufOffs] << 8);
|
|
else
|
|
val = m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8);
|
|
bufOffs += 2;
|
|
break;
|
|
case 4:
|
|
if (m_isIrixEndian)
|
|
val = m_buf[bufOffs + 3] | (m_buf[bufOffs + 2] << 8) |
|
|
(m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24);
|
|
else
|
|
val = m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8) |
|
|
(m_buf[bufOffs + 2] << 16) | (m_buf[bufOffs + 3] << 24);
|
|
bufOffs += 4;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline bool ParsedPliImp::readDinamicData(TINT32 &val, TUINT32 &bufOffs) {
|
|
bool isNegative = false;
|
|
|
|
switch (m_currDinamicTypeBytesNum) {
|
|
case 1:
|
|
val = m_buf[bufOffs] & 0x7f;
|
|
if (m_buf[bufOffs] & 0x80) {
|
|
val = -val;
|
|
isNegative = true;
|
|
}
|
|
bufOffs++;
|
|
break;
|
|
case 2:
|
|
if (m_isIrixEndian) {
|
|
val = (m_buf[bufOffs + 1] | (m_buf[bufOffs] << 8)) & 0x7fff;
|
|
if (m_buf[bufOffs] & 0x80) {
|
|
val = -val;
|
|
isNegative = true;
|
|
}
|
|
} else {
|
|
val = (m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8)) & 0x7fff;
|
|
if (m_buf[bufOffs + 1] & 0x80) {
|
|
val = -val;
|
|
isNegative = true;
|
|
}
|
|
}
|
|
bufOffs += 2;
|
|
break;
|
|
case 4:
|
|
if (m_isIrixEndian) {
|
|
val = m_buf[bufOffs + 3] | (m_buf[bufOffs + 2] << 8) |
|
|
(m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24) & 0x7fffffff;
|
|
if (m_buf[bufOffs] & 0x80) {
|
|
val = -val;
|
|
isNegative = true;
|
|
}
|
|
} else {
|
|
val = m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8) |
|
|
(m_buf[bufOffs + 2] << 16) |
|
|
(m_buf[bufOffs + 3] << 24) & 0x7fffffff;
|
|
if (m_buf[bufOffs + 3] & 0x80) {
|
|
val = -val;
|
|
isNegative = true;
|
|
}
|
|
}
|
|
bufOffs += 4;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
return isNegative;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readTextTag() {
|
|
if (m_tagLength == 0) return new TextTag("");
|
|
|
|
return new TextTag(string((char *)m_buf.get(), m_tagLength));
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readPaletteTag() {
|
|
TPixelRGBM32 *plt;
|
|
TUINT32 numColors = 0;
|
|
|
|
plt = new TPixelRGBM32[m_tagLength / 3];
|
|
|
|
for (unsigned int i = 0; i < m_tagLength; i += 3, numColors++) {
|
|
plt[numColors].r = m_buf[i];
|
|
plt[numColors].g = m_buf[i + 1];
|
|
plt[numColors].b = m_buf[i + 2];
|
|
}
|
|
|
|
PaletteTag *tag = new PaletteTag(numColors, plt);
|
|
|
|
delete plt;
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readPaletteWithAlphaTag() {
|
|
TPixelRGBM32 *plt;
|
|
TUINT32 numColors = 0;
|
|
|
|
plt = new TPixelRGBM32[m_tagLength / 4];
|
|
|
|
for (unsigned int i = 0; i < m_tagLength; i += 4, numColors++) {
|
|
plt[numColors].r = m_buf[i];
|
|
plt[numColors].g = m_buf[i + 1];
|
|
plt[numColors].b = m_buf[i + 2];
|
|
plt[numColors].m = m_buf[i + 3];
|
|
}
|
|
|
|
PaletteWithAlphaTag *tag = new PaletteWithAlphaTag(numColors, plt);
|
|
|
|
delete plt;
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readThickQuadraticChainTag(bool isLoop) {
|
|
TThickPoint p;
|
|
TUINT32 bufOffs = 0;
|
|
double dx1, dy1, dx2, dy2;
|
|
TINT32 d;
|
|
TUINT32 numQuadratics = 0;
|
|
double scale;
|
|
|
|
bool newThicknessWriteMethod =
|
|
((m_majorVersionNumber == 5 && m_minorVersionNumber >= 7) ||
|
|
(m_majorVersionNumber > 5));
|
|
|
|
scale = 1.0 / (double)m_precisionScale;
|
|
int maxThickness;
|
|
if (newThicknessWriteMethod)
|
|
|
|
{
|
|
maxThickness = m_buf[bufOffs++];
|
|
m_thickRatio = maxThickness / 255.0;
|
|
} else {
|
|
maxThickness = (int)m_maxThickness;
|
|
assert(m_thickRatio != 0);
|
|
}
|
|
|
|
TINT32 val;
|
|
readDinamicData(val, bufOffs);
|
|
p.x = scale * val;
|
|
readDinamicData(val, bufOffs);
|
|
p.y = scale * val;
|
|
|
|
p.thick = m_buf[bufOffs++] * m_thickRatio;
|
|
if (newThicknessWriteMethod)
|
|
numQuadratics = (m_tagLength - 2 * m_currDinamicTypeBytesNum - 1 - 1) /
|
|
(4 * m_currDinamicTypeBytesNum + 2);
|
|
else
|
|
numQuadratics = (m_tagLength - 2 * m_currDinamicTypeBytesNum - 1) /
|
|
(4 * m_currDinamicTypeBytesNum + 3);
|
|
|
|
std::unique_ptr<TThickQuadratic[]> quadratic(
|
|
new TThickQuadratic[numQuadratics]);
|
|
|
|
for (unsigned int i = 0; i < numQuadratics; i++) {
|
|
quadratic[i].setThickP0(p);
|
|
|
|
readDinamicData(d, bufOffs);
|
|
dx1 = scale * d;
|
|
readDinamicData(d, bufOffs);
|
|
dy1 = scale * d;
|
|
|
|
if (newThicknessWriteMethod)
|
|
p.thick = m_buf[bufOffs++] * m_thickRatio;
|
|
else {
|
|
if (m_isIrixEndian)
|
|
p.thick =
|
|
complement2((USHORT)(m_buf[bufOffs + 1] | (m_buf[bufOffs] << 8))) *
|
|
m_thickRatio;
|
|
else
|
|
p.thick =
|
|
complement2((USHORT)(m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8))) *
|
|
m_thickRatio;
|
|
bufOffs += 2;
|
|
}
|
|
|
|
readDinamicData(d, bufOffs);
|
|
dx2 = scale * d;
|
|
readDinamicData(d, bufOffs);
|
|
dy2 = scale * d;
|
|
|
|
if (dx1 == 0 && dy1 == 0) // p0==p1, or p1==p2 creates problems (in the
|
|
// increasecontrolpoints for example) I slightly
|
|
// move it...
|
|
{
|
|
if (dx2 != 0 || dy2 != 0) {
|
|
dx1 = 0.001 * dx2;
|
|
dx2 = 0.999 * dx2;
|
|
dy1 = 0.001 * dy2;
|
|
dy2 = 0.999 * dy2;
|
|
assert(dx1 != 0 || dy1 != 0);
|
|
}
|
|
} else if (dx2 == 0 && dy2 == 0) {
|
|
if (dx1 != 0 || dy1 != 0) {
|
|
dx2 = 0.001 * dx1;
|
|
dx1 = 0.999 * dx1;
|
|
dy2 = 0.001 * dy1;
|
|
dy1 = 0.999 * dy1;
|
|
assert(dx2 != 0 || dy2 != 0);
|
|
}
|
|
}
|
|
|
|
p.x += dx1;
|
|
p.y += dy1;
|
|
|
|
quadratic[i].setThickP1(p);
|
|
|
|
p.thick = m_buf[bufOffs++] * m_thickRatio;
|
|
|
|
p.x += dx2;
|
|
p.y += dy2;
|
|
|
|
quadratic[i].setThickP2(p);
|
|
}
|
|
|
|
ThickQuadraticChainTag *tag = new ThickQuadraticChainTag();
|
|
tag->m_numCurves = numQuadratics;
|
|
tag->m_curve = std::move(quadratic);
|
|
tag->m_isLoop = isLoop;
|
|
tag->m_maxThickness = maxThickness;
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readGroupTag() {
|
|
TUINT32 bufOffs = 0;
|
|
|
|
UCHAR type = m_buf[bufOffs++];
|
|
|
|
assert(type < GroupTag::TYPE_HOW_MANY);
|
|
|
|
TUINT32 numObjects = (m_tagLength - 1) / m_currDinamicTypeBytesNum;
|
|
std::unique_ptr<PliObjectTag *[]> object(new PliObjectTag *[numObjects]);
|
|
|
|
std::unique_ptr<TUINT32[]> tagOffs(new TUINT32[numObjects]);
|
|
|
|
for (TUINT32 i = 0; i < numObjects; i++) {
|
|
readDinamicData(tagOffs[i], bufOffs);
|
|
}
|
|
|
|
TagElem *elem;
|
|
for (TUINT32 i = 0; i < numObjects; i++)
|
|
while (!(object[i] = (PliObjectTag *)findTagFromOffset(tagOffs[i])))
|
|
if ((elem = readTag()))
|
|
addTag(*elem);
|
|
else
|
|
assert(false);
|
|
|
|
std::unique_ptr<GroupTag> tag(new GroupTag());
|
|
tag->m_type = type;
|
|
tag->m_numObjects = numObjects;
|
|
tag->m_object = std::move(object);
|
|
|
|
return tag.release();
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readColorTag() {
|
|
ColorTag::styleType style;
|
|
ColorTag::attributeType attribute;
|
|
TUINT32 bufOffs = 0;
|
|
|
|
style = (ColorTag::styleType)m_buf[bufOffs++];
|
|
attribute = (ColorTag::attributeType)m_buf[bufOffs++];
|
|
|
|
assert(style < ColorTag::STYLE_HOW_MANY);
|
|
assert(attribute < ColorTag::ATTRIBUTE_HOW_MANY);
|
|
|
|
TUINT32 numColors = (m_tagLength - 2) / m_currDinamicTypeBytesNum;
|
|
std::unique_ptr<TUINT32[]> colorArray(new TUINT32[numColors]);
|
|
|
|
for (unsigned int i = 0; i < numColors; i++) {
|
|
TUINT32 color;
|
|
|
|
readDinamicData(color, bufOffs);
|
|
colorArray[i] = color;
|
|
}
|
|
|
|
std::unique_ptr<ColorTag> tag(
|
|
new ColorTag(style, attribute, numColors, std::move(colorArray)));
|
|
return tag.release();
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readStyleTag() {
|
|
std::vector<TStyleParam> paramArray;
|
|
TUINT32 bufOffs = 0;
|
|
int lenght = m_tagLength;
|
|
UINT i;
|
|
USHORT id = 0;
|
|
USHORT pageIndex = 0;
|
|
|
|
UCHAR currDinamicTypeBytesNumSaved = m_currDinamicTypeBytesNum;
|
|
m_currDinamicTypeBytesNum = 2;
|
|
|
|
readUShortData(id, bufOffs);
|
|
lenght -= 2;
|
|
if (m_majorVersionNumber > 5 ||
|
|
(m_majorVersionNumber == 5 && m_minorVersionNumber >= 6)) {
|
|
readUShortData(pageIndex, bufOffs);
|
|
lenght -= 2;
|
|
}
|
|
while (lenght > 0) {
|
|
TStyleParam param;
|
|
|
|
param.m_type = (enum TStyleParam::Type)m_buf[bufOffs++];
|
|
lenght--;
|
|
switch (param.m_type) {
|
|
case TStyleParam::SP_BYTE:
|
|
param.m_numericVal = m_buf[bufOffs++];
|
|
lenght--;
|
|
break;
|
|
case TStyleParam::SP_USHORT: {
|
|
USHORT val;
|
|
readUShortData(val, bufOffs);
|
|
param.m_numericVal = val;
|
|
lenght -= 2;
|
|
break;
|
|
}
|
|
case TStyleParam::SP_INT:
|
|
case TStyleParam::SP_DOUBLE:
|
|
readFloatData(param.m_numericVal, bufOffs);
|
|
lenght -= 4;
|
|
break;
|
|
case TStyleParam::SP_RASTER:
|
|
lenght -= readRasterData(param.m_r, bufOffs);
|
|
break;
|
|
case TStyleParam::SP_STRING: {
|
|
USHORT strLen;
|
|
readUShortData(strLen, bufOffs);
|
|
// bufOffs+=2;
|
|
param.m_string = "";
|
|
for (i = 0; i < strLen; i++) {
|
|
param.m_string.append(1, m_buf[bufOffs++]);
|
|
}
|
|
lenght -= strLen + sizeof(USHORT);
|
|
break;
|
|
}
|
|
default:
|
|
assert(false);
|
|
}
|
|
paramArray.push_back(param);
|
|
}
|
|
|
|
int paramArraySize = paramArray.size();
|
|
StyleTag *tag =
|
|
new StyleTag(id, pageIndex, paramArraySize,
|
|
(paramArraySize > 0) ? paramArray.data() : nullptr);
|
|
m_currDinamicTypeBytesNum = currDinamicTypeBytesNumSaved;
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readOutlineOptionsTag() {
|
|
TUINT32 bufOffs = 0;
|
|
TINT32 d;
|
|
|
|
const double scale = 0.001;
|
|
|
|
// Read OutlineOptions
|
|
int capStyle, joinStyle;
|
|
double miterLower, miterUpper;
|
|
|
|
capStyle = m_buf[bufOffs++];
|
|
joinStyle = m_buf[bufOffs++];
|
|
|
|
readDinamicData(d, bufOffs);
|
|
miterLower = scale * d;
|
|
readDinamicData(d, bufOffs);
|
|
miterUpper = scale * d;
|
|
|
|
return new StrokeOutlineOptionsTag(
|
|
TStroke::OutlineOptions(capStyle, joinStyle, miterLower, miterUpper));
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readPrecisionScaleTag() {
|
|
TUINT32 bufOffs = 0;
|
|
|
|
TINT32 d;
|
|
readDinamicData(d, bufOffs);
|
|
m_precisionScale = d;
|
|
|
|
return new PrecisionScaleTag(m_precisionScale);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::readFloatData(double &val, TUINT32 &bufOffs) {
|
|
// UCHAR currDinamicTypeBytesNumSaved = m_currDinamicTypeBytesNum;
|
|
// m_currDinamicTypeBytesNum = 2;
|
|
TINT32 valInt;
|
|
TUINT32 valDec;
|
|
bool isNegative;
|
|
|
|
isNegative = readDinamicData(valInt, bufOffs);
|
|
readDinamicData(valDec, bufOffs);
|
|
|
|
val = valInt + (double)valDec / 65536.0; // 2^16
|
|
|
|
if (valInt == 0 && isNegative) val = -val;
|
|
|
|
// m_currDinamicTypeBytesNum = currDinamicTypeBytesNumSaved;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
UINT ParsedPliImp::readRasterData(TRaster32P &r, TUINT32 &bufOffs) {
|
|
USHORT lx, ly;
|
|
readUShortData(lx, bufOffs);
|
|
readUShortData(ly, bufOffs);
|
|
|
|
// readUShortData((USHORT&)lx, bufOffs);
|
|
// readUShortData((USHORT&)ly, bufOffs);
|
|
|
|
r.create((int)lx, (int)ly);
|
|
UINT size = lx * ly * 4;
|
|
r->lock();
|
|
memcpy(r->getRawData(), m_buf.get() + bufOffs, size);
|
|
r->unlock();
|
|
bufOffs += size;
|
|
return size + 2 + 2;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline void getLongValFromFloat(double val, TINT32 &intVal, TUINT32 &decVal) {
|
|
intVal = (TINT32)val;
|
|
if (val < 0) decVal = (TUINT32)((double)((-val) - (-intVal)) * 65536.0);
|
|
/*if (intVal<(0x1<<7))
|
|
intVal|=(0x1<<7);
|
|
else if (intVal<(0x1<<15))
|
|
intVal|=(0x1<<15);
|
|
else
|
|
{
|
|
assert(intVal<(0x1<<31));
|
|
intVal|=(0x1<<31);
|
|
}*/
|
|
else
|
|
decVal = (TUINT32)((double)(val - intVal) * 65536.0);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::writeFloatData(double val) {
|
|
UCHAR currDinamicTypeBytesNumSaved = m_currDinamicTypeBytesNum;
|
|
m_currDinamicTypeBytesNum = 2;
|
|
TINT32 valInt;
|
|
TUINT32 valDec;
|
|
// bool neg=false;
|
|
|
|
valInt = (int)val;
|
|
|
|
if (val < 0)
|
|
valDec = (int)((double)(-val + valInt) * 65536.0);
|
|
else
|
|
valDec = (int)((double)(val - valInt) * 65536.0);
|
|
|
|
assert(valInt < (0x1 << 15));
|
|
assert(valDec < (0x1 << 16));
|
|
|
|
writeDinamicData(valInt, val < 0);
|
|
writeDinamicData(valDec);
|
|
m_currDinamicTypeBytesNum = currDinamicTypeBytesNumSaved;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readGeometricTransformationTag() {
|
|
TUINT32 bufOffs = 0;
|
|
TAffine affine;
|
|
|
|
readFloatData(affine.a11, bufOffs);
|
|
readFloatData(affine.a12, bufOffs);
|
|
readFloatData(affine.a13, bufOffs);
|
|
readFloatData(affine.a21, bufOffs);
|
|
readFloatData(affine.a22, bufOffs);
|
|
readFloatData(affine.a23, bufOffs);
|
|
|
|
TUINT32 tagOffs;
|
|
readDinamicData(tagOffs, bufOffs);
|
|
|
|
TagElem *elem;
|
|
PliObjectTag *object = NULL;
|
|
if (tagOffs != 0)
|
|
while (!(object = (PliObjectTag *)findTagFromOffset(tagOffs)))
|
|
if ((elem = readTag()))
|
|
addTag(*elem);
|
|
else
|
|
assert(false);
|
|
else
|
|
m_affine = affine;
|
|
|
|
/*int realScale = tround(log10(1.0/m_affine.a11));
|
|
|
|
m_affine = TScale(1.0/pow(10.0, realScale));*/
|
|
|
|
GeometricTransformationTag *tag =
|
|
new GeometricTransformationTag(affine, (PliGeometricTag *)object);
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readDoublePairTag() {
|
|
TUINT32 bufOffs = 0;
|
|
double first, second;
|
|
|
|
readFloatData(first, bufOffs);
|
|
readFloatData(second, bufOffs);
|
|
|
|
DoublePairTag *tag = new DoublePairTag(first, second);
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::readUShortData(USHORT &val, TUINT32 &bufOffs) {
|
|
if (m_isIrixEndian)
|
|
val = m_buf[bufOffs + 1] | (m_buf[bufOffs] << 8);
|
|
else
|
|
val = m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8);
|
|
|
|
bufOffs += 2;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::readTUINT32Data(TUINT32 &val, TUINT32 &bufOffs) {
|
|
if (m_isIrixEndian)
|
|
val = m_buf[bufOffs + 3] | (m_buf[bufOffs + 2] << 8) |
|
|
(m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24);
|
|
else
|
|
val = m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8) |
|
|
(m_buf[bufOffs + 2] << 16) | (m_buf[bufOffs + 3] << 24);
|
|
|
|
bufOffs += 4;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readBitmapTag() {
|
|
USHORT lx, ly;
|
|
TUINT32 bufOffs = 0;
|
|
|
|
readUShortData(lx, bufOffs);
|
|
readUShortData(ly, bufOffs);
|
|
|
|
TRaster32P r;
|
|
|
|
r.create(lx, ly);
|
|
r->lock();
|
|
memcpy(r->getRawData(), m_buf.get() + bufOffs, lx * ly * 4);
|
|
r->unlock();
|
|
BitmapTag *tag = new BitmapTag(r);
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readImageTag() {
|
|
USHORT frame;
|
|
TUINT32 bufOffs = 0;
|
|
|
|
if (m_isIrixEndian)
|
|
frame = m_buf[bufOffs + 1] | (m_buf[bufOffs] << 8);
|
|
else
|
|
frame = m_buf[bufOffs] | (m_buf[bufOffs + 1] << 8);
|
|
|
|
bufOffs += 2;
|
|
|
|
int headerLength = 2;
|
|
char letter = 0;
|
|
if (m_majorVersionNumber > 6 ||
|
|
(m_majorVersionNumber == 6 && m_minorVersionNumber >= 6)) {
|
|
letter = (char)m_buf[bufOffs++];
|
|
++headerLength;
|
|
}
|
|
|
|
TUINT32 numObjects = (m_tagLength - headerLength) / m_currDinamicTypeBytesNum;
|
|
std::unique_ptr<PliObjectTag *[]> object(new PliObjectTag *[numObjects]);
|
|
|
|
std::unique_ptr<TUINT32[]> tagOffs(new TUINT32[numObjects]);
|
|
for (TUINT32 i = 0; i < numObjects; i++) {
|
|
readDinamicData(tagOffs[i], bufOffs);
|
|
}
|
|
|
|
TagElem *elem;
|
|
for (TUINT32 i = 0; i < numObjects; i++)
|
|
while (!(object[i] = (PliObjectTag *)findTagFromOffset(tagOffs[i])))
|
|
if ((elem = readTag()))
|
|
addTag(*elem);
|
|
else
|
|
assert(false);
|
|
|
|
std::unique_ptr<ImageTag[]> tag(
|
|
new ImageTag(TFrameId(frame, letter), numObjects, std::move(object)));
|
|
return tag.release();
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
const TSolidColorStyle ConstStyle(TPixel32::Red);
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline double doubleFromUlong(TUINT32 q) {
|
|
assert((q & 0X00000001) == 0);
|
|
TUINT32 l[2];
|
|
#if TNZ_LITTLE_ENDIAN
|
|
l[1] = 0x3FF00000 | (q >> 12);
|
|
l[0] = (q & 0xFFE) << 20;
|
|
#else
|
|
l[0] = 0x3FF00000 | (q >> 12);
|
|
l[1] = (q & 0xFFE) << 20;
|
|
#endif
|
|
|
|
return *(double *)l - 1;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
// vedi commento sulla write per chiarimenti!!
|
|
|
|
inline double truncate(double x) {
|
|
x += 1.0;
|
|
TUINT32 *l = (TUINT32 *)&x;
|
|
|
|
#if TNZ_LITTLE_ENDIAN
|
|
l[0] &= 0xFFE00000;
|
|
#else
|
|
l[1] &= 0xFFE00000;
|
|
#endif
|
|
|
|
return x - 1.0;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPliImp::readIntersectionDataTag() {
|
|
TUINT32 bufOffs = 0;
|
|
TUINT32 branchCount;
|
|
|
|
readTUINT32Data(branchCount, bufOffs);
|
|
|
|
std::unique_ptr<IntersectionBranch[]> branchArray(
|
|
new IntersectionBranch[branchCount]);
|
|
|
|
UINT i;
|
|
for (i = 0; i < branchCount; i++) {
|
|
TINT32 currInter;
|
|
readDinamicData((TINT32 &)branchArray[i].m_strokeIndex, bufOffs);
|
|
readDinamicData(currInter, bufOffs);
|
|
readDinamicData((TUINT32 &)branchArray[i].m_nextBranch, bufOffs);
|
|
USHORT style;
|
|
readUShortData(style, bufOffs);
|
|
branchArray[i].m_style = style;
|
|
/*
|
|
*/
|
|
if (m_buf[bufOffs] & 0x80) // in un numero double tra 0 e 1, il bit piu'
|
|
// significativo e' sempre 0
|
|
// sfrutto questo bit; se e' 1, vuol dire che il valore e' 0.0 o 1.0 in un
|
|
// singolo byte
|
|
{
|
|
branchArray[i].m_w = (m_buf[bufOffs] & 0x1) ? 1.0 : 0.0;
|
|
bufOffs++;
|
|
} else {
|
|
TUINT32 hi, lo;
|
|
hi = m_buf[bufOffs + 3] | (m_buf[bufOffs + 2] << 8) |
|
|
(m_buf[bufOffs + 1] << 16) | (m_buf[bufOffs] << 24);
|
|
bufOffs += 4;
|
|
readTUINT32Data(lo, bufOffs);
|
|
// readTUINT32Data(hi, bufOffs);
|
|
|
|
branchArray[i].m_w = doubleFromUlong1(hi, lo);
|
|
}
|
|
|
|
if (currInter < 0) {
|
|
branchArray[i].m_currInter = -currInter - 1;
|
|
branchArray[i].m_gettingOut = false;
|
|
} else {
|
|
branchArray[i].m_currInter = currInter - 1;
|
|
branchArray[i].m_gettingOut = true;
|
|
}
|
|
}
|
|
|
|
IntersectionDataTag *tag = new IntersectionDataTag();
|
|
tag->m_branchCount = branchCount;
|
|
tag->m_branchArray = std::move(branchArray);
|
|
|
|
return tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
bool ParsedPliImp::addTag(PliTag *tagPtr, bool addFront) {
|
|
TagElem *_tag = new TagElem(tagPtr, 0);
|
|
|
|
assert(tagPtr->m_type);
|
|
|
|
if (!m_firstTag) {
|
|
m_firstTag = m_lastTag = _tag;
|
|
} else if (addFront) {
|
|
_tag->m_next = m_firstTag;
|
|
m_firstTag = _tag;
|
|
} else {
|
|
m_lastTag->m_next = _tag;
|
|
m_lastTag = m_lastTag->m_next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
bool ParsedPliImp::addTag(const TagElem &elem, bool addFront) {
|
|
TagElem *_tag = new TagElem(elem);
|
|
|
|
if (!m_firstTag) {
|
|
m_firstTag = m_lastTag = _tag;
|
|
} else if (addFront) {
|
|
_tag->m_next = m_firstTag;
|
|
m_firstTag = _tag;
|
|
} else {
|
|
m_lastTag->m_next = _tag;
|
|
m_lastTag = m_lastTag->m_next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::writeTag(TagElem *elem) {
|
|
if (elem->m_offset != 0) // already written
|
|
return;
|
|
|
|
switch (elem->m_tag->m_type) {
|
|
case PliTag::TEXT:
|
|
elem->m_offset = writeTextTag((TextTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::PALETTE:
|
|
elem->m_offset = writePaletteTag((PaletteTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::PALETTE_WITH_ALPHA:
|
|
elem->m_offset =
|
|
writePaletteWithAlphaTag((PaletteWithAlphaTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::THICK_QUADRATIC_CHAIN_GOBJ:
|
|
elem->m_offset =
|
|
writeThickQuadraticChainTag((ThickQuadraticChainTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::GROUP_GOBJ:
|
|
elem->m_offset = writeGroupTag((GroupTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::IMAGE_GOBJ:
|
|
elem->m_offset = writeImageTag((ImageTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::COLOR_NGOBJ:
|
|
elem->m_offset = writeColorTag((ColorTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::STYLE_NGOBJ:
|
|
elem->m_offset = writeStyleTag((StyleTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::GEOMETRIC_TRANSFORMATION_GOBJ:
|
|
elem->m_offset = writeGeometricTransformationTag(
|
|
(GeometricTransformationTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::DOUBLEPAIR_OBJ:
|
|
elem->m_offset = writeDoublePairTag((DoublePairTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::BITMAP_GOBJ:
|
|
elem->m_offset = writeBitmapTag((BitmapTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::INTERSECTION_DATA_GOBJ:
|
|
elem->m_offset =
|
|
writeIntersectionDataTag((IntersectionDataTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::OUTLINE_OPTIONS_GOBJ:
|
|
elem->m_offset =
|
|
writeOutlineOptionsTag((StrokeOutlineOptionsTag *)elem->m_tag);
|
|
break;
|
|
case PliTag::PRECISION_SCALE_GOBJ:
|
|
elem->m_offset = writePrecisionScaleTag((PrecisionScaleTag *)elem->m_tag);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
// m_error = UNKNOWN_TAG;
|
|
;
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline void ParsedPliImp::setDinamicTypeBytesNum(int minval, int maxval) {
|
|
assert(m_oChan);
|
|
if (maxval > 32767 || minval < -32767) {
|
|
if (m_currDinamicTypeBytesNum != 4) {
|
|
m_currDinamicTypeBytesNum = 4;
|
|
*m_oChan << (UCHAR)PliTag::SET_DATA_32_CNTRL;
|
|
}
|
|
} else if (maxval > 127 || minval < -127) {
|
|
if (m_currDinamicTypeBytesNum != 2) {
|
|
m_currDinamicTypeBytesNum = 2;
|
|
*m_oChan << (UCHAR)PliTag::SET_DATA_16_CNTRL;
|
|
}
|
|
} else if (m_currDinamicTypeBytesNum != 1) {
|
|
m_currDinamicTypeBytesNum = 1;
|
|
*m_oChan << (UCHAR)PliTag::SET_DATA_8_CNTRL;
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline void ParsedPliImp::writeDinamicData(TUINT32 val) {
|
|
assert(m_oChan);
|
|
switch (m_currDinamicTypeBytesNum) {
|
|
case 1:
|
|
*m_oChan << (UCHAR)val;
|
|
break;
|
|
case 2:
|
|
*m_oChan << (USHORT)val;
|
|
break;
|
|
case 4:
|
|
*m_oChan << (TUINT32)val;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline void ParsedPliImp::writeDinamicData(TINT32 val,
|
|
bool isNegative = false) {
|
|
assert(m_oChan);
|
|
switch (m_currDinamicTypeBytesNum) {
|
|
case 1:
|
|
*m_oChan << complement1((char)val, isNegative);
|
|
break;
|
|
case 2:
|
|
*m_oChan << complement1((short)val, isNegative);
|
|
break;
|
|
case 4:
|
|
*m_oChan << complement1(val, isNegative);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeTagHeader(UCHAR type, UINT tagLength) {
|
|
assert(m_oChan);
|
|
TUINT32 offset = m_oChan->tellp();
|
|
|
|
assert((type & 0xc0) == 0x0);
|
|
|
|
if (tagLength == 0)
|
|
*m_oChan << type;
|
|
else if (tagLength < 256) {
|
|
*m_oChan << (UCHAR)(type | (0x1 << 6));
|
|
*m_oChan << (UCHAR)tagLength;
|
|
} else if (tagLength < 65535) {
|
|
*m_oChan << (UCHAR)(type | (0x2 << 6));
|
|
*m_oChan << (USHORT)tagLength;
|
|
} else {
|
|
*m_oChan << (UCHAR)(type | (0x3 << 6));
|
|
*m_oChan << (TUINT32)tagLength;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeTextTag(TextTag *tag) {
|
|
assert(m_oChan);
|
|
int offset, tagLength = tag->m_text.length();
|
|
|
|
offset = (int)writeTagHeader((UCHAR)PliTag::TEXT, tagLength);
|
|
|
|
for (int i = 0; i < tagLength; i++) *m_oChan << tag->m_text[i];
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writePaletteTag(PaletteTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
int offset, tagLength = (int)(tag->m_numColors * 3);
|
|
|
|
offset = (int)writeTagHeader((UCHAR)PliTag::PALETTE, tagLength);
|
|
|
|
for (unsigned int i = 0; i < tag->m_numColors; i++) {
|
|
*m_oChan << tag->m_color[i].r;
|
|
*m_oChan << tag->m_color[i].g;
|
|
*m_oChan << tag->m_color[i].b;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writePaletteWithAlphaTag(PaletteWithAlphaTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
int offset, tagLength = (int)(tag->m_numColors * 4);
|
|
|
|
offset = (int)writeTagHeader((UCHAR)PliTag::PALETTE_WITH_ALPHA, tagLength);
|
|
|
|
for (unsigned int i = 0; i < tag->m_numColors; i++) {
|
|
*m_oChan << tag->m_color[i].r;
|
|
*m_oChan << tag->m_color[i].g;
|
|
*m_oChan << tag->m_color[i].b;
|
|
*m_oChan << tag->m_color[i].m;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
#define SET_MINMAX \
|
|
if (p.x < minval) minval = (int)p.x; \
|
|
if (p.y < minval) minval = (int)p.y; \
|
|
if (p.x > maxval) maxval = (int)p.x; \
|
|
if (p.y > maxval) maxval = (int)p.y;
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline void ParsedPliImp::WRITE_UCHAR_FROM_DOUBLE(double dval) {
|
|
assert(m_oChan);
|
|
int ival = tround(dval);
|
|
if (ival > 255) ival = 255;
|
|
assert(ival >= 0);
|
|
*m_oChan << (UCHAR)ival;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
inline void ParsedPliImp::WRITE_SHORT_FROM_DOUBLE(double dval) {
|
|
assert(m_oChan);
|
|
int ival = (int)(dval);
|
|
assert(ival >= -32768 && ival < 32768);
|
|
*m_oChan << complement1((short)ival);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeThickQuadraticChainTag(ThickQuadraticChainTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
int maxval = -(std::numeric_limits<int>::max)(),
|
|
minval = (std::numeric_limits<int>::max)();
|
|
TPointD p;
|
|
double scale;
|
|
int i;
|
|
|
|
assert(m_majorVersionNumber > 5 ||
|
|
(m_majorVersionNumber == 5 && m_minorVersionNumber >= 5));
|
|
|
|
scale = m_precisionScale;
|
|
|
|
/*for ( i=0; i<tag->m_numCurves; i++)
|
|
tag->m_curve[i] = aff*tag->m_curve[i];*/
|
|
|
|
p = scale * tag->m_curve[0].getP0();
|
|
SET_MINMAX
|
|
|
|
for (i = 0; i < (int)tag->m_numCurves; i++) {
|
|
p = scale * (tag->m_curve[i].getP1() - tag->m_curve[i].getP0());
|
|
SET_MINMAX
|
|
p = scale * (tag->m_curve[i].getP2() - tag->m_curve[i].getP1());
|
|
SET_MINMAX
|
|
}
|
|
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
int tagLength =
|
|
(int)(2 * (2 * tag->m_numCurves + 1) * m_currDinamicTypeBytesNum + 1 + 1 +
|
|
2 * tag->m_numCurves);
|
|
int offset;
|
|
if (tag->m_isLoop)
|
|
offset = (int)writeTagHeader((UCHAR)PliTag::THICK_QUADRATIC_LOOP_GOBJ,
|
|
tagLength);
|
|
else
|
|
offset = (int)writeTagHeader((UCHAR)PliTag::THICK_QUADRATIC_CHAIN_GOBJ,
|
|
tagLength);
|
|
|
|
// assert(scale*tag->m_curve[0].getThickP0().x ==
|
|
// (double)(TINT32)(scale*tag->m_curve[0].getThickP0().x));
|
|
// assert(scale*tag->m_curve[0].getThickP0().y ==
|
|
// (double)(TINT32)(scale*tag->m_curve[0].getThickP0().y));
|
|
double thickRatio = tag->m_maxThickness / 255.0;
|
|
|
|
assert(tag->m_maxThickness <= 255);
|
|
assert(tag->m_maxThickness > 0);
|
|
UCHAR maxThickness = (UCHAR)(tceil(tag->m_maxThickness));
|
|
|
|
*m_oChan << maxThickness;
|
|
thickRatio = maxThickness / 255.0;
|
|
writeDinamicData((TINT32)(scale * tag->m_curve[0].getThickP0().x));
|
|
writeDinamicData((TINT32)(scale * tag->m_curve[0].getThickP0().y));
|
|
double thick = tag->m_curve[0].getThickP0().thick / thickRatio;
|
|
|
|
WRITE_UCHAR_FROM_DOUBLE(thick < 0 ? 0 : thick);
|
|
|
|
for (i = 0; i < (int)tag->m_numCurves; i++) {
|
|
TPoint dp =
|
|
convert(scale * (tag->m_curve[i].getP1() - tag->m_curve[i].getP0()));
|
|
|
|
assert(dp.x == (double)(TINT32)dp.x);
|
|
assert(dp.y == (double)(TINT32)dp.y);
|
|
|
|
writeDinamicData((TINT32)dp.x);
|
|
writeDinamicData((TINT32)dp.y);
|
|
thick = tag->m_curve[i].getThickP1().thick / thickRatio;
|
|
|
|
WRITE_UCHAR_FROM_DOUBLE(thick < 0 ? 0 : thick);
|
|
dp = convert(scale * (tag->m_curve[i].getP2() - tag->m_curve[i].getP1()));
|
|
writeDinamicData((TINT32)dp.x);
|
|
writeDinamicData((TINT32)dp.y);
|
|
thick = tag->m_curve[i].getThickP2().thick / thickRatio;
|
|
|
|
WRITE_UCHAR_FROM_DOUBLE(thick < 0 ? 0 : thick);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeGroupTag(GroupTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
TUINT32 offset, tagLength;
|
|
int maxval = 0, minval = 100000;
|
|
std::vector<TUINT32> objectOffset(tag->m_numObjects);
|
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < tag->m_numObjects; i++) {
|
|
if (!(objectOffset[i] =
|
|
findOffsetFromTag(tag->m_object[i]))) // the object was not
|
|
// already written before:
|
|
// write it now
|
|
{
|
|
TagElem elem(tag->m_object[i], 0);
|
|
writeTag(&elem);
|
|
objectOffset[i] = elem.m_offset;
|
|
addTag(elem);
|
|
elem.m_tag = 0;
|
|
}
|
|
|
|
if (objectOffset[i] < (unsigned int)minval) minval = (int)objectOffset[i];
|
|
if (objectOffset[i] > (unsigned int)maxval) maxval = (int)objectOffset[i];
|
|
}
|
|
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
tagLength = tag->m_numObjects * m_currDinamicTypeBytesNum + 1;
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::GROUP_GOBJ, tagLength);
|
|
|
|
*m_oChan << tag->m_type;
|
|
|
|
for (i = 0; i < tag->m_numObjects; i++) writeDinamicData(objectOffset[i]);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeImageTag(ImageTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
TUINT32 *objectOffset, offset, tagLength;
|
|
int maxval = 0, minval = 100000;
|
|
|
|
writeTagHeader((UCHAR)PliTag::IMAGE_BEGIN_GOBJ, 3);
|
|
*m_oChan << (USHORT)tag->m_numFrame.getNumber();
|
|
*m_oChan << tag->m_numFrame.getLetter();
|
|
|
|
m_currDinamicTypeBytesNum = 3;
|
|
|
|
objectOffset = new TUINT32[tag->m_numObjects];
|
|
unsigned int i;
|
|
for (i = 0; i < tag->m_numObjects; i++) {
|
|
if (!(objectOffset[i] =
|
|
findOffsetFromTag(tag->m_object[i]))) // the object was not
|
|
// already written before:
|
|
// write it now
|
|
{
|
|
TagElem elem(tag->m_object[i], 0);
|
|
writeTag(&elem);
|
|
objectOffset[i] = elem.m_offset;
|
|
addTag(elem);
|
|
elem.m_tag = 0;
|
|
}
|
|
|
|
if (objectOffset[i] < (unsigned int)minval) minval = (int)objectOffset[i];
|
|
if (objectOffset[i] > (unsigned int)maxval) maxval = (int)objectOffset[i];
|
|
}
|
|
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
tagLength = tag->m_numObjects * m_currDinamicTypeBytesNum + 3;
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::IMAGE_GOBJ, tagLength);
|
|
|
|
*m_oChan << (USHORT)tag->m_numFrame.getNumber();
|
|
*m_oChan << tag->m_numFrame.getLetter();
|
|
|
|
for (i = 0; i < tag->m_numObjects; i++) writeDinamicData(objectOffset[i]);
|
|
|
|
delete objectOffset;
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
/*struct intersectionBranch
|
|
{
|
|
int m_strokeIndex;
|
|
const TColorStyle* m_style;
|
|
double m_w;
|
|
UINT currInter;
|
|
UINT m_nextBranch;
|
|
bool m_gettingOut;
|
|
};
|
|
*/
|
|
|
|
// per scrivere il valore m_w, molto spesso vale 0 oppure 1;
|
|
// se vale 0, scrivo un bye con valore 0x0;
|
|
// se vale 1, scrivo un bye con valore 0x1;
|
|
// altrimenti, 4 byte con val&0x3==0x2;
|
|
// e gli altri (32-2) bit contenenti iol valore di w.
|
|
|
|
inline TUINT32 ulongFromDouble(double x) {
|
|
assert(x < 1.0);
|
|
x += 1.0;
|
|
TUINT32 *l = (TUINT32 *)&x;
|
|
#if TNZ_LITTLE_ENDIAN
|
|
TUINT32 hi = l[1], lo = l[0];
|
|
#else
|
|
TUINT32 hi = l[0], lo = l[1];
|
|
#endif
|
|
|
|
return (hi & 0XFFFFF) << 12 | ((lo & 0xFFE00000) >> 20);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeIntersectionDataTag(IntersectionDataTag *tag) {
|
|
TUINT32 offset, tagLength;
|
|
int maxval = -100000, minval = 100000;
|
|
// bool isNew = false;
|
|
int floatWCount = 0;
|
|
unsigned int i;
|
|
|
|
assert(m_oChan);
|
|
|
|
if (-(int)tag->m_branchCount - 1 < minval)
|
|
minval = -(int)tag->m_branchCount - 1;
|
|
if ((int)tag->m_branchCount + 1 > maxval)
|
|
maxval = (int)tag->m_branchCount + 1;
|
|
|
|
for (i = 0; i < tag->m_branchCount; i++) {
|
|
if (tag->m_branchArray[i].m_w != 0 && tag->m_branchArray[i].m_w != 1)
|
|
floatWCount++;
|
|
if (tag->m_branchArray[i].m_strokeIndex < minval)
|
|
minval = tag->m_branchArray[i].m_strokeIndex;
|
|
else if (tag->m_branchArray[i].m_strokeIndex > maxval)
|
|
maxval = tag->m_branchArray[i].m_strokeIndex;
|
|
}
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
tagLength = 4 + tag->m_branchCount * (3 * m_currDinamicTypeBytesNum + 2) +
|
|
floatWCount * 8 + (tag->m_branchCount - floatWCount) * 1;
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::INTERSECTION_DATA_GOBJ, tagLength);
|
|
|
|
*m_oChan << (TUINT32)tag->m_branchCount;
|
|
|
|
for (i = 0; i < tag->m_branchCount; i++) {
|
|
writeDinamicData((TINT32)tag->m_branchArray[i].m_strokeIndex);
|
|
writeDinamicData((tag->m_branchArray[i].m_gettingOut)
|
|
? (TINT32)(tag->m_branchArray[i].m_currInter + 1)
|
|
: -(TINT32)(tag->m_branchArray[i].m_currInter + 1));
|
|
writeDinamicData((TUINT32)tag->m_branchArray[i].m_nextBranch);
|
|
|
|
assert(tag->m_branchArray[i].m_style >= 0 &&
|
|
tag->m_branchArray[i].m_style < 65536);
|
|
*m_oChan << (USHORT)tag->m_branchArray[i].m_style;
|
|
|
|
assert(tag->m_branchArray[i].m_w >= 0 && tag->m_branchArray[i].m_w <= 1);
|
|
|
|
if (tag->m_branchArray[i].m_w == 0)
|
|
*m_oChan << ((UCHAR)0x80);
|
|
else if (tag->m_branchArray[i].m_w == 1)
|
|
*m_oChan << ((UCHAR)0x81);
|
|
else {
|
|
TUINT32 hi, lo;
|
|
ulongFromDouble1(tag->m_branchArray[i].m_w, hi, lo);
|
|
assert((hi & 0x80000000) == 0);
|
|
*m_oChan << (UCHAR)((hi >> 24) & 0xff);
|
|
*m_oChan << (UCHAR)((hi >> 16) & 0xff);
|
|
*m_oChan << (UCHAR)((hi >> 8) & 0xff);
|
|
*m_oChan << (UCHAR)((hi)&0xff);
|
|
// m_oChan<<((TUINT32)hi);
|
|
*m_oChan << (TUINT32)(lo);
|
|
// m_oChan<<((TUINT32)hi);
|
|
}
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeColorTag(ColorTag *tag) {
|
|
assert(m_oChan);
|
|
TUINT32 tagLength, offset;
|
|
int maxval = 0, minval = 100000;
|
|
unsigned int i;
|
|
for (i = 0; i < tag->m_numColors; i++) {
|
|
if (tag->m_color[i] < (unsigned int)minval) minval = (int)tag->m_color[i];
|
|
if (tag->m_color[i] > (unsigned int)maxval) maxval = (int)tag->m_color[i];
|
|
}
|
|
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
tagLength = tag->m_numColors * m_currDinamicTypeBytesNum + 2;
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::COLOR_NGOBJ, tagLength);
|
|
|
|
*m_oChan << (UCHAR)tag->m_style;
|
|
*m_oChan << (UCHAR)tag->m_attribute;
|
|
|
|
for (i = 0; i < tag->m_numColors; i++) writeDinamicData(tag->m_color[i]);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeStyleTag(StyleTag *tag) {
|
|
assert(m_oChan);
|
|
TUINT32 tagLength = 0, offset;
|
|
// int maxval=0, minval = 100000;
|
|
int i;
|
|
|
|
tagLength = 2 + 2;
|
|
for (i = 0; i < tag->m_numParams; i++)
|
|
tagLength += 1 + tag->m_param[i].getSize();
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::STYLE_NGOBJ, tagLength);
|
|
|
|
*m_oChan << tag->m_id;
|
|
*m_oChan << tag->m_pageIndex;
|
|
|
|
for (i = 0; i < tag->m_numParams; i++) {
|
|
*m_oChan << (UCHAR)tag->m_param[i].m_type;
|
|
switch (tag->m_param[i].m_type) {
|
|
case TStyleParam::SP_BYTE:
|
|
*m_oChan << (UCHAR)tag->m_param[i].m_numericVal;
|
|
break;
|
|
case TStyleParam::SP_USHORT:
|
|
*m_oChan << (USHORT)tag->m_param[i].m_numericVal;
|
|
break;
|
|
case TStyleParam::SP_INT:
|
|
case TStyleParam::SP_DOUBLE:
|
|
writeFloatData((double)tag->m_param[i].m_numericVal);
|
|
break;
|
|
case TStyleParam::SP_RASTER:
|
|
*m_oChan << tag->m_param[i].m_r;
|
|
break;
|
|
case TStyleParam::SP_STRING:
|
|
*m_oChan << tag->m_param[i].m_string;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeOutlineOptionsTag(StrokeOutlineOptionsTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
const double scale = 1000.0;
|
|
|
|
TINT32 miterLower = scale * tag->m_options.m_miterLower;
|
|
TINT32 miterUpper = scale * tag->m_options.m_miterUpper;
|
|
|
|
setDinamicTypeBytesNum(scale * miterLower, scale * miterUpper);
|
|
|
|
int tagLength = 2 + 2 * m_currDinamicTypeBytesNum;
|
|
int offset =
|
|
(int)writeTagHeader((UCHAR)PliTag::OUTLINE_OPTIONS_GOBJ, tagLength);
|
|
|
|
*m_oChan << (UCHAR)tag->m_options.m_capStyle;
|
|
*m_oChan << (UCHAR)tag->m_options.m_joinStyle;
|
|
writeDinamicData(miterLower);
|
|
writeDinamicData(miterUpper);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writePrecisionScaleTag(PrecisionScaleTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
setDinamicTypeBytesNum(0, tag->m_precisionScale);
|
|
|
|
int tagLength = m_currDinamicTypeBytesNum;
|
|
int offset =
|
|
(int)writeTagHeader((UCHAR)PliTag::PRECISION_SCALE_GOBJ, tagLength);
|
|
|
|
writeDinamicData((TINT32)tag->m_precisionScale);
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeGeometricTransformationTag(
|
|
GeometricTransformationTag *tag) {
|
|
assert(m_oChan);
|
|
TUINT32 offset, tagLength;
|
|
int maxval = 0, minval = 100000;
|
|
TINT32 intVal[6];
|
|
TUINT32 decVal[6];
|
|
|
|
TUINT32 objectOffset = 0;
|
|
|
|
if (tag->m_object) {
|
|
if (!(objectOffset = findOffsetFromTag(tag->m_object))) // the object was
|
|
// not already
|
|
// written before:
|
|
// write it now
|
|
{
|
|
TagElem elem(tag->m_object, 0);
|
|
writeTag(&elem);
|
|
objectOffset = elem.m_offset;
|
|
addTag(elem);
|
|
elem.m_tag = 0;
|
|
}
|
|
}
|
|
|
|
if (objectOffset < (unsigned int)minval) minval = (int)objectOffset;
|
|
if (objectOffset > (unsigned int)maxval) maxval = (int)objectOffset;
|
|
|
|
getLongValFromFloat(tag->m_affine.a11, intVal[0], decVal[0]);
|
|
if (intVal[0] < minval) minval = (int)intVal[0];
|
|
if (intVal[0] > maxval) maxval = (int)intVal[0];
|
|
if (decVal[0] > (unsigned int)maxval) maxval = (int)decVal[0];
|
|
getLongValFromFloat(tag->m_affine.a12, intVal[1], decVal[1]);
|
|
if (decVal[1] > (unsigned int)maxval) maxval = (int)decVal[1];
|
|
if (intVal[1] < minval) minval = (int)intVal[1];
|
|
if (intVal[1] > maxval) maxval = (int)intVal[1];
|
|
getLongValFromFloat(tag->m_affine.a13, intVal[2], decVal[2]);
|
|
if (decVal[2] > (unsigned int)maxval) maxval = (int)decVal[2];
|
|
if (intVal[2] < minval) minval = (int)intVal[2];
|
|
if (intVal[2] > maxval) maxval = (int)intVal[2];
|
|
getLongValFromFloat(tag->m_affine.a21, intVal[3], decVal[3]);
|
|
if (decVal[3] > (unsigned int)maxval) maxval = (int)decVal[3];
|
|
if (intVal[3] < minval) minval = (int)intVal[3];
|
|
if (intVal[3] > maxval) maxval = (int)intVal[3];
|
|
getLongValFromFloat(tag->m_affine.a22, intVal[4], decVal[4]);
|
|
if (decVal[4] > (unsigned int)maxval) maxval = (int)decVal[4];
|
|
if (intVal[4] < minval) minval = (int)intVal[4];
|
|
if (intVal[4] > maxval) maxval = (int)intVal[4];
|
|
getLongValFromFloat(tag->m_affine.a23, intVal[5], decVal[5]);
|
|
if (decVal[5] > (unsigned int)maxval) maxval = (int)decVal[5];
|
|
if (intVal[5] < minval) minval = (int)intVal[5];
|
|
if (intVal[5] > maxval) maxval = (int)intVal[5];
|
|
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
tagLength = (1 + 6 * 2) * m_currDinamicTypeBytesNum;
|
|
|
|
offset =
|
|
writeTagHeader((UCHAR)PliTag::GEOMETRIC_TRANSFORMATION_GOBJ, tagLength);
|
|
|
|
writeDinamicData(intVal[0]);
|
|
writeDinamicData(decVal[0]);
|
|
writeDinamicData(intVal[1]);
|
|
writeDinamicData(decVal[1]);
|
|
writeDinamicData(intVal[2]);
|
|
writeDinamicData(decVal[2]);
|
|
writeDinamicData(intVal[3]);
|
|
writeDinamicData(decVal[3]);
|
|
writeDinamicData(intVal[4]);
|
|
writeDinamicData(decVal[4]);
|
|
writeDinamicData(intVal[5]);
|
|
writeDinamicData(decVal[5]);
|
|
|
|
writeDinamicData(objectOffset);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeDoublePairTag(DoublePairTag *tag) {
|
|
TUINT32 offset, tagLength;
|
|
TINT32 minval = 100000, maxval = 0;
|
|
TINT32 xIntVal, yIntVal;
|
|
TUINT32 xDecVal, yDecVal;
|
|
|
|
getLongValFromFloat(tag->m_first, xIntVal, xDecVal);
|
|
getLongValFromFloat(tag->m_second, yIntVal, yDecVal);
|
|
if (xIntVal < minval) minval = (int)xIntVal;
|
|
if (xIntVal > maxval) maxval = (int)xIntVal;
|
|
if ((int)xDecVal > maxval) maxval = (int)xDecVal;
|
|
if (yIntVal < minval) minval = (int)yIntVal;
|
|
if (yIntVal > maxval) maxval = (int)yIntVal;
|
|
if ((int)yDecVal > maxval) maxval = (int)yDecVal;
|
|
|
|
setDinamicTypeBytesNum(minval, maxval);
|
|
|
|
tagLength = 4 * m_currDinamicTypeBytesNum;
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::DOUBLEPAIR_OBJ, tagLength);
|
|
|
|
writeDinamicData(xIntVal);
|
|
writeDinamicData(xDecVal);
|
|
writeDinamicData(yIntVal);
|
|
writeDinamicData(yDecVal);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
TUINT32 ParsedPliImp::writeBitmapTag(BitmapTag *tag) {
|
|
assert(m_oChan);
|
|
|
|
TUINT32 offset, tagLength;
|
|
TRaster32P r = tag->m_r;
|
|
|
|
UINT bmpSize = r->getLx() * r->getLy() * r->getPixelSize();
|
|
|
|
tagLength = 2 + 2 + bmpSize;
|
|
|
|
offset = writeTagHeader((UCHAR)PliTag::BITMAP_GOBJ, tagLength);
|
|
|
|
*m_oChan << (USHORT)r->getLx();
|
|
*m_oChan << (USHORT)r->getLy();
|
|
r->lock();
|
|
m_oChan->writeBuf(r->getRawData(), bmpSize);
|
|
r->unlock();
|
|
return offset;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
bool ParsedPliImp::writePli(const TFilePath &filename) {
|
|
MyOfstream os(filename);
|
|
if (!os || os.fail()) return false;
|
|
m_oChan = &os;
|
|
|
|
*m_oChan << c_magicNt;
|
|
// m_oChan << c_magicIrix;
|
|
|
|
*m_oChan << m_majorVersionNumber;
|
|
*m_oChan << m_minorVersionNumber;
|
|
|
|
*m_oChan << m_creator;
|
|
|
|
*m_oChan << (TUINT32)0; // fileLenght;
|
|
*m_oChan << m_framesNumber;
|
|
|
|
UCHAR s, i, d;
|
|
double absAutoClose = fabs(m_autocloseTolerance);
|
|
s = tsign(m_autocloseTolerance) + 1;
|
|
i = (UCHAR)((int)absAutoClose);
|
|
d = (UCHAR)((int)((absAutoClose - i) * 100));
|
|
*m_oChan << s;
|
|
*m_oChan << i;
|
|
*m_oChan << d;
|
|
|
|
CHECK_FOR_WRITE_ERROR(filename);
|
|
|
|
m_currDinamicTypeBytesNum = 2;
|
|
|
|
for (TagElem *elem = m_firstTag; elem; elem = elem->m_next) {
|
|
writeTag(elem);
|
|
CHECK_FOR_WRITE_ERROR(filename);
|
|
}
|
|
|
|
*m_oChan << (UCHAR)PliTag::END_CNTRL;
|
|
|
|
m_oChan->close();
|
|
m_oChan = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
|
|
ParsedPli::ParsedPli() { imp = new ParsedPliImp(); }
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPli::ParsedPli(USHORT framesNumber, UCHAR precision, UCHAR maxThickness,
|
|
double autocloseTolerance) {
|
|
imp =
|
|
new ParsedPliImp(c_majorVersionNumber, c_minorVersionNumber, framesNumber,
|
|
precision, maxThickness, autocloseTolerance);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPli::~ParsedPli() { delete imp; }
|
|
|
|
/*=====================================================================*/
|
|
|
|
bool ParsedPli::addTag(PliTag *tag, bool addFront) {
|
|
return imp->addTag(tag, addFront);
|
|
}
|
|
|
|
PliTag *ParsedPli::getFirstTag() {
|
|
imp->m_currTag = imp->m_firstTag;
|
|
return imp->m_currTag->m_tag;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
PliTag *ParsedPli::getNextTag() {
|
|
assert(imp->m_currTag);
|
|
|
|
imp->m_currTag = imp->m_currTag->m_next;
|
|
|
|
return (imp->m_currTag) ? imp->m_currTag->m_tag : NULL;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPli::setCreator(const QString &creator) {
|
|
imp->m_creator = creator.toStdString();
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
QString ParsedPli::getCreator() const {
|
|
return QString::fromStdString(imp->m_creator);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPli::ParsedPli(const TFilePath &filename, bool readInfo) {
|
|
imp = new ParsedPliImp(filename, readInfo);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPli::getVersion(UINT &majorVersionNumber,
|
|
UINT &minorVersionNumber) const {
|
|
majorVersionNumber = imp->m_majorVersionNumber;
|
|
minorVersionNumber = imp->m_minorVersionNumber;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
bool ParsedPli::writePli(const TFilePath &filename) {
|
|
return imp->writePli(filename);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
/*
|
|
Necessario per fissare un problema di lettura con le vecchie
|
|
versioni di PLI ( < 3 ).
|
|
*/
|
|
double ParsedPli::getThickRatio() const { return imp->m_thickRatio; }
|
|
|
|
/*=====================================================================*/
|
|
|
|
ParsedPliImp::~ParsedPliImp() {
|
|
TagElem *tag = m_firstTag;
|
|
while (tag) {
|
|
TagElem *auxTag = tag;
|
|
tag = tag->m_next;
|
|
delete auxTag;
|
|
}
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPli::loadInfo(bool readPalette, TPalette *&palette,
|
|
TContentHistory *&history) {
|
|
imp->loadInfo(readPalette, palette, history);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
ImageTag *ParsedPli::loadFrame(const TFrameId &frameId) {
|
|
return imp->loadFrame(frameId);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPli::setFrameCount(int frameCount) {
|
|
imp->setFrameCount(frameCount);
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
void ParsedPliImp::setFrameCount(int frameCount) {
|
|
m_framesNumber = frameCount;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
int ParsedPli::getFrameCount() const { return imp->getFrameCount(); }
|
|
|
|
/*=====================================================================*/
|
|
|
|
int ParsedPliImp::getFrameCount() { return m_framesNumber; }
|
|
|
|
/*=====================================================================*/
|
|
|
|
double ParsedPli::getAutocloseTolerance() const {
|
|
return imp->m_autocloseTolerance;
|
|
}
|
|
|
|
/*=====================================================================*/
|
|
|
|
int &ParsedPli::precisionScale() { return imp->m_precisionScale; }
|