Marble

TileCreator.cpp
1 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <[email protected]>
2 // SPDX-FileCopyrightText: 2007-2008 Inge Wallin <[email protected]>
3 // SPDX-FileCopyrightText: 2011 Niko Sams <[email protected]>
4 //
5 // SPDX-License-Identifier: LGPL-2.1-or-later
6 
7 #include "TileCreator.h"
8 
9 #include <cmath>
10 
11 #include <QDir>
12 #include <QRect>
13 #include <QSize>
14 #include <QVector>
15 #include <QApplication>
16 #include <QImage>
17 #include <QPainter>
18 
19 #include "MarbleGlobal.h"
20 #include "MarbleDirs.h"
21 #include "MarbleDebug.h"
22 #include "TileLoaderHelper.h"
23 
24 namespace Marble
25 {
26 
27 class TileCreatorPrivate
28 {
29  public:
30  TileCreatorPrivate( TileCreatorSource *source,
31  const QString& dem, const QString& targetDir=QString() )
32  : m_dem( dem ),
33  m_targetDir( targetDir ),
34  m_cancelled( false ),
35  m_tileFormat( "jpg" ),
36  m_resume( false ),
37  m_verify( false ),
38  m_source( source )
39  {
40  if (m_dem == QLatin1String("true")) {
41  m_tileQuality = 70;
42  } else {
43  m_tileQuality = 85;
44  }
45  }
46 
47  ~TileCreatorPrivate()
48  {
49  delete m_source;
50  }
51 
52  public:
53  QString m_dem;
54  QString m_targetDir;
55  bool m_cancelled;
56  QString m_tileFormat;
57  int m_tileQuality;
58  bool m_resume;
59  bool m_verify;
60 
61  TileCreatorSource *m_source;
62 };
63 
64 class TileCreatorSourceImage : public TileCreatorSource
65 {
66 public:
67  explicit TileCreatorSourceImage( const QString &sourcePath )
68  : m_sourceImage( QImage( sourcePath ) ),
69  m_cachedRowNum( -1 )
70  {
71  }
72 
73  QSize fullImageSize() const override
74  {
75  if ( m_sourceImage.size().width() > 21600 || m_sourceImage.height() > 10800 ) {
76  qDebug("Install map too large!");
77  return QSize();
78  }
79  return m_sourceImage.size();
80  }
81 
82  QImage tile(int n, int m, int maxTileLevel) override
83  {
84  int mmax = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, maxTileLevel );
85  int nmax = TileLoaderHelper::levelToRow( defaultLevelZeroRows, maxTileLevel );
86 
87  int imageHeight = m_sourceImage.height();
88  int imageWidth = m_sourceImage.width();
89 
90  // If the image size of the image source does not match the expected
91  // geometry we need to smooth-scale the image in advance to match
92  // the required size
93  bool needsScaling = ( imageWidth != 2 * nmax * (int)( c_defaultTileSize )
94  || imageHeight != nmax * (int)( c_defaultTileSize ) );
95 
96  if ( needsScaling )
97  mDebug() << "Image Size doesn't match 2*n*TILEWIDTH x n*TILEHEIGHT geometry. Scaling ...";
98 
99  int stdImageWidth = 2 * nmax * c_defaultTileSize;
100  if ( stdImageWidth == 0 )
101  stdImageWidth = 2 * c_defaultTileSize;
102 
103  int stdImageHeight = nmax * c_defaultTileSize;
104  if ( stdImageWidth != imageWidth ) {
105  mDebug() <<
106  QString( "TileCreator::createTiles() The size of the final image will measure %1 x %2 pixels").arg(stdImageWidth).arg(stdImageHeight);
107  }
108 
109  QImage row;
110 
111  if ( m_cachedRowNum == n ) {
112 
113  row = m_rowCache;
114 
115  } else {
116 
117  QRect sourceRowRect( 0, (int)( (qreal)( n * imageHeight ) / (qreal)( nmax )),
118  imageWidth,(int)( (qreal)( imageHeight ) / (qreal)( nmax ) ) );
119 
120 
121  row = m_sourceImage.copy( sourceRowRect );
122 
123  if ( needsScaling ) {
124  // Pick the current row and smooth scale it
125  // to make it match the expected size
126  QSize destSize( stdImageWidth, c_defaultTileSize );
127  row = row.scaled( destSize,
130  }
131 
132  m_cachedRowNum = n;
133  m_rowCache = row;
134  }
135 
136  if ( row.isNull() ) {
137  mDebug() << "Read-Error! Null QImage!";
138  return QImage();
139  }
140 
141  QImage tile = row.copy( m * stdImageWidth / mmax, 0, c_defaultTileSize, c_defaultTileSize );
142 
143  return tile;
144  }
145 
146 private:
147  QImage m_sourceImage;
148 
149  QImage m_rowCache;
150  int m_cachedRowNum;
151 };
152 
153 
154 TileCreator::TileCreator(const QString& sourceDir, const QString& installMap,
155  const QString& dem, const QString& targetDir)
156  : QThread(nullptr),
157  d( new TileCreatorPrivate( nullptr, dem, targetDir ) )
158 
159 {
160  mDebug() << "Prefix: " << sourceDir
161  << "installmap:" << installMap;
162 
163  QString sourcePath;
164 
165  // If the sourceDir starts with a '/' assume an absolute path.
166  // Otherwise assume a relative marble data path
167  if ( QDir::isAbsolutePath( sourceDir ) ) {
168  sourcePath = sourceDir + QLatin1Char('/') + installMap;
169  mDebug() << "Trying absolute path*:" << sourcePath;
170  }
171  else {
172  sourcePath = MarbleDirs::path(QLatin1String("maps/") + sourceDir + QLatin1Char('/') + installMap);
173  mDebug() << "Trying relative path*:"
174  << QLatin1String("maps/") + sourceDir + QLatin1Char('/') + installMap;
175  }
176 
177  mDebug() << "Creating tiles from*: " << sourcePath;
178 
179  d->m_source = new TileCreatorSourceImage( sourcePath );
180 
181  if ( d->m_targetDir.isNull() )
182  d->m_targetDir = MarbleDirs::localPath() + QLatin1String("/maps/")
183  + sourcePath.section(QLatin1Char('/'), -3, -2) + QLatin1Char('/');
184 
185  setTerminationEnabled( true );
186 }
187 
188 TileCreator::TileCreator( TileCreatorSource* source, const QString& dem, const QString& targetDir )
189  : QThread(nullptr),
190  d( new TileCreatorPrivate( source, dem, targetDir ) )
191 {
192  setTerminationEnabled( true );
193 }
194 
195 TileCreator::~TileCreator()
196 {
197  delete d;
198 }
199 
200 void TileCreator::cancelTileCreation()
201 {
202  d->m_cancelled = true;
203 }
204 
205 void TileCreator::run()
206 {
207  if (d->m_resume && d->m_tileFormat == QLatin1String("jpg") && d->m_tileQuality != 100) {
208  qWarning() << "Resuming jpegs is only supported with tileQuality 100";
209  return;
210  }
211 
212  if (!d->m_targetDir.endsWith(QLatin1Char('/')))
213  d->m_targetDir += QLatin1Char('/');
214 
215  mDebug() << "Installing tiles to: " << d->m_targetDir;
216 
217  QVector<QRgb> grayScalePalette;
218  for ( int cnt = 0; cnt <= 255; ++cnt ) {
219  grayScalePalette.insert(cnt, qRgb(cnt, cnt, cnt));
220  }
221 
222  QSize fullImageSize = d->m_source->fullImageSize();
223  int imageWidth = fullImageSize.width();
224  int imageHeight = fullImageSize.height();
225 
226  mDebug() << QString( "TileCreator::createTiles() image dimensions %1 x %2").arg(imageWidth).arg(imageHeight);
227 
228  if ( imageWidth < 1 || imageHeight < 1 ) {
229  qDebug("Invalid imagemap!");
230  return;
231  }
232 
233  // Calculating Maximum Tile Level
234  float approxMaxTileLevel = std::log( imageWidth / ( 2.0 * c_defaultTileSize ) ) / std::log( 2.0 );
235 
236  int maxTileLevel = 0;
237  if ( approxMaxTileLevel == int( approxMaxTileLevel ) )
238  maxTileLevel = static_cast<int>( approxMaxTileLevel );
239  else
240  maxTileLevel = static_cast<int>( approxMaxTileLevel + 1 );
241 
242  if ( maxTileLevel < 0 ) {
243  mDebug()
244  << QString( "TileCreator::createTiles(): Invalid Maximum Tile Level: %1" )
245  .arg( maxTileLevel );
246  }
247  mDebug() << "Maximum Tile Level: " << maxTileLevel;
248 
249 
250  if ( !QDir( d->m_targetDir ).exists() )
251  ( QDir::root() ).mkpath( d->m_targetDir );
252 
253  // Counting total amount of tiles to be generated for the progressbar
254  // to prevent compiler warnings this var should
255  // match the type of maxTileLevel
256  int tileLevel = 0;
257  int totalTileCount = 0;
258 
259  while ( tileLevel <= maxTileLevel ) {
260  totalTileCount += ( TileLoaderHelper::levelToRow( defaultLevelZeroRows, tileLevel )
261  * TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, tileLevel ) );
262  tileLevel++;
263  }
264 
265  mDebug() << totalTileCount << " tiles to be created in total.";
266 
267  int mmax = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, maxTileLevel );
268  int nmax = TileLoaderHelper::levelToRow( defaultLevelZeroRows, maxTileLevel );
269 
270  // Loading each row at highest spatial resolution and cropping tiles
271  int percentCompleted = 0;
272  int createdTilesCount = 0;
273  QString tileName;
274 
275  // Creating directory structure for the highest level
276  QString dirName( d->m_targetDir
277  + QString("%1").arg(maxTileLevel) );
278  if ( !QDir( dirName ).exists() )
279  ( QDir::root() ).mkpath( dirName );
280 
281  for ( int n = 0; n < nmax; ++n ) {
282  QString dirName( d->m_targetDir
283  + QString("%1/%2").arg(maxTileLevel).arg(n, tileDigits, 10, QLatin1Char('0')));
284  if ( !QDir( dirName ).exists() )
285  ( QDir::root() ).mkpath( dirName );
286  }
287 
288  for ( int n = 0; n < nmax; ++n ) {
289 
290  for ( int m = 0; m < mmax; ++m ) {
291 
292  mDebug() << "** tile" << m << "x" << n;
293 
294  if ( d->m_cancelled )
295  return;
296 
297  tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
298  .arg( maxTileLevel )
299  .arg(n, tileDigits, 10, QLatin1Char('0'))
300  .arg(m, tileDigits, 10, QLatin1Char('0'))
301  .arg( d->m_tileFormat );
302 
303  if ( QFile::exists( tileName ) && d->m_resume ) {
304 
305  //mDebug() << tileName << "exists already";
306 
307  } else {
308 
309  QImage tile = d->m_source->tile( n, m, maxTileLevel );
310 
311  if ( tile.isNull() ) {
312  mDebug() << "Read-Error! Null QImage!";
313  return;
314  }
315 
316  if (d->m_dem == QLatin1String("true")) {
318  grayScalePalette,
320  }
321 
322  bool ok = tile.save(tileName, d->m_tileFormat.toLatin1().data(), d->m_tileFormat == QLatin1String("jpg") ? 100 : d->m_tileQuality);
323  if ( !ok )
324  mDebug() << "Error while writing Tile: " << tileName;
325 
326  mDebug() << tileName << "size" << QFile( tileName ).size();
327 
328  if ( d->m_verify ) {
329  QImage writtenTile(tileName);
330  Q_ASSERT( writtenTile.size() == tile.size() );
331  for ( int i=0; i < writtenTile.size().width(); ++i) {
332  for ( int j=0; j < writtenTile.size().height(); ++j) {
333  if ( writtenTile.pixel( i, j ) != tile.pixel( i, j ) ) {
334  unsigned int pixel = tile.pixel( i, j);
335  unsigned int writtenPixel = writtenTile.pixel( i, j);
336  qWarning() << "***** pixel" << i << j << "is off by" << (pixel - writtenPixel) << "pixel" << pixel << "writtenPixel" << writtenPixel;
337  QByteArray baPixel((char*)&pixel, sizeof(unsigned int));
338  qWarning() << "pixel" << baPixel.size() << "0x" << baPixel.toHex();
339  QByteArray baWrittenPixel((char*)&writtenPixel, sizeof(unsigned int));
340  qWarning() << "writtenPixel" << baWrittenPixel.size() << "0x" << baWrittenPixel.toHex();
341  Q_ASSERT(false);
342  }
343  }
344  }
345  }
346 
347  }
348 
349  percentCompleted = (int) ( 90 * (qreal)(createdTilesCount)
350  / (qreal)(totalTileCount) );
351  createdTilesCount++;
352 
353  mDebug() << "percentCompleted" << percentCompleted;
354  emit progress( percentCompleted );
355  }
356  }
357 
358  mDebug() << "tileLevel: " << maxTileLevel << " successfully created.";
359 
360  tileLevel = maxTileLevel;
361 
362  // Now that we have the tiles at the highest resolution lets build
363  // them together four by four.
364 
365  while( tileLevel > 0 ) {
366  tileLevel--;
367 
368  int nmaxit = TileLoaderHelper::levelToRow( defaultLevelZeroRows, tileLevel );
369 
370  for ( int n = 0; n < nmaxit; ++n ) {
371  QString dirName( d->m_targetDir
372  + QString("%1/%2")
373  .arg(tileLevel)
374  .arg(n, tileDigits, 10, QLatin1Char('0')));
375 
376  // mDebug() << "dirName: " << dirName;
377  if ( !QDir( dirName ).exists() )
378  ( QDir::root() ).mkpath( dirName );
379 
380  int mmaxit = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, tileLevel );
381  for ( int m = 0; m < mmaxit; ++m ) {
382 
383  if ( d->m_cancelled )
384  return;
385 
386  QString newTileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
387  .arg( tileLevel )
388  .arg(n, tileDigits, 10, QLatin1Char('0'))
389  .arg(m, tileDigits, 10, QLatin1Char('0'))
390  .arg( d->m_tileFormat );
391 
392  if ( QFile::exists( newTileName ) && d->m_resume ) {
393  //mDebug() << newTileName << "exists already";
394  } else {
395  tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
396  .arg( tileLevel + 1 )
397  .arg(2*n, tileDigits, 10, QLatin1Char('0'))
398  .arg(2*m, tileDigits, 10, QLatin1Char('0'))
399  .arg( d->m_tileFormat );
400  QImage img_topleft( tileName );
401 
402  tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
403  .arg( tileLevel + 1 )
404  .arg(2*n, tileDigits, 10, QLatin1Char('0'))
405  .arg(2*m+1, tileDigits, 10, QLatin1Char('0'))
406  .arg( d->m_tileFormat );
407  QImage img_topright( tileName );
408 
409  tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
410  .arg( tileLevel + 1 )
411  .arg(2*n+1, tileDigits, 10, QLatin1Char('0'))
412  .arg(2*m, tileDigits, 10, QLatin1Char('0'))
413  .arg( d->m_tileFormat );
414  QImage img_bottomleft( tileName );
415 
416  tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
417  .arg( tileLevel + 1 )
418  .arg(2*n+1, tileDigits, 10, QLatin1Char('0'))
419  .arg(2*m+1, tileDigits, 10, QLatin1Char('0'))
420  .arg( d->m_tileFormat );
421  QImage img_bottomright( tileName );
422 
423  QSize const expectedSize( c_defaultTileSize, c_defaultTileSize );
424  if ( img_topleft.size() != expectedSize ||
425  img_topright.size() != expectedSize ||
426  img_bottomleft.size() != expectedSize ||
427  img_bottomright.size() != expectedSize ) {
428  mDebug() << "Tile write failure. Missing write permissions?";
429  emit progress( 100 );
430  return;
431  }
432  QImage tile = img_topleft;
433 
434  if (d->m_dem == QLatin1String("true")) {
435 
436  tile.setColorTable( grayScalePalette );
437  uchar* destLine;
438 
439  for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
440  destLine = tile.scanLine( y );
441  const uchar* srcLine = img_topleft.scanLine( 2 * y );
442  for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
443  destLine[x] = srcLine[ 2*x ];
444  }
445  for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
446  destLine = tile.scanLine( y );
447  const uchar* srcLine = img_topright.scanLine( 2 * y );
448  for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
449  destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
450  }
451  for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
452  destLine = tile.scanLine( y );
453  const uchar* srcLine = img_bottomleft.scanLine( 2 * ( y - c_defaultTileSize / 2 ) );
454  for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
455  destLine[ x ] = srcLine[ 2 * x ];
456  }
457  for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
458  destLine = tile.scanLine( y );
459  const uchar* srcLine = img_bottomright.scanLine( 2 * ( y - c_defaultTileSize/2 ) );
460  for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
461  destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
462  }
463  }
464  else {
465 
466  // tile.depth() != 8
467 
468  img_topleft = img_topleft.convertToFormat( QImage::Format_ARGB32 );
469  img_topright = img_topright.convertToFormat( QImage::Format_ARGB32 );
470  img_bottomleft = img_bottomleft.convertToFormat( QImage::Format_ARGB32 );
471  img_bottomright = img_bottomright.convertToFormat( QImage::Format_ARGB32 );
472  tile = img_topleft;
473 
474  QRgb* destLine;
475 
476  for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
477  destLine = (QRgb*) tile.scanLine( y );
478  const QRgb* srcLine = (QRgb*) img_topleft.scanLine( 2 * y );
479  for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
480  destLine[x] = srcLine[ 2 * x ];
481  }
482  for ( uint y = 0; y < c_defaultTileSize / 2; ++y ) {
483  destLine = (QRgb*) tile.scanLine( y );
484  const QRgb* srcLine = (QRgb*) img_topright.scanLine( 2 * y );
485  for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
486  destLine[x] = srcLine[ 2 * ( x - c_defaultTileSize / 2 ) ];
487  }
488  for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
489  destLine = (QRgb*) tile.scanLine( y );
490  const QRgb* srcLine = (QRgb*) img_bottomleft.scanLine( 2 * ( y-c_defaultTileSize/2 ) );
491  for ( uint x = 0; x < c_defaultTileSize / 2; ++x )
492  destLine[x] = srcLine[ 2 * x ];
493  }
494  for ( uint y = c_defaultTileSize / 2; y < c_defaultTileSize; ++y ) {
495  destLine = (QRgb*) tile.scanLine( y );
496  const QRgb* srcLine = (QRgb*) img_bottomright.scanLine( 2 * ( y-c_defaultTileSize / 2 ) );
497  for ( uint x = c_defaultTileSize / 2; x < c_defaultTileSize; ++x )
498  destLine[x] = srcLine[ 2*( x-c_defaultTileSize / 2 ) ];
499  }
500  }
501 
502  mDebug() << newTileName;
503 
504  // Saving at 100% JPEG quality to have a high-quality
505  // version to create the remaining needed tiles from.
506  bool ok = tile.save(newTileName, d->m_tileFormat.toLatin1().data(), d->m_tileFormat == QLatin1String("jpg") ? 100 : d->m_tileQuality);
507  if ( ! ok )
508  mDebug() << "Error while writing Tile: " << newTileName;
509  }
510 
511  percentCompleted = (int) ( 90 * (qreal)(createdTilesCount)
512  / (qreal)(totalTileCount) );
513  createdTilesCount++;
514 
515  emit progress( percentCompleted );
516  mDebug() << "percentCompleted" << percentCompleted;
517  }
518  }
519  mDebug() << "tileLevel: " << tileLevel << " successfully created.";
520  }
521  mDebug() << "Tile creation completed.";
522 
523  if (d->m_tileFormat == QLatin1String("jpg") && d->m_tileQuality != 100) {
524 
525  // Applying correct lower JPEG compression now that we created all tiles
526  int savedTilesCount = 0;
527 
528  tileLevel = 0;
529  while ( tileLevel <= maxTileLevel ) {
530  int nmaxit = TileLoaderHelper::levelToRow( defaultLevelZeroRows, tileLevel );
531  for ( int n = 0; n < nmaxit; ++n) {
532  int mmaxit = TileLoaderHelper::levelToColumn( defaultLevelZeroColumns, tileLevel );
533  for ( int m = 0; m < mmaxit; ++m) {
534 
535  if ( d->m_cancelled )
536  return;
537 
538  savedTilesCount++;
539 
540  tileName = d->m_targetDir + QString("%1/%2/%2_%3.%4")
541  .arg( tileLevel )
542  .arg(n, tileDigits, 10, QLatin1Char('0'))
543  .arg(m, tileDigits, 10, QLatin1Char('0'))
544  .arg( d->m_tileFormat );
545  QImage tile( tileName );
546 
547  bool ok;
548 
549  ok = tile.save( tileName, d->m_tileFormat.toLatin1().data(), d->m_tileQuality );
550 
551  if ( !ok )
552  mDebug() << "Error while writing Tile: " << tileName;
553  // Don't exceed 99% as this would cancel the thread unexpectedly
554  percentCompleted = 90 + (int)( 9 * (qreal)(savedTilesCount)
555  / (qreal)(totalTileCount) );
556  emit progress( percentCompleted );
557  mDebug() << "percentCompleted" << percentCompleted;
558  //mDebug() << "Saving Tile #" << savedTilesCount
559  // << " of " << totalTileCount
560  // << " Percent: " << percentCompleted;
561  }
562  }
563  tileLevel++;
564  }
565  }
566 
567  percentCompleted = 100;
568  emit progress( percentCompleted );
569 
570  mDebug() << "percentCompleted: " << percentCompleted;
571 }
572 
573 void TileCreator::setTileFormat(const QString& format)
574 {
575  d->m_tileFormat = format;
576 }
577 
578 QString TileCreator::tileFormat() const
579 {
580  return d->m_tileFormat;
581 }
582 
583 void TileCreator::setTileQuality(int quality)
584 {
585  d->m_tileQuality = quality;
586 }
587 
588 int TileCreator::tileQuality() const
589 {
590  return d->m_tileQuality;
591 }
592 
593 void TileCreator::setResume(bool resume)
594 {
595  d->m_resume = resume;
596 }
597 
598 bool TileCreator::resume() const
599 {
600  return d->m_resume;
601 }
602 
603 void TileCreator::setVerifyExactResult(bool verify)
604 {
605  d->m_verify = verify;
606 }
607 
608 bool TileCreator::verifyExactResult() const
609 {
610  return d->m_verify;
611 }
612 
613 
614 }
615 
616 #include "moc_TileCreator.cpp"
bool exists() const const
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
void insert(int i, T &&value)
QDir root()
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
int width() const const
bool exists() const const
IgnoreAspectRatio
QRgb pixel(int x, int y) const const
int height() const const
QImage convertToFormat(QImage::Format format, Qt::ImageConversionFlags flags) const &const
bool isNull() const const
Binds a QML item to a specific geodetic location in screen coordinates.
QSize size() const const
KIOCORE_EXPORT MkpathJob * mkpath(const QUrl &url, const QUrl &baseUrl=QUrl(), JobFlags flags=DefaultFlags)
uchar * scanLine(int i)
bool isAbsolutePath(const QString &path)
virtual qint64 size() const const override
ThresholdDither
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
SmoothTransformation
bool save(const QString &fileName, const char *format, int quality) const const
void setColorTable(const QVector< QRgb > colors)
QImage copy(const QRect &rectangle) const const
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Oct 2 2023 03:52:10 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.