091222_raster_patch.diff

Patch to print large rasters in tiles - Marco Hugentobler, 2009-12-22 07:34 AM

Download (13.4 KB)

View differences:

src/core/raster/qgsrasterlayer.cpp (working copy)
22 22
#include "qgsmaptopixel.h"
23 23
#include "qgsproviderregistry.h"
24 24
#include "qgsrasterbandstats.h"
25
#include "qgsrasterimagebuffer.h"
25 26
#include "qgsrasterlayer.h"
26 27
#include "qgsrasterpyramid.h"
27 28
#include "qgsrectangle.h"
......
2917 2918

  
2918 2919
  // Only do this for the non-provider (hard-coded GDAL) scenario...
2919 2920
  // Maybe WMS can do this differently using QImage::numColors and QImage::color()
2920
  if ( mProviderKey.isEmpty() && hasBand( "Palette" ) && theBandNumber > 0 ) //dont tr() this its a gdal word!
2921
  if ( mProviderKey.isEmpty() && hasBand( "Palette" ) && theBandNumber > 0 ) //don't tr() this its a gdal word!
2921 2922
  {
2922 2923
    QgsDebugMsg( "....found paletted image" );
2923 2924
    QgsColorRampShader myShader;
......
2977 2978
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
2978 2979
  QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
2979 2980
  //calculate the histogram for this band
2980
  //we assume that it only needs to be calculated if the lenght of the histogram
2981
  //we assume that it only needs to be calculated if the length of the histogram
2981 2982
  //vector is not equal to the number of bins
2982 2983
  //i.e if the histogram has never previously been generated or the user has
2983 2984
  //selected a new number of bins.
......
3786 3787
  {
3787 3788
    QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction();
3788 3789

  
3789
    //TODO: Remove the customColorRampType check and following if() in v2.0, added for compatability with older ( bugged ) project files
3790
    //TODO: Remove the customColorRampType check and following if() in v2.0, added for compatibility with older ( bugged ) project files
3790 3791
    QDomNode customColorRampTypeNode = customColorRampNode.namedItem( "customColorRampType" );
3791 3792
    QDomNode colorRampTypeNode = customColorRampNode.namedItem( "colorRampType" );
3792 3793
    QString myRampType = "";
......
4505 4506

  
4506 4507
  GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
4507 4508
  GDALDataType myDataType = GDALGetRasterDataType( myGdalBand );
4509
  QgsRasterImageBuffer imageBuffer( myGdalBand, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] );
4510
  imageBuffer.reset();
4511

  
4512
  QRgb* imageScanLine = 0;
4513
  void* rasterScanLine = 0;
4514

  
4515
  QRgb myDefaultColor = qRgba( 255, 255, 255, 0 );
4516
  double myPixelValue = 0.0;
4517
  int myRedValue = 0;
4518
  int myGreenValue = 0;
4519
  int myBlueValue = 0;
4520
  int myAlphaValue = 0;
4521

  
4522
  while( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) )
4523
  {
4524
    for( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i )
4525
    {
4526
        myRedValue = 0; myGreenValue = 0; myBlueValue = 0;
4527
        myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i);
4528

  
4529
        if ( mValidNoDataValue && ( fabs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) )
4530
        {
4531
            imageScanLine[ i ] = myDefaultColor;
4532
            continue;
4533
        }
4534

  
4535
        myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel );
4536
        if ( 0 == myAlphaValue )
4537
        {
4538
            imageScanLine[ i ] = myDefaultColor;
4539
            continue;
4540
        }
4541

  
4542
        if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) )
4543
        {
4544
            imageScanLine[ i ] = myDefaultColor;
4545
            continue;
4546
        }
4547

  
4548
        if ( mInvertColor )
4549
        {
4550
            //Invert flag, flip blue and read
4551
            imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue );
4552
        }
4553
        else
4554
        {
4555
            //Normal
4556
            imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue );
4557
        }
4558
    }
4559
  }
4560

  
4561
#if 0
4562

  
4563

  
4508 4564
  void *myGdalScanData = readData( myGdalBand, theRasterViewPort );
4509 4565

  
4510 4566
  /* Check for out of memory error */
......
4568 4624
  CPLFree( myGdalScanData );
4569 4625

  
4570 4626
  paintImageToCanvas( theQPainter, theRasterViewPort, theQgsMapToPixel, &myQImage );
4627
#endif //0
4571 4628
}
4572 4629

  
4573 4630
/**
......
5314 5371
    mRasterType = Multiband;
5315 5372
  }
5316 5373
  //TODO hasBand is really obsolete and only used in the Palette instance, change to new function hasPalette(int)
5317
  else if ( hasBand( "Palette" ) ) //dont tr() this its a gdal word!
5374
  else if ( hasBand( "Palette" ) ) //don't tr() this its a gdal word!
5318 5375
  {
5319 5376
    mRasterType = Palette;
5320 5377
  }
src/core/raster/qgsrasterimagebuffer.cpp (revision 0)
1
/***************************************************************************
2
    qgsrasterimagebuffer.cpp
3
    ------------------------
4
    begin                : December 2009
5
    copyright            : (C) 2009 by Marco Hugentobler
6
    email                : marco at hugis dot net
7
 ***************************************************************************
8
 *                                                                         *
9
 *   This program is free software; you can redistribute it and/or modify  *
10
 *   it under the terms of the GNU General Public License as published by  *
11
 *   the Free Software Foundation; either version 2 of the License, or     *
12
 *   (at your option) any later version.                                   *
13
 *                                                                         *
14
 ***************************************************************************/
