/*
* algos.cpp (C) 2006-2007, Aurélien Croc (AP²C)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: page.cpp 160 2008-02-09 02:08:33Z ap2c $
*/
#include "page.h"
#include <QtCore/QByteArray>
#include <QtCore/QTextStream>
#include "algo0x11.h"
#include "qpdl.h"
#include "i18n.h"
static const char* _colorsName[] = {"cyan","magenta","yellow","black"};
/*
* Constructeur - Destructeur
* Init - Uninit
*/
Page::Page()
{
_version = 0;
_maxColors = 0;
for (unsigned int i=0; i < 4; i++) {
_layers[i].clear();
_lastBand[i] = 0;
}
_qpdl = NULL;
}
/*
* Gestion des fichiers
* Files management
*/
void Page::_closeFiles()
{
for (unsigned int i=0; i < _maxColors; i++)
_files[i].close();
}
bool Page::_openFiles(quint8 compression, const QString& extension,
QTextStream& err)
{
// Check if files are still opened
if (_files[0].isOpen())
return true;
// Open it
_maxColors = _qpdl->type() == QPDLDocument::SPLc ? 4 : 1;
for (unsigned int i=0; i < _maxColors; i++) {
_files[i].setFileName(QString("page%1-%2.%3").arg(_qpdl->page(), 3,
10, QChar('0')).arg(_colorsName[i]).arg(extension));
if (!_files[i].open(QIODevice::WriteOnly)) {
err << QString(_("Page: cannot open file %1 in write mode")).
arg(_files[i].fileName()) << endl;
_closeFiles();
return false;
}
}
return true;
}
/*
* Nettoyage
* Clear all
*/
void Page::clear()
{
_closeFiles();
_maxColors = 0;
for (unsigned int i=0; i < 4; i++) {
_layers[i].clear();
_lastBand[i] = 0;
_width[i] = 0;
_height[i] = 0;
}
}
/*
* Extraction des informations
* Extract information
*/
quint32 Page::read32(const QByteArray& data, quint32 i)
{
quint32 tmp;
if (_be)
tmp = ((quint8)data.at(i+0) << 24) + ((quint8)data.at(i+1) << 16) +
((quint8)data.at(i+2) << 8) + (quint8)data.at(i+3);
else
tmp = ((quint8)data.at(i+3) << 24) + ((quint8)data.at(i+2) << 16) +
((quint8)data.at(i+1) << 8) + (quint8)data.at(i+0);
return tmp;
}
quint16 Page::read16(const QByteArray& data, quint32 i)
{
quint16 tmp;
if (_be)
tmp = ((quint8)data.at(i+0) << 8) + (quint8)data.at(i+1);
else
tmp = ((quint8)data.at(i+1) << 8) + (quint8)data.at(i+0);
return tmp;
}
quint8 Page::read8(const QByteArray& data, quint32 i)
{
return (quint8)data.at(i+0);
}
/*
* Réception d'une bande pour traitement
* Manage band data
*/
bool Page::process(quint8 color, quint16 width, quint16 height,
quint8 compression, QByteArray& content, QTextStream& out,
QTextStream& err)
{
QString extension;
quint32 size, state;
// Check if the compression is supported
if (compression == 0)
extension = "dump";
else if (compression == 0x11)
extension = "pbm";
else if (compression == 0x13)
extension = "jbg";
else {
err << QString(_("Page: Unsupported compression algorithm (0x%1)")).
arg(compression, 0, 16) << endl;
return false;
}
// Check the sub-header version
if (_version > 3) {
err << QString(_("Page: unsupported band sub-header version (%1)")).
arg(_version) << endl;
return false;
}
// Open files if it has not be done
if (!_openFiles(compression, extension, err))
return false;
// Extract the sub-header (if version >= 2)
if (_version >= 2) {
size = read32(content, 0);
content.remove(0, 4);
if (_version == 3) {
state = read32(content, 0);
for (unsigned int i=0; i < 5; i++) {
quint32 tmp = read32(content, (i + 1) * 4);
if (tmp != 0)
err << QString(_("Page: invalid header value in sub-header "
"band (%1)")).arg(tmp) << endl;
}
content.remove(0, 6*4);
}
if (content.size() != size) {
err << QString(_("Page: content data is %1 bytes long whereas it "
"should be %2 bytes long")).arg(content.size()).arg(size) <<
endl;
return false;
}
}
if (compression == 0)
_dump(color-1, width, height, content, err);
else if (compression == 0x11)
_compression0x11(color-1, width, height, content, err);
else if (compression == 0x13)
_compression0x13(color-1, width, height, content, err);
return true;
}
void Page::flush()
{
// Save the PBM file
if (_lastBand[0] || _lastBand[1] || _lastBand[2] || _lastBand[3]) {
for (unsigned int c=0; c < _maxColors; c++) {
QString header = QString("P4\n# Page %1 - layer %2 --- (C) "
"decompress, 2006-2007 by Aurélien Croc (AP²C)\n%3 %4\n").
arg(_qpdl->page()).arg(c+1).arg(_width[c]).arg(_height[c]);
_files[c].write(header.toLatin1());
_files[c].write(_layers[c]);
}
}
_closeFiles();
}
/*
* Algorithmes de décompression
* Decompress algorithms
*/
bool Page::_dump(quint8 color, quint16 width, quint16 height, QByteArray& data,
QTextStream& err)
{
_files[color].write(data);
}
bool Page::_compression0x11(quint8 color, quint16 width, quint16 height,
QByteArray& data, QTextStream& err)
{
QByteArray band;
_width[color] = width;
_height[color] += height;
if (_lastBand[color] < _qpdl->currentBandNr()) {
QByteArray blank((width * height + 7) >> 3, 0);
while (_lastBand[color] < _qpdl->currentBandNr()) {
_layers[color].append(blank);
_lastBand[color]++;
}
}
if (!decompress0x11(data, band, width, height, this, err))
return false;
_layers[color].append(band);
_lastBand[color]++;
return true;
}
bool Page::_compression0x13(quint8 color, quint16 width, quint16 height,
QByteArray& data, QTextStream& err)
{
unsigned long size = data.length();
_files[color].write((const char *)&size, sizeof(size));
_files[color].write(data);
}
/* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin enc=utf8 : */