| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| std::string buildErrorString(int error); |
| |
| void readChannel(FILE *f, TPSDLayerInfo *li, TPSDChannelInfo *chan, |
| int channels, TPSDHeaderInfo *h); |
| void readLongData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li); |
| void readByteData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li); |
| void readKey(FILE *f, struct dictentry *parent, TPSDLayerInfo *li); |
| void readLayer16(FILE *f, struct dictentry *parent, TPSDLayerInfo *li); |
| |
| |
| char swapByte(unsigned char src) { |
| unsigned char out = 0; |
| for (int i = 0; i < 8; ++i) { |
| out = out << 1; |
| out |= (src & 1); |
| src = src >> 1; |
| } |
| return out; |
| } |
| |
| TPSDReader::TPSDReader(const TFilePath &path) |
| : m_shrinkX(1), m_shrinkY(1), m_region(TRect()) { |
| m_layerId = 0; |
| QString name = path.getName().c_str(); |
| name.append(path.getDottedType().c_str()); |
| int sepPos = name.indexOf("#"); |
| int dotPos = name.indexOf(".", sepPos); |
| name.remove(sepPos, dotPos - sepPos); |
| m_path = path.getParentDir() + TFilePath(name.toStdString()); |
| |
| QMutexLocker sl(&m_mutex); |
| openFile(); |
| if (!doInfo()) { |
| fclose(m_file); |
| throw TImageException(m_path, "Do PSD INFO ERROR"); |
| } |
| fclose(m_file); |
| } |
| TPSDReader::~TPSDReader() { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| int TPSDReader::openFile() { |
| m_file = fopen(m_path, "rb"); |
| if (!m_file) throw TImageException(m_path, buildErrorString(2)); |
| return 0; |
| } |
| bool TPSDReader::doInfo() { |
| |
| if (!doHeaderInfo()) return false; |
| |
| if (!doColorModeData()) return false; |
| |
| if (!doImageResources()) return false; |
| |
| if (!doLayerAndMaskInfo()) return false; |
| |
| |
| m_headerInfo.layerDataPos = ftell(m_file); |
| |
| if (m_headerInfo.layersCount == 0) |
| { |
| fseek(m_file, m_headerInfo.layerDataPos, SEEK_SET); |
| skipBlock(m_file); |
| psdByte currentPos = ftell(m_file); |
| psdByte len = m_headerInfo.lmistart + m_headerInfo.lmilen - |
| currentPos; |
| doExtraData(NULL, len); |
| } |
| return true; |
| } |
| |
| bool TPSDReader::doHeaderInfo() { |
| fread(m_headerInfo.sig, 1, 4, m_file); |
| m_headerInfo.version = read2UBytes(m_file); |
| read4Bytes(m_file); |
| read2Bytes(m_file); |
| m_headerInfo.channels = read2UBytes(m_file); |
| m_headerInfo.rows = read4Bytes(m_file); |
| m_headerInfo.cols = read4Bytes(m_file); |
| m_headerInfo.depth = read2UBytes(m_file); |
| m_headerInfo.mode = read2UBytes(m_file); |
| |
| if (!feof(m_file) && !memcmp(m_headerInfo.sig, "8BPS", 4)) { |
| if (m_headerInfo.version == 1) { |
| if (m_headerInfo.channels <= 0 || m_headerInfo.channels > 64 || |
| m_headerInfo.rows <= 0 || m_headerInfo.cols <= 0 || |
| m_headerInfo.depth < 0 || m_headerInfo.depth > 32 || |
| m_headerInfo.mode < 0) { |
| throw TImageException(m_path, "Reading PSD Header Info error"); |
| return false; |
| } |
| } else { |
| throw TImageException(m_path, "PSD Version not supported"); |
| return false; |
| } |
| } else { |
| throw TImageException(m_path, "Cannot read Header"); |
| return false; |
| } |
| return true; |
| } |
| |
| bool TPSDReader::doColorModeData() { |
| m_headerInfo.colormodepos = ftell(m_file); |
| skipBlock(m_file); |
| return true; |
| } |
| |
| bool TPSDReader::doImageResources() { |
| |
| long len = read4Bytes(m_file); |
| while (len > 0) { |
| char type[4], name[0x100]; |
| int id, namelen; |
| long size; |
| fread(type, 1, 4, m_file); |
| id = read2Bytes(m_file); |
| namelen = fgetc(m_file); |
| fread(name, 1, NEXT2(1 + namelen) - 1, m_file); |
| name[namelen] = 0; |
| size = read4Bytes(m_file); |
| if (id == 1005) |
| { |
| psdByte savepos = ftell(m_file); |
| long hres, vres; |
| double hresd, vresd; |
| hresd = FIXDPI(hres = read4Bytes(m_file)); |
| read2Bytes(m_file); |
| read2Bytes(m_file); |
| vresd = FIXDPI(vres = read4Bytes(m_file)); |
| m_headerInfo.vres = vresd; |
| m_headerInfo.hres = hresd; |
| fseek(m_file, savepos, SEEK_SET); |
| } |
| len -= 4 + 2 + NEXT2(1 + namelen) + 4 + NEXT2(size); |
| fseek(m_file, NEXT2(size), SEEK_CUR); |
| } |
| if (len != 0) return false; |
| return true; |
| } |
| |
| bool TPSDReader::doLayerAndMaskInfo() { |
| psdByte layerlen; |
| |
| m_headerInfo.layersCount = 0; |
| m_headerInfo.lmilen = read4Bytes(m_file); |
| m_headerInfo.lmistart = ftell(m_file); |
| if (m_headerInfo.lmilen) { |
| |
| layerlen = read4Bytes(m_file); |
| m_headerInfo.linfoBlockEmpty = false; |
| m_headerInfo.mergedalpha = 0; |
| if (layerlen) { |
| doLayersInfo(); |
| } else { |
| |
| } |
| } else { |
| |
| } |
| return true; |
| } |
| |
| |
| |
| bool TPSDReader::doLayersInfo() { |
| m_headerInfo.layersCount = read2Bytes(m_file); |
| m_headerInfo.linfoBlockEmpty = false; |
| m_headerInfo.mergedalpha = m_headerInfo.layersCount < 0; |
| if (m_headerInfo.mergedalpha > 0) { |
| m_headerInfo.layersCount = -m_headerInfo.layersCount; |
| } |
| if (!m_headerInfo.linfoBlockEmpty) { |
| m_headerInfo.linfo = (TPSDLayerInfo *)mymalloc( |
| m_headerInfo.layersCount * sizeof(struct TPSDLayerInfo)); |
| int i = 0; |
| for (i = 0; i < m_headerInfo.layersCount; i++) { |
| readLayerInfo(i); |
| } |
| } |
| return true; |
| } |
| bool TPSDReader::readLayerInfo(int i) { |
| psdByte chlen, extralen, extrastart; |
| int j, chid, namelen; |
| TPSDLayerInfo *li = m_headerInfo.linfo + i; |
| |
| |
| li->top = read4Bytes(m_file); |
| li->left = read4Bytes(m_file); |
| li->bottom = read4Bytes(m_file); |
| li->right = read4Bytes(m_file); |
| li->channels = read2UBytes(m_file); |
| |
| if (li->bottom < li->top || li->right < li->left || |
| li->channels > 64) |
| { |
| |
| fseek(m_file, 6 * li->channels + 12, SEEK_CUR); |
| skipBlock(m_file); |
| } else { |
| li->chan = (TPSDChannelInfo *)mymalloc(li->channels * |
| sizeof(struct TPSDChannelInfo)); |
| li->chindex = (int *)mymalloc((li->channels + 2) * sizeof(int)); |
| li->chindex += 2; |
| |
| for (j = -2; j < li->channels; ++j) li->chindex[j] = -1; |
| |
| |
| for (j = 0; j < li->channels; ++j) { |
| chid = li->chan[j].id = read2Bytes(m_file); |
| chlen = li->chan[j].length = read4Bytes(m_file); |
| |
| if (chid >= -2 && chid < li->channels) |
| li->chindex[chid] = j; |
| else { |
| |
| } |
| } |
| |
| fread(li->blend.sig, 1, 4, m_file); |
| fread(li->blend.key, 1, 4, m_file); |
| li->blend.opacity = fgetc(m_file); |
| li->blend.clipping = fgetc(m_file); |
| li->blend.flags = fgetc(m_file); |
| fgetc(m_file); |
| |
| extralen = read4Bytes(m_file); |
| extrastart = ftell(m_file); |
| |
| |
| if ((li->mask.size = read4Bytes(m_file))) { |
| li->mask.top = read4Bytes(m_file); |
| li->mask.left = read4Bytes(m_file); |
| li->mask.bottom = read4Bytes(m_file); |
| li->mask.right = read4Bytes(m_file); |
| li->mask.default_colour = fgetc(m_file); |
| li->mask.flags = fgetc(m_file); |
| fseek(m_file, li->mask.size - 18, SEEK_CUR); |
| li->mask.rows = li->mask.bottom - li->mask.top; |
| li->mask.cols = li->mask.right - li->mask.left; |
| } else { |
| |
| } |
| |
| skipBlock(m_file); |
| |
| |
| li->nameno = (char *)malloc(16); |
| sprintf(li->nameno, "layer%d", i + 1); |
| namelen = fgetc(m_file); |
| li->name = (char *)mymalloc(NEXT4(namelen + 1)); |
| fread(li->name, 1, NEXT4(namelen + 1) - 1, m_file); |
| li->name[namelen] = 0; |
| if (namelen) { |
| if (li->name[0] == '.') li->name[0] = '_'; |
| } |
| |
| |
| |
| li->additionalpos = ftell(m_file); |
| li->additionallen = extrastart + extralen - li->additionalpos; |
| doExtraData(li, li->additionallen); |
| |
| |
| fseek(m_file, extrastart + extralen, SEEK_SET); |
| } |
| return true; |
| } |
| |
| void TPSDReader::doImage(TRasterP &rasP, int layerId) { |
| m_layerId = layerId; |
| int layerIndex = getLayerInfoIndexById(layerId); |
| TPSDLayerInfo *li = getLayerInfo(layerIndex); |
| psdByte imageDataEnd; |
| |
| psdByte startPos = ftell(m_file); |
| if (m_headerInfo.layersCount > 0) { |
| struct TPSDLayerInfo *lilast = |
| &m_headerInfo.linfo[m_headerInfo.layersCount - 1]; |
| startPos = lilast->additionalpos + lilast->additionallen; |
| } |
| if (layerIndex > 0) { |
| for (int j = 0; j < layerIndex; j++) { |
| struct TPSDLayerInfo *liprev = &m_headerInfo.linfo[j]; |
| for (int ch = 0; ch < liprev->channels; ch++) { |
| startPos += liprev->chan[ch].length; |
| } |
| } |
| } |
| fseek(m_file, startPos, SEEK_SET); |
| |
| long pixw = li ? li->right - li->left : m_headerInfo.cols; |
| long pixh = li ? li->bottom - li->top : m_headerInfo.rows; |
| int channels = li ? li->channels : m_headerInfo.channels; |
| |
| if (li == NULL) |
| fseek(m_file, m_headerInfo.lmistart + m_headerInfo.lmilen, SEEK_SET); |
| |
| psdPixel rows = pixh; |
| psdPixel cols = pixw; |
| |
| int ch = 0; |
| psdByte **rowpos; |
| |
| rowpos = (psdByte **)mymalloc(channels * sizeof(psdByte *)); |
| |
| for (ch = 0; ch < channels; ++ch) { |
| psdPixel chrows = |
| li && !m_headerInfo.linfoBlockEmpty && li->chan[ch].id == -2 |
| ? li->mask.rows |
| : rows; |
| rowpos[ch] = (psdByte *)mymalloc((chrows + 1) * sizeof(psdByte)); |
| } |
| |
| int tnzchannels = 0; |
| |
| int depth = m_headerInfo.depth; |
| switch (m_headerInfo.mode) { |
| |
| |
| case ModeBitmap: |
| case ModeGrayScale: |
| case ModeGray16: |
| case ModeDuotone: |
| case ModeDuotone16: |
| tnzchannels = 1; |
| |
| if (li ? li->chindex[-1] != -1 : channels > 1 && m_headerInfo.mergedalpha) { |
| tnzchannels = 2; |
| } |
| break; |
| case ModeIndexedColor: |
| tnzchannels = 1; |
| break; |
| case ModeRGBColor: |
| case ModeRGB48: |
| tnzchannels = 3; |
| if (li ? li->chindex[-1] != -1 : channels > 3 && m_headerInfo.mergedalpha) { |
| tnzchannels = 4; |
| } |
| break; |
| default: |
| tnzchannels = channels; |
| |
| break; |
| } |
| |
| if (!li || m_headerInfo.linfoBlockEmpty) { |
| TPSDChannelInfo *mergedChans = |
| (TPSDChannelInfo *)mymalloc(channels * sizeof(struct TPSDChannelInfo)); |
| |
| readChannel(m_file, NULL, mergedChans, channels, &m_headerInfo); |
| imageDataEnd = ftell(m_file); |
| readImageData(rasP, NULL, mergedChans, tnzchannels, rows, cols); |
| free(mergedChans); |
| } else { |
| for (ch = 0; ch < channels; ++ch) { |
| readChannel(m_file, li, li->chan + ch, 1, &m_headerInfo); |
| } |
| imageDataEnd = ftell(m_file); |
| readImageData(rasP, li, li->chan, tnzchannels, rows, cols); |
| } |
| fseek(m_file, imageDataEnd, SEEK_SET); |
| |
| for (ch = 0; ch < channels; ++ch) free(rowpos[ch]); |
| free(rowpos); |
| } |
| |
| void TPSDReader::load(TRasterImageP &img, int layerId) { |
| QMutexLocker sl(&m_mutex); |
| TPSDLayerInfo *li = NULL; |
| int layerIndex = 0; |
| if (layerId > 0) { |
| layerIndex = getLayerInfoIndexById(layerId); |
| li = getLayerInfo(layerIndex); |
| } |
| if (layerId < 0) throw TImageException(m_path, "Layer ID not exists"); |
| |
| if (m_headerInfo.mode == 4 || m_headerInfo.depth == 32) { |
| img = TRasterImageP(); |
| return; |
| } |
| |
| try { |
| TRasterP rasP; |
| openFile(); |
| doImage(rasP, layerId); |
| fclose(m_file); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if (!rasP) { |
| img = TRasterImageP(); |
| return; |
| } |
| |
| TRect layerSaveBox = m_layersSavebox[layerId]; |
| TRect savebox(layerSaveBox); |
| TDimension imgSize(rasP->getLx(), rasP->getLy()); |
| assert(TRect(imgSize).contains(savebox)); |
| |
| if (TRasterGR8P ras = rasP) { |
| TPixelGR8 bgColor; |
| ras->fillOutside(savebox, bgColor); |
| img = TRasterImageP(ras); |
| } else if (TRaster32P ras = rasP) { |
| TPixel32 bgColor(0, 0, 0, 0); |
| if (savebox != TRect()) |
| ras->fillOutside(savebox, bgColor); |
| else |
| ras->fill(bgColor); |
| img = TRasterImageP(ras); |
| } else if ((TRaster64P)rasP) { |
| TRaster32P raux(rasP->getLx(), rasP->getLy()); |
| TRop::convert(raux, rasP); |
| TPixel32 bgColor(0, 0, 0, 0); |
| raux->fillOutside(savebox, bgColor); |
| img = TRasterImageP(raux); |
| } else { |
| throw TImageException(m_path, "Invalid Raster"); |
| } |
| img->setDpi(m_headerInfo.hres, m_headerInfo.vres); |
| img->setSavebox(savebox); |
| } catch (...) { |
| } |
| } |
| |
| int TPSDReader::getLayerInfoIndexById(int layerId) { |
| int layerIndex = -1; |
| for (int i = 0; i < m_headerInfo.layersCount; i++) { |
| TPSDLayerInfo *litemp = m_headerInfo.linfo + i; |
| if (litemp->layerId == layerId) { |
| layerIndex = i; |
| break; |
| } |
| } |
| if (layerIndex < 0 && layerId != 0) |
| throw TImageException(m_path, "Layer ID not exists"); |
| return layerIndex; |
| } |
| TPSDLayerInfo *TPSDReader::getLayerInfo(int index) { |
| if (index < 0 || index >= m_headerInfo.layersCount) return NULL; |
| return m_headerInfo.linfo + index; |
| } |
| TPSDHeaderInfo TPSDReader::getPSDHeaderInfo() { return m_headerInfo; } |
| |
| void TPSDReader::readImageData(TRasterP &rasP, TPSDLayerInfo *li, |
| TPSDChannelInfo *chan, int chancount, |
| psdPixel rows, psdPixel cols) { |
| int channels = li ? li->channels : m_headerInfo.channels; |
| |
| short depth = m_headerInfo.depth; |
| |
| psdByte savepos = ftell(m_file); |
| if (rows == 0 || cols == 0) return; |
| psdPixel j; |
| |
| unsigned char *inrows[4], *rledata; |
| |
| int ch, map[4]; |
| |
| rledata = (unsigned char *)mymalloc(chan->rowbytes * 2); |
| |
| for (ch = 0; ch < chancount; ++ch) { |
| inrows[ch] = (unsigned char *)mymalloc(chan->rowbytes); |
| map[ch] = li && chancount > 1 ? li->chindex[ch] : ch; |
| } |
| |
| |
| if (li && (chancount == 2 || chancount == 4)) { |
| if (li->chindex[-1] == -1) { |
| |
| } else |
| map[chancount - 1] = li->chindex[-1]; |
| } |
| |
| |
| |
| int x0 = 0; |
| int x1 = m_headerInfo.cols - 1; |
| int y0 = 0; |
| int y1 = m_headerInfo.rows - 1; |
| |
| if (!m_region.isEmpty()) { |
| x0 = m_region.getP00().x; |
| |
| if (x0 >= m_headerInfo.cols) { |
| free(rledata); |
| return; |
| } |
| x1 = x0 + m_region.getLx() - 1; |
| |
| if (x1 >= m_headerInfo.cols) x1 = m_headerInfo.cols - 1; |
| y0 = m_region.getP00().y; |
| |
| if (y0 >= m_headerInfo.rows) { |
| free(rledata); |
| return; |
| } |
| y1 = y0 + m_region.getLy() - 1; |
| |
| if (y1 >= m_headerInfo.rows) y1 = m_headerInfo.rows - 1; |
| } |
| if (m_shrinkX > x1 - x0) m_shrinkX = x1 - x0; |
| if (m_shrinkY > y1 - y0) m_shrinkY = y1 - y0; |
| assert(m_shrinkX > 0 && m_shrinkY > 0); |
| if (m_shrinkX > 1) { |
| x1 -= (x1 - x0) % m_shrinkX; |
| } |
| if (m_shrinkY > 1) { |
| y1 -= (y1 - y0) % m_shrinkY; |
| } |
| assert(x0 <= x1 && y0 <= y1); |
| |
| TDimension imgSize((x1 - x0) / m_shrinkX + 1, (y1 - y0) / m_shrinkY + 1); |
| if (depth == 1 && chancount == 1) { |
| rasP = TRasterGR8P(imgSize); |
| } else if (depth == 8 && chancount > 1) { |
| rasP = TRaster32P(imgSize); |
| } else if (m_headerInfo.depth == 8 && chancount == 1) { |
| rasP = TRasterGR8P(imgSize); |
| } else if (m_headerInfo.depth == 16 && chancount == 1 && |
| m_headerInfo.mergedalpha) { |
| rasP = TRasterGR8P(imgSize); |
| } else if (m_headerInfo.depth == 16) { |
| rasP = TRaster64P(imgSize); |
| } |
| |
| |
| |
| long sbx0 = li ? li->left - x0 : 0; |
| long sby0 = li ? m_headerInfo.rows - li->bottom - y0 : 0; |
| long sbx1 = li ? li->right - 1 - x0 : x1 - x0; |
| long sby1 = li ? m_headerInfo.rows - li->top - 1 - y0 : y1 - y0; |
| |
| TRect layerSaveBox; |
| layerSaveBox = TRect(sbx0, sby0, sbx1, sby1); |
| |
| TRect imageRect; |
| if (!m_region.isEmpty()) |
| imageRect = TRect(0, 0, m_region.getLx() - 1, m_region.getLy() - 1); |
| else |
| imageRect = TRect(0, 0, m_headerInfo.cols - 1, m_headerInfo.rows - 1); |
| |
| |
| |
| |
| layerSaveBox *= imageRect; |
| |
| if (layerSaveBox == TRect() || layerSaveBox.isEmpty()) { |
| free(rledata); |
| return; |
| } |
| |
| |
| |
| int firstXPixIndexOfLayer = layerSaveBox.getP00().x - 1 + m_shrinkX - |
| (abs(layerSaveBox.getP00().x - 1) % m_shrinkX); |
| int lrx0 = firstXPixIndexOfLayer / m_shrinkX; |
| int firstLineIndexOfLayer = layerSaveBox.getP00().y - 1 + m_shrinkY - |
| (abs(layerSaveBox.getP00().y - 1) % m_shrinkY); |
| int lry0 = firstLineIndexOfLayer / m_shrinkY; |
| int lrx1 = |
| (layerSaveBox.getP11().x - abs(layerSaveBox.getP11().x % m_shrinkX)) / |
| m_shrinkX; |
| int lry1 = |
| (layerSaveBox.getP11().y - abs(layerSaveBox.getP11().y % m_shrinkY)) / |
| m_shrinkY; |
| TRect layerSaveBox2 = TRect(lrx0, lry0, lrx1, lry1); |
| if (layerSaveBox2.isEmpty()) return; |
| assert(TRect(imgSize).contains(layerSaveBox2)); |
| if (li) |
| m_layersSavebox[li->layerId] = layerSaveBox2; |
| else |
| m_layersSavebox[0] = layerSaveBox2; |
| TRasterP smallRas = rasP->extract(layerSaveBox2); |
| assert(smallRas); |
| if (!smallRas) return; |
| |
| |
| int colOffset = firstXPixIndexOfLayer - layerSaveBox.getP00().x; |
| assert(colOffset >= 0); |
| |
| |
| |
| |
| int rowOffset = abs(sby1) % m_shrinkY; |
| int rowCount = rowOffset; |
| |
| for (j = 0; j < smallRas->getLy(); j++) { |
| for (ch = 0; ch < chancount; ++ch) { |
| |
| if (map[ch] < 0 || map[ch] > chancount) { |
| |
| memset(inrows[ch], 0, chan->rowbytes); |
| } else |
| readrow(m_file, chan + map[ch], rowCount, inrows[ch], rledata); |
| } |
| |
| if (sby1 - rowCount < 0 || sby1 - rowCount > m_headerInfo.rows - 1) { |
| rowCount += m_shrinkY; |
| continue; |
| } |
| if (depth == 1 && chancount == 1) { |
| if (!(layerSaveBox.getP00().x - sbx0 >= 0 && |
| layerSaveBox.getP00().x - sbx0 + smallRas->getLx() / 8 - 1 < |
| chan->rowbytes)) |
| throw TImageException( |
| m_path, "Unable to read image with this depth and channels values"); |
| smallRas->lock(); |
| unsigned char *rawdata = |
| (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1); |
| TPixelGR8 *pix = (TPixelGR8 *)rawdata; |
| int colCount = colOffset; |
| for (int k = 0; k < smallRas->getLx(); k += 8) { |
| char value = ~inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]; |
| pix[k].setValue(value); |
| pix[k + 1].setValue(value); |
| pix[k + 2].setValue(value); |
| pix[k + 3].setValue(value); |
| pix[k + 4].setValue(value); |
| pix[k + 5].setValue(value); |
| pix[k + 6].setValue(value); |
| pix[k + 7].setValue(value); |
| colCount += m_shrinkX; |
| } |
| smallRas->unlock(); |
| } else if (depth == 8 && chancount > 1) { |
| if (!(layerSaveBox.getP00().x - sbx0 >= 0 && |
| layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < |
| chan->rowbytes)) |
| throw TImageException( |
| m_path, "Unable to read image with this depth and channels values"); |
| smallRas->lock(); |
| unsigned char *rawdata = |
| (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1); |
| TPixel32 *pix = (TPixel32 *)rawdata; |
| int colCount = colOffset; |
| for (int k = 0; k < smallRas->getLx(); k++) { |
| if (chancount >= 3) { |
| pix[k].r = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]; |
| pix[k].g = inrows[1][layerSaveBox.getP00().x - sbx0 + colCount]; |
| pix[k].b = inrows[2][layerSaveBox.getP00().x - sbx0 + colCount]; |
| if (chancount == 4) |
| pix[k].m = inrows[3][layerSaveBox.getP00().x - sbx0 + colCount]; |
| else |
| pix[k].m = 255; |
| } else if (chancount <= 2) |
| { |
| pix[k].r = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]; |
| pix[k].g = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]; |
| pix[k].b = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]; |
| if (chancount == 2) |
| pix[k].m = inrows[1][layerSaveBox.getP00().x - sbx0 + colCount]; |
| else |
| pix[k].m = 255; |
| } |
| colCount += m_shrinkX; |
| } |
| |
| smallRas->unlock(); |
| } else if (m_headerInfo.depth == 8 && chancount == 1) { |
| if (!(layerSaveBox.getP00().x - sbx0 >= 0 && |
| layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < |
| chan->rowbytes)) |
| throw TImageException( |
| m_path, "Unable to read image with this depth and channels values"); |
| smallRas->lock(); |
| unsigned char *rawdata = |
| (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1); |
| |
| TPixelGR8 *pix = (TPixelGR8 *)rawdata; |
| int colCount = colOffset; |
| for (int k = 0; k < smallRas->getLx(); k++) { |
| pix[k].setValue(inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]); |
| colCount += m_shrinkX; |
| } |
| smallRas->unlock(); |
| } else if (m_headerInfo.depth == 16 && chancount == 1 && |
| m_headerInfo.mergedalpha) |
| { |
| if (!(layerSaveBox.getP00().x - sbx0 >= 0 && |
| layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < |
| chan->rowbytes)) |
| throw TImageException( |
| m_path, "Unable to read image with this depth and channels values"); |
| smallRas->lock(); |
| unsigned char *rawdata = |
| (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1); |
| TPixelGR8 *pix = (TPixelGR8 *)rawdata; |
| int colCount = colOffset; |
| for (int k = 0; k < smallRas->getLx(); k++) { |
| pix[k].setValue(inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]); |
| colCount += m_shrinkX; |
| } |
| smallRas->unlock(); |
| } else if (m_headerInfo.depth == 16) { |
| if (!(layerSaveBox.getP00().x - sbx0 >= 0 && |
| layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < |
| chan->rowbytes)) |
| throw TImageException( |
| m_path, "Unable to read image with this depth and channels values"); |
| smallRas->lock(); |
| unsigned short *rawdata = |
| (unsigned short *)smallRas->getRawData(0, smallRas->getLy() - j - 1); |
| TPixel64 *pix = (TPixel64 *)rawdata; |
| int colCount = colOffset; |
| for (int k = 0; k < smallRas->getLx(); k++) { |
| if (chancount >= 3) { |
| pix[k].r = swapShort( |
| ((psdUint16 *) |
| inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| pix[k].g = swapShort( |
| ((psdUint16 *) |
| inrows[1])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| pix[k].b = swapShort( |
| ((psdUint16 *) |
| inrows[2])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| } else if (chancount <= 2) { |
| pix[k].r = swapShort( |
| ((psdUint16 *) |
| inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| pix[k].g = swapShort( |
| ((psdUint16 *) |
| inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| pix[k].b = swapShort( |
| ((psdUint16 *) |
| inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| if (chancount == 2) |
| pix[k].m = swapShort( |
| ((psdUint16 *) |
| inrows[1])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| } |
| if (chancount == 4) { |
| pix[k].m = swapShort( |
| ((psdUint16 *) |
| inrows[3])[layerSaveBox.getP00().x - sbx0 + colCount]); |
| } else |
| pix[k].m = 0xffff; |
| colCount += m_shrinkX; |
| } |
| smallRas->unlock(); |
| } else { |
| throw TImageException( |
| m_path, "Unable to read image with this depth and channels values"); |
| } |
| rowCount += m_shrinkY; |
| } |
| fseek(m_file, savepos, SEEK_SET); |
| |
| free(rledata); |
| for (ch = 0; ch < chancount; ++ch) free(inrows[ch]); |
| } |
| |
| void TPSDReader::doExtraData(TPSDLayerInfo *li, psdByte length) { |
| static struct dictentry extradict[] = { |
| |
| {0, "levl", "LEVELS", "Levels", NULL }, |
| {0, "curv", "CURVES", "Curves", NULL }, |
| {0, "brit", "BRIGHTNESSCONTRAST", "Brightness/contrast", NULL}, |
| {0, "blnc", "COLORBALANCE", "Color balance", NULL}, |
| {0, "hue ", "HUESATURATION4", "Old Hue/saturation, Photoshop 4.0", |
| NULL }, |
| {0, "hue2", "HUESATURATION5", "New Hue/saturation, Photoshop 5.0", |
| NULL }, |
| {0, "selc", "SELECTIVECOLOR", "Selective color", NULL }, |
| {0, "thrs", "THRESHOLD", "Threshold", NULL}, |
| {0, "nvrt", "INVERT", "Invert", NULL}, |
| {0, "post", "POSTERIZE", "Posterize", NULL}, |
| |
| {0, "lrFX", "EFFECT", "Effects layer", NULL }, |
| {0, "tySh", "TYPETOOL5", "Type tool (5.0)", NULL }, |
| {0, "luni", "-UNICODENAME", "Unicode layer name", |
| NULL }, |
| {0, "lyid", "-LAYERID", "Layer ID", |
| readLongData}, |
| |
| {0, "lfx2", "OBJECTEFFECT", "Object based effects layer", |
| NULL }, |
| {0, "Patt", "PATTERN", "Pattern", NULL}, |
| {0, "Pat2", "PATTERNCS", "Pattern (CS)", NULL}, |
| {0, "Anno", "ANNOTATION", "Annotation", NULL }, |
| {0, "clbl", "-BLENDCLIPPING", "Blend clipping", readByteData}, |
| {0, "infx", "-BLENDINTERIOR", "Blend interior", readByteData}, |
| {0, "knko", "-KNOCKOUT", "Knockout", readByteData}, |
| {0, "lspf", "-PROTECTED", "Protected", readLongData}, |
| {0, "lclr", "SHEETCOLOR", "Sheet color", NULL}, |
| {0, "fxrp", "-REFERENCEPOINT", "Reference point", |
| NULL }, |
| {0, "grdm", "GRADIENT", "Gradient", NULL}, |
| {0, "lsct", "-SECTION", "Section divider", readLongData}, |
| {0, "SoCo", "SOLIDCOLORSHEET", "Solid color sheet", |
| NULL }, |
| {0, "PtFl", "PATTERNFILL", "Pattern fill", |
| NULL }, |
| {0, "GdFl", "GRADIENTFILL", "Gradient fill", |
| NULL }, |
| {0, "vmsk", "VECTORMASK", "Vector mask", NULL}, |
| {0, "TySh", "TYPETOOL6", "Type tool (6.0)", |
| NULL }, |
| {0, "ffxi", "-FOREIGNEFFECTID", "Foreign effect ID", |
| readLongData}, |
| {0, "lnsr", "-LAYERNAMESOURCE", "Layer name source", |
| readKey}, |
| |
| {0, "shpa", "PATTERNDATA", "Pattern data", NULL}, |
| {0, "shmd", "METADATASETTING", "Metadata setting", |
| NULL }, |
| {0, "brst", "BLENDINGRESTRICTIONS", "Channel blending restrictions", |
| NULL}, |
| |
| {0, "lyvr", "-LAYERVERSION", "Layer version", readLongData}, |
| {0, "tsly", "-TRANSPARENCYSHAPES", "Transparency shapes layer", |
| readByteData}, |
| {0, "lmgm", "-LAYERMASKASGLOBALMASK", "Layer mask as global mask", |
| readByteData}, |
| {0, "vmgm", "-VECTORMASKASGLOBALMASK", "Vector mask as global mask", |
| readByteData}, |
| |
| {0, "mixr", "CHANNELMIXER", "Channel mixer", NULL}, |
| {0, "phfl", "PHOTOFILTER", "Photo Filter", NULL}, |
| |
| {0, "Lr16", "LAYER16", "Layer 16", readLayer16}, |
| {0, NULL, NULL, NULL, NULL}}; |
| |
| while (length >= 12) { |
| psdByte block = sigkeyblock(m_file, extradict, li); |
| if (!block) { |
| |
| break; |
| } |
| length -= block; |
| } |
| } |
| |
| struct dictentry *TPSDReader::findbykey(FILE *f, struct dictentry *parent, |
| char *key, TPSDLayerInfo *li) { |
| struct dictentry *d; |
| |
| for (d = parent; d->key; ++d) |
| if (!memcmp(key, d->key, 4)) { |
| |
| |
| if (d->func) { |
| psdByte savepos = ftell(f); |
| |
| |
| if (memcmp(key, "Lr16", 4) == 0) { |
| doLayersInfo(); |
| } else |
| d->func(f, d, li); |
| fseek(f, savepos, SEEK_SET); |
| } else { |
| |
| |
| |
| } |
| return d; |
| } |
| return NULL; |
| } |
| |
| int TPSDReader::sigkeyblock(FILE *f, struct dictentry *dict, |
| TPSDLayerInfo *li) { |
| char sig[4], key[4]; |
| long len; |
| struct dictentry *d; |
| |
| fread(sig, 1, 4, f); |
| fread(key, 1, 4, f); |
| len = read4Bytes(f); |
| if (!memcmp(sig, "8BIM", 4)) { |
| if (dict && (d = findbykey(f, dict, key, li)) && !d->func) { |
| |
| |
| } |
| fseek(f, len, SEEK_CUR); |
| return len + 12; |
| } |
| return 0; |
| } |
| |
| |
| std::string buildErrorString(int error) { |
| std::string message = ""; |
| switch (error) { |
| case 0: |
| message = "NO Error Found"; |
| break; |
| case 1: |
| message = "Reading File Error"; |
| break; |
| case 2: |
| message = "Opening File Error"; |
| break; |
| default: |
| message = "Unknown Error"; |
| } |
| return message; |
| } |
| |
| void readChannel(FILE *f, TPSDLayerInfo *li, |
| TPSDChannelInfo *chan, |
| int channels, TPSDHeaderInfo *h) { |
| int comp, ch; |
| psdByte pos, chpos, rb; |
| unsigned char *zipdata; |
| psdPixel count, last, j; |
| chpos = ftell(f); |
| |
| if (li) { |
| |
| if (chan->id == -2) { |
| chan->rows = li->mask.rows; |
| chan->cols = li->mask.cols; |
| } else { |
| |
| chan->rows = li->bottom - li->top; |
| chan->cols = li->right - li->left; |
| } |
| } else { |
| |
| chan->rows = h->rows; |
| chan->cols = h->cols; |
| } |
| |
| |
| rb = ((long)chan->cols * h->depth + 7) / 8; |
| |
| |
| comp = read2UBytes(f); |
| |
| |
| pos = chpos + 2; |
| |
| |
| if (comp == RLECOMP) pos += (channels * chan->rows) << h->version; |
| |
| for (ch = 0; ch < channels; ++ch) { |
| if (!li) chan[ch].id = ch; |
| chan[ch].rowbytes = rb; |
| chan[ch].comptype = comp; |
| chan[ch].rows = chan->rows; |
| chan[ch].cols = chan->cols; |
| chan[ch].filepos = pos; |
| |
| if (!chan->rows) continue; |
| |
| |
| |
| switch (comp) { |
| case RAWDATA: |
| pos += chan->rowbytes * chan->rows; |
| break; |
| |
| case RLECOMP: |
| |
| chan[ch].rowpos = |
| (psdByte *)mymalloc((chan[ch].rows + 1) * sizeof(psdByte)); |
| last = chan[ch].rowbytes; |
| for (j = 0; j < chan[ch].rows && !feof(f); ++j) { |
| count = h->version == 1 ? read2UBytes(f) : (unsigned long)read4Bytes(f); |
| |
| if (count > 2 * chan[ch].rowbytes) |
| count = last; |
| last = count; |
| |
| chan[ch].rowpos[j] = pos; |
| pos += count; |
| } |
| if (j < chan[ch].rows) { |
| |
| } |
| chan[ch].rowpos[j] = pos; |
| break; |
| |
| case ZIPWITHOUTPREDICTION: |
| case ZIPWITHPREDICTION: |
| if (li) { |
| pos += chan->length - 2; |
| |
| zipdata = (unsigned char *)mymalloc(chan->length); |
| count = fread(zipdata, 1, chan->length - 2, f); |
| |
| |
| |
| |
| chan->unzipdata = |
| (unsigned char *)mymalloc(chan->rows * chan->rowbytes); |
| if (comp == ZIPWITHOUTPREDICTION) |
| psdUnzipWithoutPrediction(zipdata, count, chan->unzipdata, |
| chan->rows * chan->rowbytes); |
| else |
| psdUnzipWithPrediction(zipdata, count, chan->unzipdata, |
| chan->rows * chan->rowbytes, chan->cols, |
| h->depth); |
| |
| free(zipdata); |
| } else { |
| |
| } |
| break; |
| default: { |
| |
| } |
| if (li) fseek(f, chan->length - 2, SEEK_CUR); |
| break; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| fseek(f, pos, SEEK_SET); |
| } |
| |
| void readLongData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li) { |
| unsigned long id = read4Bytes(f); |
| if (strcmp(parent->key, "lyid") == 0) |
| li->layerId = id; |
| else if (strcmp(parent->key, "lspf") == 0) |
| li->protect = id; |
| else if (strcmp(parent->key, "lsct") == 0) |
| li->section = id; |
| else if (strcmp(parent->key, "ffxi") == 0) |
| li->foreignEffectID = id; |
| else if (strcmp(parent->key, "lyvr") == 0) |
| li->layerVersion = id; |
| } |
| |
| void readByteData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li) { |
| int id = fgetc(f); |
| if (strcmp(parent->key, "clbl") == 0) |
| li->blendClipping = id; |
| else if (strcmp(parent->key, "infx") == 0) |
| li->blendInterior = id; |
| else if (strcmp(parent->key, "knko") == 0) |
| li->knockout = id; |
| else if (strcmp(parent->key, "tsly") == 0) |
| li->transparencyShapes = id; |
| else if (strcmp(parent->key, "lmgm") == 0) |
| li->layerMaskAsGlobalMask = id; |
| else if (strcmp(parent->key, "vmgm") == 0) |
| li->vectorMaskAsGlobalMask = id; |
| } |
| |
| void readKey(FILE *f, struct dictentry *parent, TPSDLayerInfo *li) { |
| static char key[5]; |
| if (fread(key, 1, 4, f) == 4) |
| key[4] = 0; |
| else |
| key[0] = 0; |
| |
| if (strcmp(parent->key, "lnsr") == 0) li->layerNameSource = key; |
| } |
| |
| void readLayer16(FILE *f, struct dictentry *parent, TPSDLayerInfo *li) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| TPSDParser::TPSDParser(const TFilePath &path) { |
| m_path = path; |
| QString name = path.getName().c_str(); |
| name.append(path.getDottedType().c_str()); |
| int sepPos = name.indexOf("#"); |
| int dotPos = name.indexOf(".", sepPos); |
| name.remove(sepPos, dotPos - sepPos); |
| TFilePath psdpath = m_path.getParentDir() + TFilePath(name.toStdString()); |
| m_psdreader = new TPSDReader(psdpath); |
| doLevels(); |
| } |
| |
| TPSDParser::~TPSDParser() { delete m_psdreader; } |
| |
| void TPSDParser::doLevels() { |
| QString path = m_path.getName().c_str(); |
| QStringList list = path.split("#"); |
| m_levels.clear(); |
| if (list.size() > 1) { |
| TPSDHeaderInfo psdheader = m_psdreader->getPSDHeaderInfo(); |
| if (list.contains("frames") && list.at(0) != "frames") { |
| int firstLayerId = 0; |
| Level level; |
| for (int i = 0; i < psdheader.layersCount; i++) { |
| TPSDLayerInfo *li = m_psdreader->getLayerInfo(i); |
| long width = li->right - li->left; |
| long height = li->bottom - li->top; |
| if (width > 0 && height > 0) { |
| assert(li->layerId >= 0); |
| if (i == 0) firstLayerId = li->layerId; |
| level.addFrame(li->layerId); |
| } |
| } |
| |
| level.setLayerId(0); |
| if (psdheader.layersCount == 0) |
| level.addFrame(firstLayerId); |
| |
| m_levels.push_back(level); |
| } else if (list.size() == 3) { |
| if (list.at(2) == "group") { |
| int folderTagOpen = 0; |
| int scavenge = 0; |
| for (int i = 0; i < psdheader.layersCount; i++) { |
| TPSDLayerInfo *li = m_psdreader->getLayerInfo(i); |
| long width = li->right - li->left; |
| long height = li->bottom - li->top; |
| if (width > 0 && height > 0 && folderTagOpen == 0) { |
| assert(li->layerId >= 0); |
| Level level(li->name, li->layerId); |
| level.addFrame(li->layerId); |
| m_levels.push_back(level); |
| scavenge = 0; |
| } else { |
| if (width != 0 && height != 0) { |
| m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)] |
| .addFrame(li->layerId); |
| } else { |
| if (strcmp(li->name, "</Layer group>") == 0 || |
| strcmp(li->name, "</Layer set>") == 0) { |
| assert(li->layerId >= 0); |
| Level level(li->name, li->layerId, true); |
| m_levels.push_back(level); |
| folderTagOpen++; |
| scavenge = folderTagOpen; |
| } else if (li->section > 0 && |
| li->section <= 3) |
| { |
| assert(li->layerId >= 0); |
| m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)] |
| .setName(li->name); |
| m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)] |
| .setLayerId(li->layerId); |
| folderTagOpen--; |
| if (folderTagOpen > 0) |
| m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)] |
| .addFrame(li->layerId, true); |
| } |
| } |
| } |
| } |
| if (psdheader.layersCount == |
| 0) |
| { |
| Level level; |
| level.setLayerId(0); |
| level.addFrame(0); |
| m_levels.push_back(level); |
| } |
| } else |
| throw TImageException(m_path, "PSD code name error"); |
| } else if (list.size() == 2) |
| { |
| TPSDHeaderInfo psdheader = m_psdreader->getPSDHeaderInfo(); |
| for (int i = 0; i < psdheader.layersCount; i++) { |
| TPSDLayerInfo *li = m_psdreader->getLayerInfo(i); |
| long width = li->right - li->left; |
| long height = li->bottom - li->top; |
| if (width > 0 && height > 0) { |
| assert(li->layerId >= 0); |
| Level level(li->name, li->layerId); |
| level.addFrame(li->layerId); |
| m_levels.push_back(level); |
| } |
| } |
| if (psdheader.layersCount == |
| 0) |
| { |
| Level level; |
| level.setLayerId(0); |
| level.addFrame(0); |
| m_levels.push_back(level); |
| } |
| } else |
| throw TImageException(m_path, "PSD code name error"); |
| } else |
| { |
| Level level; |
| level.setName(m_path.getName()); |
| level.addFrame(0); |
| m_levels.push_back(level); |
| } |
| } |
| |
| void TPSDParser::load(TRasterImageP &rasP, int layerId) { |
| m_psdreader->load(rasP, layerId); |
| } |
| |
| int TPSDParser::getLevelIndexById(int layerId) { |
| int layerIndex = -1; |
| for (int i = 0; i < (int)m_levels.size(); i++) { |
| if (m_levels[i].getLayerId() == layerId) { |
| layerIndex = i; |
| break; |
| } |
| } |
| if (layerId == 0 && layerIndex < 0) layerIndex = 0; |
| if (layerIndex < 0 && layerId != 0) |
| throw TImageException(m_path, "Layer ID not exists"); |
| return layerIndex; |
| } |
| int TPSDParser::getLevelIdByName(std::string levelName) { |
| int pos = levelName.find_last_of(LEVEL_NAME_INDEX_SEP); |
| int counter = 0; |
| if (pos != std::string::npos) { |
| counter = atoi(levelName.substr(pos + 1).c_str()); |
| levelName = levelName.substr(0, pos); |
| } |
| int lyid = -1; |
| int levelNameCount = 0; |
| for (int i = 0; i < (int)m_levels.size(); i++) { |
| if (m_levels[i].getName() == levelName) { |
| lyid = m_levels[i].getLayerId(); |
| if (counter == levelNameCount) break; |
| levelNameCount++; |
| } |
| } |
| if (lyid == 0 && lyid < 0) lyid = 0; |
| if (lyid < 0 && lyid != 0) |
| throw TImageException(m_path, "Layer ID not exists"); |
| return lyid; |
| } |
| int TPSDParser::getFramesCount(int levelId) { |
| int levelIndex = getLevelIndexById(levelId); |
| assert(levelIndex >= 0 && levelIndex < (int)m_levels.size()); |
| return m_levels[levelIndex].getFrameCount(); |
| } |
| std::string TPSDParser::getLevelName(int levelId) { |
| int levelIndex = getLevelIndexById(levelId); |
| assert(levelIndex >= 0 && levelIndex < (int)m_levels.size()); |
| return m_levels[levelIndex].getName(); |
| } |
| std::string TPSDParser::getLevelNameWithCounter(int levelId) { |
| std::string levelName = getLevelName(levelId); |
| int count = 0; |
| for (int i = 0; i < (int)m_levels.size(); i++) { |
| if (m_levels[i].getName() == levelName) { |
| if (m_levels[i].getLayerId() == levelId) { |
| break; |
| } |
| count++; |
| } |
| } |
| if (count > 0) { |
| levelName.append(LEVEL_NAME_INDEX_SEP); |
| std::string c = QString::number(count).toStdString(); |
| levelName.append(c); |
| } |
| return levelName; |
| } |
| |