1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-30 22:51:16 +01:00

Do not cache the raster data

This commit is contained in:
Martin Tůma 2021-01-27 21:18:06 +01:00
parent 02c3682758
commit 33f2002a52
12 changed files with 154 additions and 114 deletions

View File

@ -12,7 +12,7 @@ public:
GMAP(const QString &fileName);
~GMAP();
QString fileName() const {return _fileName;}
const QString &fileName() const {return _fileName;}
static bool isGMAP(const QString &path);

View File

@ -1,5 +1,6 @@
#include <QMap>
#include <QtEndian>
#include <QFile>
#include "vectortile.h"
#include "img.h"
@ -24,7 +25,7 @@ static SubFile::Type tileType(const char str[3])
return SubFile::Unknown;
}
IMG::IMG(const QString &fileName) : _file(fileName)
IMG::IMG(const QString &fileName) : _fileName(fileName)
{
#define CHECK(condition) \
if (!(condition)) { \
@ -33,19 +34,20 @@ IMG::IMG(const QString &fileName) : _file(fileName)
return; \
}
QFile file(fileName);
TileMap tileMap;
QByteArray typFile;
if (!_file.open(QFile::ReadOnly)) {
_errorString = _file.errorString();
if (!file.open(QFile::ReadOnly)) {
_errorString = file.errorString();
return;
}
// Read IMG header
char signature[7], identifier[7];
_file.read((char*)&_key, 1) && _file.seek(0x10)
&& read(signature, sizeof(signature)) && _file.seek(0x41)
&& read(identifier, sizeof(identifier));
file.read((char*)&_key, 1) && file.seek(0x10)
&& read(file, signature, sizeof(signature)) && file.seek(0x41)
&& read(file, identifier, sizeof(identifier));
if (memcmp(signature, "DSKIMG", sizeof(signature))
|| memcmp(identifier, "GARMIN", sizeof(identifier))) {
_errorString = "Not a Garmin IMG file";
@ -53,9 +55,9 @@ IMG::IMG(const QString &fileName) : _file(fileName)
}
char d1[20], d2[31];
quint8 e1, e2;
CHECK(_file.seek(0x49) && read(d1, sizeof(d1)) && _file.seek(0x61)
&& readValue(e1) && readValue(e2) && _file.seek(0x65)
&& read(d2, sizeof(d2)));
CHECK(file.seek(0x49) && read(file, d1, sizeof(d1)) && file.seek(0x61)
&& readValue(file, e1) && readValue(file, e2) && file.seek(0x65)
&& read(file, d2, sizeof(d2)));
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
@ -66,7 +68,7 @@ IMG::IMG(const QString &fileName) : _file(fileName)
quint64 offset = 0x200;
// Skip unused FAT blocks if any
while (true) {
CHECK(_file.seek(offset) && readValue(flag));
CHECK(file.seek(offset) && readValue(file, flag));
if (flag)
break;
offset += 512;
@ -76,15 +78,17 @@ IMG::IMG(const QString &fileName) : _file(fileName)
char name[8], type[3];
quint32 size;
quint16 part;
CHECK(_file.seek(offset + 12) && readValue(size));
CHECK(file.seek(offset + 12) && readValue(file, size));
offset += 512;
int cnt = (size - offset) / 512;
// Read FAT blocks describing the IMG sub-files
for (int i = 0; i < cnt; i++) {
quint16 block;
CHECK(_file.seek(offset) && readValue(flag) && read(name, sizeof(name))
&& read(type, sizeof(type)) && readValue(size) && readValue(part));
CHECK(file.seek(offset) && readValue(file, flag)
&& read(file, name, sizeof(name))
&& read(file, type, sizeof(type)) && readValue(file, size)
&& readValue(file, part));
SubFile::Type tt = tileType(type);
QByteArray fn(name, sizeof(name));
@ -97,16 +101,16 @@ IMG::IMG(const QString &fileName) : _file(fileName)
} else
tile = *it;
SubFile *file = part ? tile->file(tt)
SubFile *subFile = part ? tile->file(tt)
: tile->addFile(this, tt);
CHECK(file);
CHECK(subFile);
_file.seek(offset + 0x20);
file.seek(offset + 0x20);
for (int i = 0; i < 240; i++) {
CHECK(readValue(block));
CHECK(readValue(file, block));
if (block == 0xFFFF)
break;
file->addBlock(block);
subFile->addBlock(block);
}
} else if (tt == SubFile::TYP) {
SubFile *typ = 0;
@ -118,9 +122,9 @@ IMG::IMG(const QString &fileName) : _file(fileName)
typ = _typ;
if (typ) {
_file.seek(offset + 0x20);
file.seek(offset + 0x20);
for (int i = 0; i < 240; i++) {
CHECK(readValue(block));
CHECK(readValue(file, block));
if (block == 0xFFFF)
break;
typ->addBlock(block);
@ -138,7 +142,7 @@ IMG::IMG(const QString &fileName) : _file(fileName)
VectorTile *tile = it.value();
if (!tile->init()) {
qWarning("%s: %s: Invalid map tile", qPrintable(_file.fileName()),
qWarning("%s: %s: Invalid map tile", qPrintable(file.fileName()),
qPrintable(it.key()));
delete tile;
continue;
@ -178,20 +182,20 @@ IMG::IMG(const QString &fileName) : _file(fileName)
_valid = true;
}
qint64 IMG::read(char *data, qint64 maxSize)
qint64 IMG::read(QFile &file, char *data, qint64 maxSize)
{
qint64 ret = _file.read(data, maxSize);
qint64 ret = file.read(data, maxSize);
if (_key)
for (int i = 0; i < ret; i++)
data[i] ^= _key;
return ret;
}
template<class T> bool IMG::readValue(T &val)
template<class T> bool IMG::readValue(QFile &file, T &val)
{
T data;
if (read((char*)&data, sizeof(T)) < (qint64)sizeof(T))
if (read(file, (char*)&data, sizeof(T)) < (qint64)sizeof(T))
return false;
val = qFromLittleEndian(data);
@ -199,11 +203,11 @@ template<class T> bool IMG::readValue(T &val)
return true;
}
bool IMG::readBlock(int blockNum, char *data)
bool IMG::readBlock(QFile &file, int blockNum, char *data)
{
if (!_file.seek((quint64)blockNum << _blockBits))
if (!file.seek((quint64)blockNum << _blockBits))
return false;
if (read(data, 1ULL<<_blockBits) < (qint64)(1ULL<<_blockBits))
if (read(file, data, 1ULL<<_blockBits) < (qint64)(1ULL<<_blockBits))
return false;
return true;

View File

@ -1,25 +1,26 @@
#ifndef IMG_H
#define IMG_H
#include <QFile>
#include "mapdata.h"
class QFile;
class IMG : public MapData
{
public:
IMG(const QString &fileName);
QString fileName() const {return _file.fileName();}
const QString &fileName() const {return _fileName;}
private:
friend class SubFile;
unsigned blockBits() const {return _blockBits;}
bool readBlock(int blockNum, char *data);
qint64 read(char *data, qint64 maxSize);
template<class T> bool readValue(T &val);
bool readBlock(QFile &file, int blockNum, char *data);
qint64 read(QFile &file, char *data, qint64 maxSize);
template<class T> bool readValue(QFile &file, T &val);
QFile _file;
QString _fileName;
quint8 _key;
unsigned _blockBits;
};

View File

@ -94,20 +94,23 @@ bool LBLFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
}
if (hdrLen >= 0x19A) {
quint32 size, flags;
if (!(seek(hdl, _gmpOffset + 0x184) && readUInt32(hdl, _imgOffsetsOffset)
&& readUInt32(hdl, size) && readUInt16(hdl, _imgOffsetsRecordSize)
quint32 offset, recordSize, size, flags;
if (!(seek(hdl, _gmpOffset + 0x184) && readUInt32(hdl, offset)
&& readUInt32(hdl, size) && readUInt16(hdl, recordSize)
&& readUInt32(hdl, flags) && readUInt32(hdl, _imgOffset)
&& readUInt32(hdl, _imgSize)))
return false;
_imgOffsetsCount = size ? size / _imgOffsetsRecordSize : 0;
quint32 count = size ? size / recordSize : 0;
quint32 maxId = _imgOffsetsCount - 1;
quint32 maxId = count - 1;
_imgOffsetIdSize = 0;
do {
_imgOffsetIdSize++;
maxId = maxId >> 8;
} while (maxId != 0);
if (!loadFiles(hdl, count, offset, recordSize))
return false;
}
if (_encoding == 11) {
@ -301,31 +304,43 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) con
}
}
QByteArray LBLFile::readImage(Handle &hdl, quint32 id) const
bool LBLFile::loadFiles(Handle &hdl, quint32 count, quint32 offset,
quint32 recordSize)
{
quint32 offset, nextOffset, size;
_rasters.resize(count);
if (id >= _imgOffsetsCount)
return QByteArray();
for (quint32 i = 0; i < count; i++) {
quint32 currentOffset, nextOffset, size;
if (!(seek(hdl, _imgOffsetsOffset + id * _imgOffsetsRecordSize)
&& readVUInt32(hdl, _imgOffsetsRecordSize, offset)))
return QByteArray();
if (id == _imgOffsetsCount - 1)
if (!(seek(hdl, offset + i * recordSize)
&& readVUInt32(hdl, recordSize, currentOffset)))
return false;
if (i == count - 1)
nextOffset = _imgSize;
else {
if (!readVUInt32(hdl, _imgOffsetsRecordSize, nextOffset))
return QByteArray();
if (!readVUInt32(hdl, recordSize, nextOffset))
return false;
}
size = nextOffset - offset;
size = nextOffset - currentOffset;
if (!seek(hdl, _imgOffset + offset))
return QByteArray();
QByteArray ba;
ba.resize(size);
for (quint32 i = 0; i < size; i++)
if (!readUInt8(hdl, *(ba.data() + i)))
return QByteArray();
_rasters[i] = File(currentOffset, size);
}
return ba;
return true;
}
QImage LBLFile::readImage(Handle &hdl, quint32 id) const
{
if (id >= (quint32)_rasters.size())
return QImage();
if (!seek(hdl, _imgOffset + _rasters.at(id).offset))
return QImage();
QByteArray ba;
ba.resize(_rasters.at(id).size);
for (int i = 0; i < ba.size(); i++)
if (!readUInt8(hdl, *(ba.data() + i)))
return QImage();
return QImage::fromData(ba);
}

View File

@ -1,6 +1,7 @@
#ifndef LBLFILE_H
#define LBLFILE_H
#include <QImage>
#include "common/textcodec.h"
#include "subfile.h"
#include "label.h"
@ -13,16 +14,16 @@ class LBLFile : public SubFile
public:
LBLFile(IMG *img)
: SubFile(img), _huffmanText(0), _table(0), _offset(0), _size(0),
_poiOffset(0), _poiSize(0), _imgOffsetsCount(0), _imgOffsetIdSize(0),
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
_poiOffset(0), _poiSize(0), _imgOffsetIdSize(0), _poiMultiplier(0),
_multiplier(0), _encoding(0) {}
LBLFile(const QString *path)
: SubFile(path), _huffmanText(0), _table(0), _offset(0), _size(0),
_poiOffset(0), _poiSize(0), _imgOffsetsCount(0), _imgOffsetIdSize(0),
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
_poiOffset(0), _poiSize(0), _imgOffsetIdSize(0), _poiMultiplier(0),
_multiplier(0), _encoding(0) {}
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_huffmanText(0), _table(0), _offset(0), _size(0), _poiOffset(0),
_poiSize(0), _imgOffsetsCount(0), _imgOffsetIdSize(0), _poiMultiplier(0),
_multiplier(0), _encoding(0) {}
_poiSize(0), _imgOffsetIdSize(0), _poiMultiplier(0), _multiplier(0),
_encoding(0) {}
~LBLFile();
bool load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl);
@ -32,13 +33,23 @@ public:
bool capitalize = true) const;
quint8 imageIdSize() const {return _imgOffsetIdSize;}
QByteArray readImage(Handle &hdl, quint32 id) const;
QImage readImage(Handle &hdl, quint32 id) const;
private:
struct File {
File() : offset(0), size(0) {}
File(quint32 offset, quint32 size) : offset(offset), size(size) {}
quint32 offset;
quint32 size;
};
Label str2label(const QVector<quint8> &str, bool capitalize) const;
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
Label label8b(Handle &hdl, quint32 offset, bool capitalize) const;
Label labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const;
bool loadFiles(Handle &hdl, quint32 count, quint32 offset,
quint32 recordSize);
HuffmanText *_huffmanText;
quint32 *_table;
@ -47,15 +58,14 @@ private:
quint32 _size;
quint32 _poiOffset;
quint32 _poiSize;
quint32 _imgOffsetsOffset;
quint32 _imgOffsetsCount;
quint32 _imgOffsetsRecordSize;
quint32 _imgOffset;
quint32 _imgSize;
quint8 _imgOffsetIdSize;
quint8 _poiMultiplier;
quint8 _multiplier;
quint8 _encoding;
QVector<File> _rasters;
};
#endif // LBLFILE_H

View File

@ -60,7 +60,7 @@ public:
void load();
void clear();
virtual QString fileName() const = 0;
virtual const QString &fileName() const = 0;
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}

View File

@ -2,34 +2,37 @@
#define RASTER_H
#include <QRect>
#include <QByteArray>
#include <QDebug>
#include "common/rectc.h"
#include "common/garmin.h"
class LBLFile;
class Raster {
public:
Raster() {}
Raster(const QByteArray &img, const QRect &rect) : _img(img), _rect(rect) {}
Raster() : _lbl(0) {}
Raster(const LBLFile *lbl, quint32 id, const QRect &rect)
: _lbl(lbl), _id(id), _rect(rect) {}
const QByteArray &img() const {return _img;}
const LBLFile *lbl() const {return _lbl;}
quint32 id() const {return _id;}
const RectC rect() const
{
return RectC(Coordinates(toWGS32(_rect.left()), toWGS32(_rect.top())),
Coordinates(toWGS32(_rect.right()), toWGS32(_rect.bottom())));
}
bool isValid() const {return !_img.isNull();}
bool isValid() const {return (_lbl != 0);}
private:
QByteArray _img;
const LBLFile *_lbl;
quint32 _id;
QRect _rect;
};
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const Raster &raster)
{
dbg.nospace() << "Raster(" << raster.img().size() << ", " << raster.rect()
<< ")";
dbg.nospace() << "Raster(" << raster.rect() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -5,6 +5,7 @@
#include "textpointitem.h"
#include "bitmapline.h"
#include "style.h"
#include "lblfile.h"
#include "rastertile.h"
@ -224,8 +225,11 @@ void RasterTile::drawPolygons(QPainter *painter)
QPointF br(_map->ll2xy(r.bottomRight()));
QSize size(QRectF(tl, br).toRect().size());
painter->drawImage(tl, QImage::fromData(poly.raster.img()).
scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
SubFile::Handle hdl(poly.raster.lbl());
QImage img(poly.raster.lbl()->readImage(hdl, poly.raster.id()));
painter->drawImage(tl, img.scaled(size, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
//painter->setPen(Qt::blue);
//painter->setBrush(Qt::NoBrush);

View File

@ -30,7 +30,7 @@ RGNFile::~RGNFile()
}
bool RGNFile::readClassFields(Handle &hdl, SegmentType segmentType,
MapData::Poly *poly, const LBLFile *lbl, Handle *lblHdl) const
MapData::Poly *poly, const LBLFile *lbl) const
{
quint8 flags;
quint32 rs;
@ -67,8 +67,8 @@ bool RGNFile::readClassFields(Handle &hdl, SegmentType segmentType,
&& readUInt32(hdl, bottom) && readUInt32(hdl, left)))
return false;
poly->raster = Raster(lbl->readImage(*lblHdl, id),
QRect(QPoint(left, top), QPoint(right, bottom)));
poly->raster = Raster(lbl, id, QRect(QPoint(left, top), QPoint(right,
bottom)));
rs -= lbl->imageIdSize() + 16;
}
@ -336,8 +336,7 @@ bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
if (subtype & 0x20 && !readUInt24(hdl, labelPtr))
return false;
if (subtype & 0x80 && !readClassFields(hdl, segmentType, &poly, lbl,
&lblHdl))
if (subtype & 0x80 && !readClassFields(hdl, segmentType, &poly, lbl))
return false;
if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line
? _linesLclFlags : _polygonsLclFlags))

