/*************************************************************************** * Copyright (C) 2012 Stefan Bühler * * * * 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 "nonogrammarker.h" #include 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(0, 0), m_data(0), m_blackPixels(0) { load(image); } 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); } void NonogramImage::load(const QImage & image) { delete [] m_data; m_data = 0; m_blackPixels = 0; m_size = image.size(); int rows = m_size.height(), cols = m_size.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; } } } void NonogramImage::load(const NonogramMarker & marker) { delete [] m_data; m_data = 0; m_blackPixels = 0; m_size = marker.size(); int n = m_size.height() * m_size.width(); m_data = new bool[n]; for (int i = 0; i < n; ++i) { m_data[i] = (NonogramMarker::MARKED == marker.m_data[i]); if (m_data[i]) ++m_blackPixels; } } QDataStream & operator<<(QDataStream & stream, const NonogramImage & image) { image.writeToStream(stream); return stream; } QDataStream & operator>>(QDataStream & stream, NonogramImage & image) { image.readFromStream(stream); return stream; } }