#include #ifndef XPRESS #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 #include "../compatibility/tfile_io.h" #include "tenv.h" /*=====================================================================*/ #if defined(MACOSX) #include #elif defined(_WIN32) #include #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 : 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; } } /*=====================================================================*/ #ifdef _WIN32 #define CHECK_FOR_READ_ERROR(filePath) #else #define CHECK_FOR_READ_ERROR(filePath) \ { \ /*if (m_iChan.flags()&(ios::failbit|ios::eofbit)) \ { \ m_lastError = PREMATURE_EOF; \ throw TImageException( filePath, "Error on reading file"); \ }*/ \ } #endif #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 m_buf; TAffine m_affine; int m_precisionScale; std::map 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; }; /*=====================================================================*/ 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); } /*=====================================================================*/ 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<> 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::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> 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; CASE PliTag::SET_DATA_16_CNTRL : m_currDinamicTypeBytesNum = 2; CASE PliTag::SET_DATA_32_CNTRL : m_currDinamicTypeBytesNum = 4; DEFAULT:; } } 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; CASE 0x1 : UCHAR clength; m_iChan >> clength; m_tagLength = clength; CASE 0x2 : USHORT slength; m_iChan >> slength; m_tagLength = slength; CASE 0x3 : m_iChan >> m_tagLength; DEFAULT: assert(false); } 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::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; CASE 0x1 : UCHAR clength; m_iChan >> clength; m_tagLength = clength; CASE 0x2 : USHORT slength; m_iChan >> slength; m_tagLength = slength; CASE 0x3 : m_iChan >> m_tagLength; 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; CASE PliTag::SET_DATA_16_CNTRL : m_currDinamicTypeBytesNum = 2; CASE PliTag::SET_DATA_32_CNTRL : m_currDinamicTypeBytesNum = 4; CASE PliTag::TEXT : newTag = readTextTag(); CASE PliTag::PALETTE : newTag = readPaletteTag(); CASE PliTag::PALETTE_WITH_ALPHA : newTag = readPaletteWithAlphaTag(); CASE PliTag::THICK_QUADRATIC_CHAIN_GOBJ : __OR PliTag::THICK_QUADRATIC_LOOP_GOBJ : newTag = readThickQuadraticChainTag(tagType == PliTag::THICK_QUADRATIC_LOOP_GOBJ); CASE PliTag::GROUP_GOBJ : newTag = readGroupTag(); CASE PliTag::IMAGE_GOBJ : newTag = readImageTag(); CASE PliTag::COLOR_NGOBJ : newTag = readColorTag(); CASE PliTag::STYLE_NGOBJ : newTag = readStyleTag(); CASE PliTag::GEOMETRIC_TRANSFORMATION_GOBJ : newTag = readGeometricTransformationTag(); CASE PliTag::DOUBLEPAIR_OBJ : newTag = readDoublePairTag(); CASE PliTag::BITMAP_GOBJ : newTag = readBitmapTag(); CASE PliTag::INTERSECTION_DATA_GOBJ : newTag = readIntersectionDataTag(); CASE PliTag::OUTLINE_OPTIONS_GOBJ : newTag = readOutlineOptionsTag(); CASE PliTag::PRECISION_SCALE_GOBJ : newTag = readPrecisionScaleTag(); CASE PliTag::END_CNTRL : return 0; DEFAULT:; } 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++]; 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; 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; 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++; 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; 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; 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 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 object(new PliObjectTag *[numObjects]); std::unique_ptr 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 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 colorArray(new TUINT32[numColors]); for (unsigned int i = 0; i < numColors; i++) { TUINT32 color; readDinamicData(color, bufOffs); colorArray[i] = color; } std::unique_ptr tag(new ColorTag(style, attribute, numColors, std::move(colorArray))); return tag.release(); } /*=====================================================================*/ PliTag *ParsedPliImp::readStyleTag() { std::vector 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--; CASE TStyleParam::SP_USHORT : USHORT val; readUShortData(val, bufOffs); param.m_numericVal = val; lenght -= 2; CASE TStyleParam::SP_INT : __OR TStyleParam::SP_DOUBLE : readFloatData(param.m_numericVal, bufOffs); lenght -= 4; CASE TStyleParam::SP_RASTER : lenght -= readRasterData(param.m_r, bufOffs); 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); 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 object(new PliObjectTag*[numObjects]); std::unique_ptr 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 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 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); CASE PliTag::PALETTE : elem->m_offset = writePaletteTag((PaletteTag *)elem->m_tag); CASE PliTag::PALETTE_WITH_ALPHA : elem->m_offset = writePaletteWithAlphaTag((PaletteWithAlphaTag *)elem->m_tag); CASE PliTag::THICK_QUADRATIC_CHAIN_GOBJ : elem->m_offset = writeThickQuadraticChainTag((ThickQuadraticChainTag *)elem->m_tag); CASE PliTag::GROUP_GOBJ : elem->m_offset = writeGroupTag((GroupTag *)elem->m_tag); CASE PliTag::IMAGE_GOBJ : elem->m_offset = writeImageTag((ImageTag *)elem->m_tag); CASE PliTag::COLOR_NGOBJ : elem->m_offset = writeColorTag((ColorTag *)elem->m_tag); CASE PliTag::STYLE_NGOBJ : elem->m_offset = writeStyleTag((StyleTag *)elem->m_tag); CASE PliTag::GEOMETRIC_TRANSFORMATION_GOBJ : elem->m_offset = writeGeometricTransformationTag((GeometricTransformationTag *)elem->m_tag); CASE PliTag::DOUBLEPAIR_OBJ : elem->m_offset = writeDoublePairTag((DoublePairTag *)elem->m_tag); CASE PliTag::BITMAP_GOBJ : elem->m_offset = writeBitmapTag((BitmapTag *)elem->m_tag); CASE PliTag::INTERSECTION_DATA_GOBJ : elem->m_offset = writeIntersectionDataTag((IntersectionDataTag *)elem->m_tag); CASE PliTag::OUTLINE_OPTIONS_GOBJ : elem->m_offset = writeOutlineOptionsTag((StrokeOutlineOptionsTag *)elem->m_tag); CASE PliTag::PRECISION_SCALE_GOBJ : elem->m_offset = writePrecisionScaleTag((PrecisionScaleTag *)elem->m_tag); 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; CASE 2 : *m_oChan << (USHORT)val; CASE 4 : *m_oChan << (TUINT32)val; 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); CASE 2 : *m_oChan << complement1((short)val, isNegative); CASE 4 : *m_oChan << complement1(val, isNegative); 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::max)(), minval = (std::numeric_limits::max)(); TPointD p; double scale; int i; assert(m_majorVersionNumber > 5 || (m_majorVersionNumber == 5 && m_minorVersionNumber >= 5)); scale = m_precisionScale; /*for ( i=0; im_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 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; CASE TStyleParam::SP_USHORT : *m_oChan << (USHORT)tag->m_param[i].m_numericVal; CASE TStyleParam::SP_INT : __OR TStyleParam::SP_DOUBLE : writeFloatData((double)tag->m_param[i].m_numericVal); CASE TStyleParam::SP_RASTER : *m_oChan << tag->m_param[i].m_r; CASE TStyleParam::SP_STRING : *m_oChan << tag->m_param[i].m_string; DEFAULT: assert(false); } } 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; } #endif