15

  
16
#include "qgsrasterimagebuffer.h"
17
#include "qgsmaptopixel.h"
18
#include "qgsrasterviewport.h"
19
#include <QImage>
20
#include <QPainter>
21
#include <gdal.h>
22
#include "cpl_conv.h"
23

  
24
#ifndef Q_OS_MACX
25
#include <cmath>
26
#else
27
#include <math.h>
28
#endif
29

  
30

  
31
QgsRasterImageBuffer::QgsRasterImageBuffer(GDALRasterBandH rasterBand, QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* geoTransform): \
32
mRasterBand(rasterBand), mPainter(p), mViewPort(viewPort), mMapToPixel(mapToPixel), mValid(false), mCurrentImage(0), mCurrentGDALData(0), mGeoTransform(geoTransform)
33
{
34

  
35
}
36

  
37
QgsRasterImageBuffer::~QgsRasterImageBuffer()
38
{
39
    delete mCurrentImage;
40
    CPLFree(mCurrentGDALData);
41
}
42

  
43
void QgsRasterImageBuffer::reset()
44
{
45
    if( mRasterBand && mPainter && mViewPort && mMapToPixel )
46
    {
47
        mValid = true;
48
    }
49
    else
50
    {
51
        mValid = false;
52
        return;
53
    }
54

  
55
    //decide on the partition of the image
56

  
57
    int pixels = mViewPort->drawableAreaXDim * mViewPort->drawableAreaYDim;
58
    int mNumPartImages = std::max(pixels / 50000000.0, 1.0);
59
    mNumRasterRowsPerPart = (double)mViewPort->clippedHeight / (double)mNumPartImages + 0.5;
60

  
61
    mCurrentPartRasterMin = -1;
62
    mCurrentPartRasterMax = -1;
63
    mCurrentPartImageRow = 0;
64
    mNumCurrentImageRows = 0;
65

  
66
    createNextPartImage();
67
}
68

  
69
bool QgsRasterImageBuffer::nextScanLine(QRgb** imageScanLine, void** rasterScanLine)
70
{
71
    if(!mValid)
72
    {
73
        return false;
74
    }
75

  
76
    if( !mCurrentGDALData || ! mCurrentImage )
77
    {
78
        return false;
79
    }
80

  
81
    if(mCurrentPartImageRow >= (mNumCurrentImageRows))
82
    {
83
        if(!createNextPartImage())
84
        {
85
            return false;
86
        }
87
    }
88

  
89
    *imageScanLine = ( QRgb* )(mCurrentImage->scanLine(mCurrentPartImageRow));
90
    GDALDataType type = GDALGetRasterDataType( mRasterBand );
91
    int size = GDALGetDataTypeSize( type ) / 8;
92
    *rasterScanLine = mCurrentGDALData + mCurrentPartImageRow * mViewPort->drawableAreaXDim * size;
93

  
94
    ++mCurrentPartImageRow;
95
    ++mCurrentRow;
96
    return true;
97
}
98

  
99
bool QgsRasterImageBuffer::createNextPartImage()
100
{
101
    //draw the last image if mCurrentImage if it exists
102
    if(mCurrentImage)
103
    {
104
        double xLeft = mViewPort->topLeftPoint.x();
105
        double yTop = mViewPort->topLeftPoint.y() + fabs(mGeoTransform[5]) * mCurrentPartRasterMin / mMapToPixel->mapUnitsPerPixel();
106
        mPainter->drawImage(QPointF(xLeft, yTop), *mCurrentImage);
107
    }
108

  
109
    delete mCurrentImage; mCurrentImage = 0;
110
    CPLFree(mCurrentGDALData); mCurrentGDALData = 0;
111

  
112
    if(mCurrentPartRasterMax >= mViewPort->clippedHeight)
113
    {
114
        return false; //already at the end...
115
    }
116

  
117
    mCurrentPartRasterMin = mCurrentPartRasterMax + 1;
118
    mCurrentPartRasterMax = mCurrentPartRasterMin + mNumRasterRowsPerPart;
119
    if(mCurrentPartRasterMax > mViewPort->clippedHeight)
120
    {
121
        mCurrentPartRasterMax = mViewPort->clippedHeight;
122
    }
123
    mCurrentRow = mCurrentPartRasterMin;
124
    mCurrentPartImageRow = 0;
125

  
126
    //read GDAL image data
127
    GDALDataType type = GDALGetRasterDataType( mRasterBand );
128
    int size = GDALGetDataTypeSize( type ) / 8;
129
    int xSize = mViewPort->drawableAreaXDim;
130

  
131
    //make the raster tiles overlap at least 2 pixels to avoid white stripes
132
    int overlapRows = 0;
133
    overlapRows = mMapToPixel->mapUnitsPerPixel() / fabs(mGeoTransform[5]) + 2;
134
    if(mCurrentPartRasterMax + overlapRows >= mViewPort->clippedHeight)
135
    {
136
      overlapRows = 0;
137
    }
138
    int rasterYSize = mCurrentPartRasterMax - mCurrentPartRasterMin + overlapRows;
139

  
140
    int ySize = fabs(( (rasterYSize) / mMapToPixel->mapUnitsPerPixel() * mGeoTransform[5] ) ) + 0.5;
141
    if(ySize == 0)
142
    {
143
      return false;
144
    }
145
    mNumCurrentImageRows = ySize;
146
    mCurrentGDALData = VSIMalloc(size * xSize * ySize);
147
    CPLErr myErr = GDALRasterIO( mRasterBand, GF_Read, mViewPort->rectXOffset, \
148
                       mViewPort->rectYOffset + mCurrentRow, mViewPort->clippedWidth, rasterYSize, \
149
                       mCurrentGDALData, xSize, ySize, type, 0, 0);
150

  
151
    if ( myErr != CPLE_None )
152
    {
153
        CPLFree(mCurrentGDALData);
154
        mCurrentGDALData = 0;
155
        return false;
156
    }
157

  
158
    //create the QImage
159
    mCurrentImage = new QImage( xSize, ySize, QImage::Format_ARGB32 );
160
    mCurrentImage->fill(qRgba(255, 255, 255, 0));
161
    return true;
162
}
163

  
src/core/raster/qgsrasterimagebuffer.h (revision 0)
1
/***************************************************************************
2
    qgsrasterimagebuffer.h
3
    ---------------------
4
    begin                : December 2009
5
    copyright            : (C) 2009 by Marco Hugentobler
6
    email                : marco at hugis dot net
7
 ***************************************************************************
8
 *                                                                         *
9
 *   This program is free software; you can redistribute it and/or modify  *
10
 *   it under the terms of the GNU General Public License as published by  *
11
 *   the Free Software Foundation; either version 2 of the License, or     *
12
 *   (at your option) any later version.                                   *
13
 *                                                                         *
14
 ***************************************************************************/
