26 #include "imageclasses/ImgWriterGdal.h"
27 #include "imageclasses/ImgReaderGdal.h"
28 #include "imageclasses/ImgReaderOgr.h"
29 #include "base/Optionpk.h"
30 #include "algorithms/Egcs.h"
101 int main(
int argc,
char *argv[])
103 Optionpk<string> input_opt(
"i",
"input",
"Input image file(s). If input contains multiple images, a multi-band output is created");
105 Optionpk<string> projection_opt(
"a_srs",
"a_srs",
"Override the projection for the output file (leave blank to copy from input file, use epsg:3035 to use European projection and force to European grid");
107 Optionpk<string> extent_opt(
"e",
"extent",
"get boundary from extent from polygons in vector file");
108 Optionpk<bool> cut_opt(
"cut",
"crop_to_cutline",
"Crop the extent of the target dataset to the extent of the cutline.",
false);
109 Optionpk<string> mask_opt(
"m",
"mask",
"Use the the specified file as a validity mask (0 is nodata).");
110 Optionpk<float> msknodata_opt(
"msknodata",
"msknodata",
"Mask value not to consider for crop.", 0);
111 Optionpk<short> mskband_opt(
"mskband",
"mskband",
"Mask band to read (0 indexed). Provide band for each mask.", 0);
112 Optionpk<double> ulx_opt(
"ulx",
"ulx",
"Upper left x value bounding box", 0.0);
113 Optionpk<double> uly_opt(
"uly",
"uly",
"Upper left y value bounding box", 0.0);
114 Optionpk<double> lrx_opt(
"lrx",
"lrx",
"Lower right x value bounding box", 0.0);
115 Optionpk<double> lry_opt(
"lry",
"lry",
"Lower right y value bounding box", 0.0);
116 Optionpk<double> dx_opt(
"dx",
"dx",
"Output resolution in x (in meter) (empty: keep original resolution)");
117 Optionpk<double> dy_opt(
"dy",
"dy",
"Output resolution in y (in meter) (empty: keep original resolution)");
118 Optionpk<double> cx_opt(
"x",
"x",
"x-coordinate of image center to crop (in meter)");
119 Optionpk<double> cy_opt(
"y",
"y",
"y-coordinate of image center to crop (in meter)");
122 Optionpk<int> ns_opt(
"ns",
"ns",
"number of samples to crop (in pixels)");
123 Optionpk<int> nl_opt(
"nl",
"nl",
"number of lines to crop (in pixels)");
127 Optionpk<double> autoscale_opt(
"as",
"autoscale",
"scale output to min and max, e.g., --autoscale 0 --autoscale 255");
129 Optionpk<double> offset_opt(
"offset",
"offset",
"output=scale*input+offset");
130 Optionpk<string> otype_opt(
"ot",
"otype",
"Data type for output image ({Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/CInt16/CInt32/CFloat32/CFloat64}). Empty string: inherit type from input image",
"");
131 Optionpk<string> oformat_opt(
"of",
"oformat",
"Output image format (see also gdal_translate).",
"GTiff");
132 Optionpk<string> option_opt(
"co",
"co",
"Creation option for output file. Multiple options can be specified.");
133 Optionpk<string> colorTable_opt(
"ct",
"ct",
"color table (file with 5 columns: id R G B ALFA (0: transparent, 255: solid)");
134 Optionpk<float> nodata_opt(
"nodata",
"nodata",
"Nodata value to put in image if out of bounds.");
135 Optionpk<string> resample_opt(
"r",
"resampling-method",
"Resampling method (near: nearest neighbor, bilinear: bi-linear interpolation).",
"near");
136 Optionpk<string> description_opt(
"d",
"description",
"Set image description");
137 Optionpk<bool> align_opt(
"align",
"align",
"Align output bounding box to input image",
false);
140 extent_opt.setHide(1);
142 bstart_opt.setHide(1);
145 msknodata_opt.setHide(1);
146 mskband_opt.setHide(1);
147 option_opt.setHide(1);
154 scale_opt.setHide(1);
155 offset_opt.setHide(1);
156 nodata_opt.setHide(1);
157 description_opt.setHide(1);
161 doProcess=input_opt.retrieveOption(argc,argv);
162 output_opt.retrieveOption(argc,argv);
163 projection_opt.retrieveOption(argc,argv);
164 ulx_opt.retrieveOption(argc,argv);
165 uly_opt.retrieveOption(argc,argv);
166 lrx_opt.retrieveOption(argc,argv);
167 lry_opt.retrieveOption(argc,argv);
168 band_opt.retrieveOption(argc,argv);
169 bstart_opt.retrieveOption(argc,argv);
170 bend_opt.retrieveOption(argc,argv);
171 autoscale_opt.retrieveOption(argc,argv);
172 otype_opt.retrieveOption(argc,argv);
173 oformat_opt.retrieveOption(argc,argv);
174 colorTable_opt.retrieveOption(argc,argv);
175 dx_opt.retrieveOption(argc,argv);
176 dy_opt.retrieveOption(argc,argv);
177 resample_opt.retrieveOption(argc,argv);
178 extent_opt.retrieveOption(argc,argv);
179 cut_opt.retrieveOption(argc,argv);
180 mask_opt.retrieveOption(argc,argv);
181 msknodata_opt.retrieveOption(argc,argv);
182 mskband_opt.retrieveOption(argc,argv);
183 option_opt.retrieveOption(argc,argv);
184 cx_opt.retrieveOption(argc,argv);
185 cy_opt.retrieveOption(argc,argv);
186 nx_opt.retrieveOption(argc,argv);
187 ny_opt.retrieveOption(argc,argv);
188 ns_opt.retrieveOption(argc,argv);
189 nl_opt.retrieveOption(argc,argv);
190 scale_opt.retrieveOption(argc,argv);
191 offset_opt.retrieveOption(argc,argv);
192 nodata_opt.retrieveOption(argc,argv);
193 description_opt.retrieveOption(argc,argv);
194 align_opt.retrieveOption(argc,argv);
195 verbose_opt.retrieveOption(argc,argv);
197 catch(
string predefinedString){
198 std::cout << predefinedString << std::endl;
202 cout << setprecision(12) <<
"--ulx=" << ulx_opt[0] <<
" --uly=" << uly_opt[0] <<
" --lrx=" << lrx_opt[0] <<
" --lry=" << lry_opt[0] << endl;
206 cout <<
"Usage: pkcrop -i input -o output" << endl;
208 std::cout <<
"short option -h shows basic options only, use long option --help to show all options" << std::endl;
211 if(input_opt.empty()){
212 std::cerr <<
"No input file provided (use option -i). Use --help for help information" << std::endl;
215 if(output_opt.empty()){
216 std::cerr <<
"No output file provided (use option -o). Use --help for help information" << std::endl;
220 float nodataValue=nodata_opt.size()? nodata_opt[0] : 0;
221 RESAMPLE theResample;
222 if(resample_opt[0]==
"near"){
225 cout <<
"resampling: nearest neighbor" << endl;
227 else if(resample_opt[0]==
"bilinear"){
228 theResample=BILINEAR;
230 cout <<
"resampling: bilinear interpolation" << endl;
233 std::cout <<
"Error: resampling method " << resample_opt[0] <<
" not supported" << std::endl;
237 const char* pszMessage;
238 void* pProgressArg=NULL;
239 GDALProgressFunc pfnProgress=GDALTermProgress;
241 pfnProgress(progress,pszMessage,pProgressArg);
255 if(bstart_opt.size()){
256 if(bend_opt.size()!=bstart_opt.size()){
257 string errorstring=
"Error: options for start and end band indexes must be provided as pairs, missing end band";
261 for(
int ipair=0;ipair<bstart_opt.size();++ipair){
262 if(bend_opt[ipair]<=bstart_opt[ipair]){
263 string errorstring=
"Error: index for end band must be smaller then start band";
266 for(
int iband=bstart_opt[ipair];iband<=bend_opt[ipair];++iband)
267 band_opt.push_back(iband);
272 cerr << error << std::endl;
277 string projectionString;
278 for(
int iimg=0;iimg<input_opt.size();++iimg){
279 imgReader.open(input_opt[iimg]);
281 isGeoRef=imgReader.isGeoRef();
282 if(imgReader.isGeoRef()&&projection_opt.empty())
283 projectionString=imgReader.getProjection();
285 if(!iimg||imgReader.getDeltaX()<dx)
286 dx=imgReader.getDeltaX();
289 if(!iimg||imgReader.getDeltaY()<dy)
290 dy=imgReader.getDeltaY();
293 ncropband+=band_opt.size();
295 ncropband+=imgReader.nrOfBand();
299 GDALDataType theType=GDT_Unknown;
301 cout <<
"possible output data types: ";
302 for(
int iType = 0; iType < GDT_TypeCount; ++iType){
304 cout <<
" " << GDALGetDataTypeName((GDALDataType)iType);
305 if( GDALGetDataTypeName((GDALDataType)iType) != NULL
306 && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
307 otype_opt[0].c_str()))
308 theType=(GDALDataType) iType;
312 if(theType==GDT_Unknown)
313 cout <<
"Unknown output pixel type: " << otype_opt[0] << endl;
315 cout <<
"Output pixel type: " << GDALGetDataTypeName(theType) << endl;
318 double cropulx=ulx_opt[0];
319 double cropuly=uly_opt[0];
320 double croplrx=lrx_opt[0];
321 double croplry=lry_opt[0];
325 if(extent_opt.size()){
330 for(
int iextent=0;iextent<extent_opt.size();++iextent){
331 extentReader.open(extent_opt[iextent]);
332 if(!(extentReader.getExtent(e_ulx,e_uly,e_lrx,e_lry))){
333 cerr <<
"Error: could not get extent from " << extent_opt[0] << endl;
352 extentReader.close();
355 extentReader.open(extent_opt[0]);
357 else if(cx_opt.size()&&cy_opt.size()&&nx_opt.size()&&ny_opt.size()){
358 ulx_opt[0]=cx_opt[0]-nx_opt[0]/2.0;
359 uly_opt[0]=(isGeoRef) ? cy_opt[0]+ny_opt[0]/2.0 : cy_opt[0]-ny_opt[0]/2.0;
360 lrx_opt[0]=cx_opt[0]+nx_opt[0]/2.0;
361 lry_opt[0]=(isGeoRef) ? cy_opt[0]-ny_opt[0]/2.0 : cy_opt[0]+ny_opt[0]/2.0;
371 else if(cx_opt.size()&&cy_opt.size()&&ns_opt.size()&&nl_opt.size()){
372 ulx_opt[0]=cx_opt[0]-ns_opt[0]*dx/2.0;
373 uly_opt[0]=(isGeoRef) ? cy_opt[0]+nl_opt[0]*dy/2.0 : cy_opt[0]-nl_opt[0]*dy/2.0;
374 lrx_opt[0]=cx_opt[0]+ns_opt[0]*dx/2.0;
375 lry_opt[0]=(isGeoRef) ? cy_opt[0]-nl_opt[0]*dy/2.0 : cy_opt[0]+nl_opt[0]*dy/2.0;
387 cout <<
"--ulx=" << ulx_opt[0] <<
" --uly=" << uly_opt[0] <<
" --lrx=" << lrx_opt[0] <<
" --lry=" << lry_opt[0] << endl;
393 if(extent_opt.size()&&cut_opt[0]){
395 ncropcol=abs(static_cast<int>(ceil((lrx_opt[0]-ulx_opt[0])/dx)));
396 ncroprow=abs(static_cast<int>(ceil((uly_opt[0]-lry_opt[0])/dy)));
397 maskWriter.open(
"/vsimem/mask.tif",ncropcol,ncroprow,1,GDT_Float32,
"GTiff",option_opt);
405 maskWriter.setGeoTransform(gt);
406 if(projection_opt.size())
407 maskWriter.setProjectionProj4(projection_opt[0]);
408 else if(projectionString.size())
409 maskWriter.setProjection(projectionString);
412 vector<double> burnValues(1,1);
413 maskWriter.rasterizeOgr(extentReader,burnValues);
417 cerr << error << std::endl;
421 cerr <<
"error caught" << std::endl;
426 mask_opt.push_back(
"/vsimem/mask.tif");
431 if(verbose_opt[0]>=1)
432 std::cout <<
"opening mask image file " << mask_opt[0] << std::endl;
433 maskReader.open(mask_opt[0]);
434 if(mskband_opt[0]>=maskReader.nrOfBand()){
435 string errorString=
"Error: illegal mask band";
440 cerr << error << std::endl;
444 cerr <<
"error caught" << std::endl;
452 if(scale_opt.size()){
453 while(scale_opt.size()<band_opt.size())
454 scale_opt.push_back(scale_opt[0]);
456 if(offset_opt.size()){
457 while(offset_opt.size()<band_opt.size())
458 offset_opt.push_back(offset_opt[0]);
460 if(autoscale_opt.size()){
461 assert(autoscale_opt.size()%2==0);
468 for(
int iimg=0;iimg<input_opt.size();++iimg){
470 cout <<
"opening image " << input_opt[iimg] << endl;
471 imgReader.open(input_opt[iimg]);
473 if(theType==GDT_Unknown){
474 theType=imgReader.getDataType();
476 cout <<
"Using data type from input image: " << GDALGetDataTypeName(theType) << endl;
478 if(option_opt.findSubstring(
"INTERLEAVE=")==option_opt.end()){
479 string theInterleave=
"INTERLEAVE=";
480 theInterleave+=imgReader.getInterleave();
481 option_opt.push_back(theInterleave);
483 int nrow=imgReader.nrOfRow();
484 int ncol=imgReader.nrOfCol();
490 cout <<
"size of " << input_opt[iimg] <<
": " << ncol <<
" cols, "<< nrow <<
" rows" << endl;
491 double uli,ulj,lri,lrj;
492 bool forceEUgrid=
false;
493 if(projection_opt.size())
494 forceEUgrid=(!(projection_opt[0].compare(
"EPSG:3035"))||!(projection_opt[0].compare(
"EPSG:3035"))||projection_opt[0].find(
"ETRS-LAEA")!=string::npos);
495 if(ulx_opt[0]>=lrx_opt[0]){
497 lri=imgReader.nrOfCol()-1;
499 lrj=imgReader.nrOfRow()-1;
500 ncropcol=imgReader.nrOfCol();
501 ncroprow=imgReader.nrOfRow();
502 imgReader.getBoundingBox(cropulx,cropuly,croplrx,croplry);
503 double magicX=1,magicY=1;
508 egcs.setLevel(egcs.res2level(dx));
509 egcs.force2grid(cropulx,cropuly,croplrx,croplry);
510 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
511 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
513 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
514 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
516 ncropcol=abs(static_cast<int>(ceil((croplrx-cropulx)/dx)));
517 ncroprow=abs(static_cast<int>(ceil((cropuly-croplry)/dy)));
520 double magicX=1,magicY=1;
529 egcs.setLevel(egcs.res2level(dx));
530 egcs.force2grid(cropulx,cropuly,croplrx,croplry);
532 else if(align_opt[0]){
533 if(cropulx>imgReader.getUlx())
534 cropulx-=fmod(cropulx-imgReader.getUlx(),dx);
535 else if(cropulx<imgReader.getUlx())
536 cropulx+=fmod(imgReader.getUlx()-cropulx,dx)-dx;
537 if(croplrx<imgReader.getLrx())
538 croplrx+=fmod(imgReader.getLrx()-croplrx,dx);
539 else if(croplrx>imgReader.getLrx())
540 croplrx-=fmod(croplrx-imgReader.getLrx(),dx)+dx;
541 if(croplry>imgReader.getLry())
542 croplry-=fmod(croplry-imgReader.getLry(),dy);
543 else if(croplry<imgReader.getLry())
544 croplry+=fmod(imgReader.getLry()-croplry,dy)-dy;
545 if(cropuly<imgReader.getUly())
546 cropuly+=fmod(imgReader.getUly()-cropuly,dy);
547 else if(cropuly>imgReader.getUly())
548 cropuly-=fmod(cropuly-imgReader.getUly(),dy)+dy;
550 imgReader.geo2image(cropulx+(magicX-1.0)*imgReader.getDeltaX(),cropuly-(magicY-1.0)*imgReader.getDeltaY(),uli,ulj);
551 imgReader.geo2image(croplrx+(magicX-2.0)*imgReader.getDeltaX(),croplry-(magicY-2.0)*imgReader.getDeltaY(),lri,lrj);
553 ncropcol=abs(static_cast<int>(ceil((croplrx-cropulx)/dx)));
554 ncroprow=abs(static_cast<int>(ceil((cropuly-croplry)/dy)));
563 double deltaX=imgReader.getDeltaX();
564 double deltaY=imgReader.getDeltaY();
565 dcropcol=(lri-uli+1)/(dx/deltaX);
566 dcroprow=(lrj-ulj+1)/(dy/deltaY);
567 if(!imgWriter.nrOfBand()){
569 cout <<
"cropulx: " << cropulx << endl;
570 cout <<
"cropuly: " << cropuly << endl;
571 cout <<
"croplrx: " << croplrx << endl;
572 cout <<
"croplry: " << croplry << endl;
573 cout <<
"ncropcol: " << ncropcol << endl;
574 cout <<
"ncroprow: " << ncroprow << endl;
575 cout <<
"cropulx+ncropcol*dx: " << cropulx+ncropcol*dx << endl;
576 cout <<
"cropuly-ncroprow*dy: " << cropuly-ncroprow*dy << endl;
577 cout <<
"upper left column of input image: " << uli << endl;
578 cout <<
"upper left row of input image: " << ulj << endl;
579 cout <<
"lower right column of input image: " << lri << endl;
580 cout <<
"lower right row of input image: " << lrj << endl;
581 cout <<
"new number of cols: " << ncropcol << endl;
582 cout <<
"new number of rows: " << ncroprow << endl;
583 cout <<
"new number of bands: " << ncropband << endl;
596 if(oformat_opt.size())
597 imageType=oformat_opt[0];
599 imgWriter.open(output_opt[0],ncropcol,ncroprow,ncropband,theType,imageType,option_opt);
600 if(nodata_opt.size()){
601 for(
int iband=0;iband<ncropband;++iband)
602 imgWriter.GDALSetNoDataValue(nodata_opt[0],iband);
605 catch(
string errorstring){
606 cout << errorstring << endl;
609 if(description_opt.size())
610 imgWriter.setImageDescription(description_opt[0]);
617 gt[5]=(imgReader.isGeoRef())? -dy : dy;
618 imgWriter.setGeoTransform(gt);
619 if(projection_opt.size()){
621 cout <<
"projection: " << projection_opt[0] << endl;
622 imgWriter.setProjectionProj4(projection_opt[0]);
625 imgWriter.setProjection(imgReader.getProjection());
626 if(imgWriter.getDataType()==GDT_Byte){
627 if(colorTable_opt.size()){
628 if(colorTable_opt[0]!=
"none")
629 imgWriter.setColorTable(colorTable_opt[0]);
631 else if (imgReader.getColorTable()!=NULL)
632 imgWriter.setColorTable(imgReader.getColorTable());
640 else if(uli>=imgReader.nrOfCol())
641 startCol=imgReader.nrOfCol()-1;
644 else if(lri>=imgReader.nrOfCol())
645 endCol=imgReader.nrOfCol()-1;
650 else if(ulj>=imgReader.nrOfRow())
651 startRow=imgReader.nrOfRow()-1;
654 else if(lrj>=imgReader.nrOfRow())
655 endRow=imgReader.nrOfRow()-1;
659 int readncol=endCol-startCol+1;
660 vector<double> readBuffer(readncol+1);
661 int nband=(band_opt.size())?band_opt.size() : imgReader.nrOfBand();
662 for(
int iband=0;iband<nband;++iband){
663 int readBand=(band_opt.size()>iband)?band_opt[iband]:iband;
665 cout <<
"extracting band " << readBand << endl;
666 pfnProgress(progress,pszMessage,pProgressArg);
670 if(autoscale_opt.size()){
672 imgReader.getMinMax(static_cast<int>(startCol),static_cast<int>(endCol),static_cast<int>(startRow),static_cast<int>(endRow),readBand,theMin,theMax);
674 catch(
string errorString){
675 cout << errorString << endl;
678 cout <<
"minmax: " << theMin <<
", " << theMax << endl;
679 double theScale=(autoscale_opt[1]-autoscale_opt[0])/(theMax-theMin);
680 double theOffset=autoscale_opt[0]-theScale*theMin;
681 imgReader.setScale(theScale,readBand);
682 imgReader.setOffset(theOffset,readBand);
685 if(scale_opt.size()){
686 if(scale_opt.size()>iband)
687 imgReader.setScale(scale_opt[iband],readBand);
689 imgReader.setScale(scale_opt[0],readBand);
691 if(offset_opt.size()){
692 if(offset_opt.size()>iband)
693 imgReader.setOffset(offset_opt[iband],readBand);
695 imgReader.setOffset(offset_opt[0],readBand);
703 for(
int irow=0;irow<imgWriter.nrOfRow();++irow){
704 vector<float> lineMask;
708 imgWriter.image2geo(0,irow,x,y);
710 imgReader.geo2image(x,y,readCol,readRow);
711 vector<double> writeBuffer;
712 if(readRow<0||readRow>=imgReader.nrOfRow()){
717 for(
int icol=0;icol<imgWriter.nrOfCol();++icol)
718 writeBuffer.push_back(nodataValue);
722 cout <<
"reading row: " << readRow << endl;
724 if(endCol<imgReader.nrOfCol()-1)
725 imgReader.readData(readBuffer,GDT_Float64,startCol,endCol+1,readRow,readBand,theResample);
727 imgReader.readData(readBuffer,GDT_Float64,startCol,endCol,readRow,readBand,theResample);
729 double oldRowMask=-1;
730 for(
int icol=0;icol<imgWriter.nrOfCol();++icol){
731 imgWriter.image2geo(icol,irow,x,y);
733 imgReader.geo2image(x,y,readCol,readRow);
734 if(readCol<0||readCol>=imgReader.nrOfCol()){
740 writeBuffer.push_back(nodataValue);
751 imgWriter.image2geo(icol,irow,geox,geoy);
752 maskReader.geo2image(geox,geoy,colMask,rowMask);
753 colMask=
static_cast<int>(colMask);
754 rowMask=
static_cast<int>(rowMask);
755 if(rowMask>=0&&rowMask<maskReader.nrOfRow()&&colMask>=0&&colMask<maskReader.nrOfCol()){
756 if(static_cast<int>(rowMask)!=
static_cast<int>(oldRowMask)){
758 assert(rowMask>=0&&rowMask<maskReader.nrOfRow());
760 maskReader.readData(lineMask,GDT_Float32,static_cast<int>(rowMask),mskband_opt[0]);
762 catch(
string errorstring){
763 cerr << errorstring << endl;
767 cerr <<
"error caught" << std::endl;
772 if(lineMask[colMask]==msknodata_opt[0])
778 writeBuffer.push_back(nodataValue);
782 lowerCol=readCol-0.5;
783 lowerCol=
static_cast<int>(lowerCol);
784 upperCol=readCol+0.5;
785 upperCol=
static_cast<int>(upperCol);
788 if(upperCol>=imgReader.nrOfCol())
789 upperCol=imgReader.nrOfCol()-1;
791 writeBuffer.push_back((readCol-0.5-lowerCol)*readBuffer[upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[lowerCol-startCol]);
794 readCol=
static_cast<int>(readCol);
797 writeBuffer.push_back(readBuffer[readCol]);
804 catch(
string errorstring){
805 cout << errorstring << endl;
809 if(writeBuffer.size()!=imgWriter.nrOfCol())
810 cout <<
"writeBuffer.size()=" << writeBuffer.size() <<
", imgWriter.nrOfCol()=" << imgWriter.nrOfCol() << endl;
811 assert(writeBuffer.size()==imgWriter.nrOfCol());
813 imgWriter.writeData(writeBuffer,GDT_Float64,irow,writeBand);
815 catch(
string errorstring){
816 cout << errorstring << endl;
821 progress/=imgWriter.nrOfRow();
822 pfnProgress(progress,pszMessage,pProgressArg);
826 progress+=(imgWriter.nrOfRow()*writeBand);
827 progress/=imgWriter.nrOfBand()*imgWriter.nrOfRow();
830 pfnProgress(progress,pszMessage,pProgressArg);
837 if(extent_opt.size()&&cut_opt.size()){
838 extentReader.close();