View File

@ -61,7 +61,7 @@ private:
QMap<SegmentType, SubDiv::Segment> segments(Handle &hdl, SubDiv *subdiv)
const;
bool readClassFields(Handle &hdl, SegmentType segmentType,
MapData::Poly *poly = 0, const LBLFile *lbl = 0, Handle *lblHdl = 0) const;
MapData::Poly *poly = 0, const LBLFile *lbl = 0) const;
bool skipLclFields(Handle &hdl, const quint32 flags[3]) const;
bool skipGblFields(Handle &hdl, quint32 flags) const;

View File

@ -7,38 +7,37 @@
bool SubFile::seek(Handle &handle, quint32 pos) const
{
if (handle._file) {
int blockNum = pos >> BLOCK_BITS;
if (handle._blockNum != blockNum) {
if (!handle._file->seek((quint64)blockNum << BLOCK_BITS))
return false;
if (handle._file->read(handle._data.data(), (1<<BLOCK_BITS)) < 0)
return false;
handle._blockNum = blockNum;
}
handle._blockPos = mod2n(pos, 1U<<BLOCK_BITS);
handle._pos = pos;
return true;
} else {
if (_img) {
quint32 blockBits = _img->blockBits();
int blockNum = pos >> blockBits;
if (handle._blockNum != blockNum) {
if (blockNum >= _blocks->size())
return false;
if (!_img->readBlock(_blocks->at(blockNum), handle._data.data()))
if (!_img->readBlock(handle._file, _blocks->at(blockNum),
handle._data.data()))
return false;
handle._blockNum = blockNum;
}
handle._blockPos = mod2n(pos, 1U<<blockBits);
handle._pos = pos;
} else {
int blockNum = pos >> BLOCK_BITS;
if (handle._blockNum != blockNum) {
if (!handle._file.seek((quint64)blockNum << BLOCK_BITS))
return false;
if (handle._file.read(handle._data.data(), (1<<BLOCK_BITS)) < 0)
return false;
handle._blockNum = blockNum;
}
handle._blockPos = mod2n(pos, 1U<<BLOCK_BITS);
handle._pos = pos;
}
return true;
}
}
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const

View File

@ -17,21 +17,26 @@ public:
{
public:
Handle(const SubFile *subFile)
: _file(0), _blockNum(-1), _blockPos(-1), _pos(-1)
: _blockNum(-1), _blockPos(-1), _pos(-1)
{
if (subFile && subFile->_path) {
_file = new QFile(*(subFile->_path));
_file->open(QIODevice::ReadOnly);
if (!subFile)
return;
if (subFile->_path) {
_file.setFileName(*(subFile->_path));
_data.resize(1U<<BLOCK_BITS);
} else if (subFile)
} else {
_file.setFileName(subFile->_img->fileName());
_data.resize(1U<<subFile->_img->blockBits());
}
~Handle() {delete _file;}
_file.open(QIODevice::ReadOnly);
}
private:
friend class SubFile;
QFile *_file;
QFile _file;
QByteArray _data;
int _blockNum;
int _blockPos;