15

  
16
#ifndef QGSRASTERIMAGEBUFFER_H
17
#define QGSRASTERIMAGEBUFFER_H
18

  
19
#include <QColor>
20

  
21
typedef void* GDALRasterBandH;
22
class QgsMapToPixel;
23
struct QgsRasterViewPort;
24
class QImage;
25
class QPainter;
26

  
27
/**A class encapsulates reading from a raster band and drawing the pixels to a painter.
28
   The class allows sequential reading of the scan lines and setting the image scan line pixels. It automatically decides
29
   on how much of the band / image should stay in virtual memory at a time*/
30
class QgsRasterImageBuffer
31
{
32
    public:
33
        QgsRasterImageBuffer(GDALRasterBandH rasterBand, QPainter* p, \
34
                             QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* mGeoTransform);
35
        ~QgsRasterImageBuffer();
36
        void reset();
37
        /**Returns a pointer to the next scan line (or 0 if end)*/
38
        bool nextScanLine(QRgb** imageScanLine, void** rasterScanLine);
39

  
40
    private:
41
        QgsRasterImageBuffer(); //forbidden
42
        /**Creates next part image. Returns false if at end*/
43
        bool createNextPartImage();
44

  
45
        GDALRasterBandH mRasterBand; //raster band
46
        QPainter* mPainter;
47
        QgsRasterViewPort* mViewPort;
48
        const QgsMapToPixel* mMapToPixel;
49
        double* mGeoTransform;
50

  
51
        bool mValid;
52
        int mCurrentRow;
53
        int mNumPartImages; //number of part images
54
        int mNumRasterRowsPerPart; //number of (raster source) rows per part
55
        int mCurrentPartRasterMin; //minimum (raster source) row of current image
56
        int mCurrentPartRasterMax; //maximum (raster source) row of current image
57
        int mCurrentPartImageRow; //current image row
58
        int mNumCurrentImageRows; //number of image rows for the current part
59

  
60
        //current memory image and gdal scan data
61
        QImage* mCurrentImage;
62
        void* mCurrentGDALData;
63
};
64

  
65
#endif // QGSRASTERIMAGEBUFFER_H
src/core/CMakeLists.txt (working copy)
110 110
  raster/qgslinearminmaxenhancement.cpp
111 111
  raster/qgslinearminmaxenhancementwithclip.cpp
112 112
  raster/qgspseudocolorshader.cpp
113
  raster/qgsrasterimagebuffer.cpp
113 114
  raster/qgsrasterlayer.cpp
114 115
  raster/qgsrastertransparency.cpp
115 116
  raster/qgsrastershader.cpp