qcross/libqnono/nonogramimage.cpp

209 lines
6.5 KiB
C++

/***************************************************************************
* Copyright (C) 2012 Stefan Bühler <stbuehler@web.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "nonogramimage.h"
#include <QDataStream>
namespace libqnono {
static const quint64 NonogramImage_DataStream_MAGIC = Q_UINT64_C(0xe47028650d925b33);
class NonogramImageViewRowColumn : public NonogramImageView {
public:
NonogramImageViewRowColumn(NonogramImage & img) : m_img(img) { }
virtual bool pixel(int row, int col) const {
return m_img.pixel(col, row);
}
virtual bool & pixel(int row, int col) {
return m_img.pixel(col, row);
}
private:
NonogramImage &m_img;
};
class NonogramImageViewColumnRow : public NonogramImageView {
public:
NonogramImageViewColumnRow(NonogramImage & img) : m_img(img) { }
virtual bool pixel(int col, int row) const {
return m_img.pixel(col, row);
}
virtual bool & pixel(int col, int row) {
return m_img.pixel(col, row);
}
private:
NonogramImage &m_img;
};
NonogramImage::NonogramImage() : m_size(0,0), m_data(0), m_blackPixels(0) {
}
NonogramImage::NonogramImage(QSize size)
: m_size(size), m_blackPixels(0) {
int n = m_size.width() * m_size.height();
m_data = new bool[n];
for (int i = 0; i < n; ++i) m_data[i] = 0;
}
NonogramImage::NonogramImage(const NonogramImage& other)
: m_size(other.size()), m_data(0), m_blackPixels(other.m_blackPixels) {
int n = m_size.width() * m_size.height();
m_data = new bool[n];
for (int i = 0; i < n; ++i) m_data[i] = other.m_data[i];
}
NonogramImage::NonogramImage(const QImage & image)
: m_size(image.size()), m_data(0), m_blackPixels(0) {
int rows = image.height(), cols = image.width();
m_data = new bool[rows*cols];
for (int i = 0, y = 0; y < rows; ++y) {
for (int x = 0; x < cols; ++x, ++i) {
m_data[i] = (0 == (image.pixel(x, y) & 0x00FFFFFF));
if (m_data[i]) ++m_blackPixels;
}
}
}
NonogramImage::~NonogramImage() {
delete [] m_data; m_data = 0;
}
NonogramImage& NonogramImage::operator=(const NonogramImage& other) {
delete [] m_data; m_data = 0;
m_size = other.m_size;
m_blackPixels = other.m_blackPixels;
int n = m_size.width() * m_size.height();
m_data = new bool[n];
for (int i = 0; i < n; ++i) m_data[i] = other.m_data[i];
return *this;
}
bool NonogramImage::operator==(const NonogramImage& other) const {
if (m_size != other.m_size || m_blackPixels != other.m_blackPixels) return false;
int n = m_size.width() * m_size.height();
for (int i = 0; i < n; ++i) if (m_data[i] != other.m_data[i]) return false;
return true;
}
void NonogramImage::fill(bool value) {
int n = m_size.width() * m_size.height();
for (int i = 0; i < n; ++i) m_data[i] = value;
m_blackPixels = value ? n : 0;
}
void NonogramImage::resize(QSize size) {
int n = size.width() * size.height();
bool *data = new bool[n];
int oldwidth = m_size.width(), newwidth = size.width(), w = qMin(oldwidth, newwidth), h = qMin(size.height(), m_size.height());
int y, x;
m_blackPixels = 0;
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
data[y*newwidth+x] = m_data[y*oldwidth+x];
if (data[y*newwidth+x]) ++m_blackPixels;
}
for (; x < newwidth; ++x) {
data[y*newwidth+x] = 0;
}
}
for (int i = y*newwidth; i < n; ++i) {
data[i] = 0;
}
delete [] m_data;
m_data = data;
m_size = size;
}
NonogramImageView* NonogramImage::viewRowColumn() {
return new NonogramImageViewRowColumn(*this);
}
NonogramImageView* NonogramImage::viewColumnRow() {
return new NonogramImageViewColumnRow(*this);
}
bool NonogramImage::readFromStream(QDataStream & stream) {
quint64 magic;
stream >> magic;
if (NonogramImage_DataStream_MAGIC != magic || QDataStream::Ok != stream.status()) {
if (QDataStream::ReadPastEnd != stream.status()) stream.setStatus(QDataStream::ReadCorruptData);
return false;
}
QSize size;
stream >> size;
if (QDataStream::Ok != stream.status()) return false;
int n = size.width() * size.height();
int bitcount = (n+7)/8;
char *bits = new char[bitcount];
if (bitcount != stream.readRawData(bits, bitcount) || QDataStream::Ok != stream.status()) {
delete[] bits;
if (QDataStream::ReadCorruptData != stream.status()) stream.setStatus(QDataStream::ReadPastEnd);
return false;
}
int blackPixels = 0;
delete[] m_data;
m_data = new bool[n];
for (int i = 0, k = 0; k < bitcount; ++k) {
unsigned char byte = bits[k];
for (int l = 0 ; l < 8 && i < n; ++l, ++i, byte >>= 1) {
m_data[i] = (byte & 0x1);
if (m_data[i]) ++blackPixels;
}
}
delete[] bits;
m_size = size;
m_blackPixels = blackPixels;
return true;
}
void NonogramImage::writeToStream(QDataStream & stream) const {
stream << NonogramImage_DataStream_MAGIC << m_size;
int n = m_size.width() * m_size.height();
int bitcount = (n+7)/8;
char *bits = new char[bitcount];
for (int i = 0, k = 0; k < bitcount; ++k) {
unsigned char byte = 0, mask = 1;
for (int l = 0 ; l < 8 && i < n; ++l, ++i, mask <<= 1) {
if (m_data[i]) byte |= mask;
}
bits[k] = byte;
}
stream.writeRawData(bits, bitcount);
}
QDataStream & operator<<(QDataStream & stream, const NonogramImage & image) {
image.writeToStream(stream);
return stream;
}
QDataStream & operator>>(QDataStream & stream, NonogramImage & image) {
image.readFromStream(stream);
return stream;
}
}