1 : /******************************************************************************
2 : * $Id: nearblack.cpp 22783 2011-07-23 19:28:16Z rouault $
3 : *
4 : * Project: GDAL Utilities
5 : * Purpose: Convert nearly black or nearly white border to exact black/white.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : * ****************************************************************************
9 : * Copyright (c) 2006, MapShots Inc (www.mapshots.com)
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include <vector>
34 : #include "commonutils.h"
35 :
36 : CPL_CVSID("$Id: nearblack.cpp 22783 2011-07-23 19:28:16Z rouault $");
37 :
38 : typedef std::vector<int> Color;
39 : typedef std::vector< Color > Colors;
40 :
41 : static void ProcessLine( GByte *pabyLine, GByte *pabyMask, int iStart,
42 : int iEnd, int nSrcBands, int nDstBands, int nNearDist,
43 : int nMaxNonBlack, int bNearWhite, Colors *poColors,
44 : int *panLastLineCounts, int bDoHorizontalCheck,
45 : int bDoVerticalCheck, int bBottomUp);
46 :
47 : /************************************************************************/
48 : /* IsInt() */
49 : /************************************************************************/
50 :
51 6 : int IsInt( const char *pszArg )
52 : {
53 6 : if( pszArg[0] == '-' )
54 0 : pszArg++;
55 :
56 6 : if( *pszArg == '\0' )
57 0 : return FALSE;
58 :
59 24 : while( *pszArg != '\0' )
60 : {
61 12 : if( *pszArg < '0' || *pszArg > '9' )
62 0 : return FALSE;
63 12 : pszArg++;
64 : }
65 :
66 6 : return TRUE;
67 : }
68 :
69 : /************************************************************************/
70 : /* Usage() */
71 : /************************************************************************/
72 :
73 0 : void Usage()
74 : {
75 : printf( "nearblack [-of format] [-white | [-color c1,c2,c3...cn]*] [-near dist] [-nb non_black_pixels]\n"
76 0 : " [-setalpha] [-setmask] [-o outfile] [-q] [-co \"NAME=VALUE\"]* infile\n" );
77 0 : exit( 1 );
78 : }
79 :
80 : /************************************************************************/
81 : /* main() */
82 : /************************************************************************/
83 :
84 8 : int main( int argc, char ** argv )
85 :
86 : {
87 : /* Check that we are running against at least GDAL 1.4 (probably older in fact !) */
88 : /* Note to developers : if we use newer API, please change the requirement */
89 8 : if (atoi(GDALVersionInfo("VERSION_NUM")) < 1400)
90 : {
91 : fprintf(stderr, "At least, GDAL >= 1.4.0 is required for this version of %s, "
92 0 : "which was compiled against GDAL %s\n", argv[0], GDAL_RELEASE_NAME);
93 0 : exit(1);
94 : }
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* Generic arg processing. */
98 : /* -------------------------------------------------------------------- */
99 8 : GDALAllRegister();
100 8 : GDALSetCacheMax( 100000000 );
101 8 : argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
102 8 : if( argc < 1 )
103 0 : exit( -argc );
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Parse arguments. */
107 : /* -------------------------------------------------------------------- */
108 : int i;
109 8 : const char *pszOutFile = NULL;
110 8 : const char *pszInFile = NULL;
111 8 : int nMaxNonBlack = 2;
112 8 : int nNearDist = 15;
113 8 : int bNearWhite = FALSE;
114 8 : int bSetAlpha = FALSE;
115 8 : int bSetMask = FALSE;
116 8 : const char* pszDriverName = "HFA";
117 8 : int bFormatExplicitelySet = FALSE;
118 8 : char** papszCreationOptions = NULL;
119 8 : int bQuiet = FALSE;
120 :
121 8 : Colors oColors;
122 :
123 44 : for( i = 1; i < argc; i++ )
124 : {
125 37 : if( EQUAL(argv[i], "--utility_version") )
126 : {
127 : printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
128 1 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
129 1 : return 0;
130 : }
131 41 : else if( EQUAL(argv[i], "-o") && i < argc-1 )
132 5 : pszOutFile = argv[++i];
133 38 : else if( EQUAL(argv[i], "-of") && i < argc-1 )
134 : {
135 7 : pszDriverName = argv[++i];
136 7 : bFormatExplicitelySet = TRUE;
137 : }
138 24 : else if( EQUAL(argv[i], "-white") ) {
139 1 : bNearWhite = TRUE;
140 : }
141 :
142 : /***** -color c1,c2,c3...cn *****/
143 :
144 25 : else if( EQUAL(argv[i], "-color") && i < argc-1 ) {
145 2 : Color oColor;
146 :
147 : /***** tokenize the arg on , *****/
148 :
149 : char **papszTokens;
150 2 : papszTokens = CSLTokenizeString2( argv[++i], ",", 0 );
151 :
152 : /***** loop over the tokens *****/
153 :
154 : int iToken;
155 16 : for( iToken = 0; papszTokens && papszTokens[iToken]; iToken++ )
156 : {
157 :
158 : /***** ensure the token is an int and add it to the color *****/
159 :
160 6 : if ( IsInt( papszTokens[iToken] ) )
161 6 : oColor.push_back( atoi( papszTokens[iToken] ) );
162 : else {
163 : CPLError(CE_Failure, CPLE_AppDefined,
164 0 : "Colors must be valid integers." );
165 0 : CSLDestroy( papszTokens );
166 0 : exit(1);
167 : }
168 : }
169 :
170 2 : CSLDestroy( papszTokens );
171 :
172 : /***** check if the number of bands is consistant *****/
173 :
174 2 : if ( oColors.size() > 0 &&
175 : oColors.front().size() != oColor.size() )
176 : {
177 : CPLError(CE_Failure, CPLE_AppDefined,
178 0 : "ERROR: all -color args must have the same number of values.\n" );
179 0 : exit(1);
180 : }
181 :
182 : /***** add the color to the colors *****/
183 :
184 2 : oColors.push_back( oColor );
185 :
186 : }
187 :
188 27 : else if( EQUAL(argv[i], "-nb") && i < argc-1 )
189 6 : nMaxNonBlack = atoi(argv[++i]);
190 15 : else if( EQUAL(argv[i], "-near") && i < argc-1 )
191 0 : nNearDist = atoi(argv[++i]);
192 15 : else if( EQUAL(argv[i], "-setalpha") )
193 3 : bSetAlpha = TRUE;
194 12 : else if( EQUAL(argv[i], "-setmask") )
195 2 : bSetMask = TRUE;
196 11 : else if( EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet") )
197 1 : bQuiet = TRUE;
198 11 : else if( EQUAL(argv[i], "-co") && i < argc-1 )
199 2 : papszCreationOptions = CSLAddString(papszCreationOptions, argv[++i]);
200 7 : else if( argv[i][0] == '-' )
201 0 : Usage();
202 7 : else if( pszInFile == NULL )
203 7 : pszInFile = argv[i];
204 : else
205 0 : Usage();
206 : }
207 :
208 7 : if( pszInFile == NULL )
209 0 : Usage();
210 :
211 7 : if( pszOutFile == NULL )
212 2 : pszOutFile = pszInFile;
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Open input file. */
216 : /* -------------------------------------------------------------------- */
217 7 : GDALDatasetH hInDS, hOutDS = NULL;
218 : int nXSize, nYSize, nBands;
219 :
220 7 : if( pszOutFile == pszInFile )
221 2 : hInDS = hOutDS = GDALOpen( pszInFile, GA_Update );
222 : else
223 5 : hInDS = GDALOpen( pszInFile, GA_ReadOnly );
224 :
225 7 : if( hInDS == NULL )
226 0 : exit( 1 );
227 :
228 7 : nXSize = GDALGetRasterXSize( hInDS );
229 7 : nYSize = GDALGetRasterYSize( hInDS );
230 7 : nBands = GDALGetRasterCount( hInDS );
231 7 : int nDstBands = nBands;
232 :
233 7 : if( hOutDS != NULL && papszCreationOptions != NULL)
234 : {
235 : CPLError(CE_Warning, CPLE_AppDefined,
236 0 : "Warning: creation options are ignored when writing to an existing file.");
237 : }
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Do we need to create output file? */
241 : /* -------------------------------------------------------------------- */
242 7 : if( hOutDS == NULL )
243 : {
244 5 : GDALDriverH hDriver = GDALGetDriverByName( pszDriverName );
245 5 : if (hDriver == NULL)
246 0 : exit(1);
247 :
248 5 : if (!bQuiet && !bFormatExplicitelySet)
249 0 : CheckExtensionConsistency(pszOutFile, pszDriverName);
250 :
251 5 : if (bSetAlpha)
252 : {
253 : /***** fixme there should be a way to preserve alpha band data not in the collar *****/
254 2 : if (nBands == 4)
255 0 : nBands --;
256 : else
257 2 : nDstBands ++;
258 : }
259 :
260 5 : if (bSetMask)
261 : {
262 1 : if (nBands == 4)
263 0 : nDstBands = nBands = 3;
264 : }
265 :
266 : hOutDS = GDALCreate( hDriver, pszOutFile,
267 : nXSize, nYSize, nDstBands, GDT_Byte,
268 5 : papszCreationOptions );
269 5 : if( hOutDS == NULL )
270 0 : exit( 1 );
271 :
272 : double adfGeoTransform[6];
273 :
274 5 : if( GDALGetGeoTransform( hInDS, adfGeoTransform ) == CE_None )
275 : {
276 4 : GDALSetGeoTransform( hOutDS, adfGeoTransform );
277 4 : GDALSetProjection( hOutDS, GDALGetProjectionRef( hInDS ) );
278 : }
279 : }
280 : else
281 : {
282 2 : if (bSetAlpha)
283 : {
284 1 : if (nBands != 4 &&
285 : (nBands < 2 ||
286 : GDALGetRasterColorInterpretation(GDALGetRasterBand(hOutDS, nBands)) != GCI_AlphaBand))
287 : {
288 : CPLError(CE_Failure, CPLE_AppDefined,
289 0 : "Last band is not an alpha band.");
290 0 : exit(1);
291 : }
292 :
293 1 : nBands --;
294 : }
295 :
296 2 : if (bSetMask)
297 : {
298 1 : if (nBands == 4)
299 0 : nDstBands = nBands = 3;
300 : }
301 : }
302 :
303 : /***** set a color if there are no colors set? *****/
304 :
305 7 : if ( oColors.size() == 0) {
306 6 : Color oColor;
307 :
308 : /***** loop over the bands to get the right number of values *****/
309 :
310 : int iBand;
311 24 : for (iBand = 0; iBand < nBands ; iBand++) {
312 :
313 : /***** black or white? *****/
314 :
315 18 : if (bNearWhite)
316 3 : oColor.push_back(255);
317 : else
318 15 : oColor.push_back(0);
319 : }
320 :
321 : /***** add the color to the colors *****/
322 :
323 6 : oColors.push_back(oColor);
324 :
325 : }
326 :
327 : /***** does the number of bands match the number of color values? *****/
328 :
329 7 : if ( (int)oColors.front().size() != nBands ) {
330 : CPLError( CE_Failure, CPLE_AppDefined,
331 0 : "-color args must have the same number of values as the non alpha input band count.\n" );
332 0 : exit(1);
333 : }
334 :
335 : /***** check the input and output datasets are the same size *****/
336 :
337 7 : if (GDALGetRasterXSize(hOutDS) != nXSize ||
338 : GDALGetRasterYSize(hOutDS) != nYSize)
339 : {
340 : CPLError(CE_Failure, CPLE_AppDefined,
341 : "The dimensions of the output dataset don't match "
342 0 : "the dimensions of the input dataset.");
343 0 : exit(1);
344 : }
345 :
346 :
347 : int iBand;
348 28 : for( iBand = 0; iBand < nBands; iBand++ )
349 : {
350 21 : GDALRasterBandH hBand = GDALGetRasterBand(hInDS, iBand+1);
351 21 : if (GDALGetRasterDataType(hBand) != GDT_Byte)
352 : {
353 : CPLError(CE_Warning, CPLE_AppDefined,
354 0 : "Band %d is not of type GDT_Byte. It can lead to unexpected results.", iBand+1);
355 : }
356 21 : if (GDALGetRasterColorTable(hBand) != NULL)
357 : {
358 : CPLError(CE_Warning, CPLE_AppDefined,
359 : "Band %d has a color table, which is ignored by nearblack. "
360 0 : "It can lead to unexpected results.", iBand+1);
361 : }
362 : }
363 :
364 7 : GDALRasterBandH hMaskBand = NULL;
365 :
366 7 : if (bSetMask) {
367 :
368 : /***** if there isn't already a mask band on the output file create one *****/
369 :
370 2 : if ( GMF_PER_DATASET != GDALGetMaskFlags( GDALGetRasterBand(hOutDS, 1) ) )
371 : {
372 :
373 1 : if ( CE_None != GDALCreateDatasetMaskBand(hOutDS, GMF_PER_DATASET) ) {
374 : CPLError(CE_Failure, CPLE_AppDefined,
375 0 : "Failed to create mask band on output DS");
376 0 : bSetMask = FALSE;
377 : }
378 : }
379 :
380 2 : if (bSetMask) {
381 2 : hMaskBand = GDALGetMaskBand(GDALGetRasterBand(hOutDS, 1));
382 : }
383 : }
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Allocate a line buffer. */
387 : /* -------------------------------------------------------------------- */
388 : GByte *pabyLine;
389 7 : GByte *pabyMask=NULL;
390 :
391 : int *panLastLineCounts;
392 :
393 7 : pabyLine = (GByte *) CPLMalloc(nXSize * nDstBands);
394 :
395 7 : if (bSetMask)
396 2 : pabyMask = (GByte *) CPLMalloc(nXSize);
397 :
398 7 : panLastLineCounts = (int *) CPLCalloc(sizeof(int),nXSize);
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Processing data one line at a time. */
402 : /* -------------------------------------------------------------------- */
403 : int iLine;
404 :
405 357 : for( iLine = 0; iLine < nYSize; iLine++ )
406 : {
407 : CPLErr eErr;
408 :
409 : eErr = GDALDatasetRasterIO( hInDS, GF_Read, 0, iLine, nXSize, 1,
410 : pabyLine, nXSize, 1, GDT_Byte,
411 350 : nBands, NULL, nDstBands, nXSize * nDstBands, 1 );
412 350 : if( eErr != CE_None )
413 0 : break;
414 :
415 350 : if (bSetAlpha)
416 : {
417 : int iCol;
418 7650 : for(iCol = 0; iCol < nXSize; iCol ++)
419 : {
420 7500 : pabyLine[iCol * nDstBands + nDstBands - 1] = 255;
421 : }
422 : }
423 :
424 350 : if (bSetMask)
425 : {
426 : int iCol;
427 5100 : for(iCol = 0; iCol < nXSize; iCol ++)
428 : {
429 5000 : pabyMask[iCol] = 255;
430 : }
431 : }
432 :
433 : ProcessLine( pabyLine, pabyMask, 0, nXSize-1, nBands, nDstBands,
434 : nNearDist, nMaxNonBlack, bNearWhite, &oColors,
435 : panLastLineCounts,
436 : TRUE, // bDoHorizontalCheck
437 : TRUE, // bDoVerticalCheck
438 : FALSE // bBottomUp
439 350 : );
440 : ProcessLine( pabyLine, pabyMask, nXSize-1, 0, nBands, nDstBands,
441 : nNearDist, nMaxNonBlack, bNearWhite, &oColors,
442 : panLastLineCounts,
443 : TRUE, // bDoHorizontalCheck
444 : FALSE, // bDoVerticalCheck
445 : FALSE // bBottomUp
446 350 : );
447 :
448 : eErr = GDALDatasetRasterIO( hOutDS, GF_Write, 0, iLine, nXSize, 1,
449 : pabyLine, nXSize, 1, GDT_Byte,
450 350 : nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
451 :
452 350 : if( eErr != CE_None )
453 0 : break;
454 :
455 : /***** write out the mask band line *****/
456 :
457 350 : if (bSetMask) {
458 :
459 : eErr = GDALRasterIO ( hMaskBand, GF_Write, 0, iLine, nXSize, 1,
460 : pabyMask, nXSize, 1, GDT_Byte,
461 100 : 0, 0 );
462 :
463 100 : if( eErr != CE_None ) {
464 : CPLError(CE_Warning, CPLE_AppDefined,
465 0 : "ERROR writeing out line to mask band.");
466 0 : break;
467 : }
468 : }
469 :
470 350 : if (!bQuiet)
471 300 : GDALTermProgress( 0.5 * ((iLine+1) / (double) nYSize), NULL, NULL );
472 : }
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Now process from the bottom back up .*/
476 : /* -------------------------------------------------------------------- */
477 7 : memset( panLastLineCounts, 0, sizeof(int) * nXSize);
478 :
479 357 : for( iLine = nYSize-1; iLine >= 0; iLine-- )
480 : {
481 : CPLErr eErr;
482 :
483 : eErr = GDALDatasetRasterIO( hOutDS, GF_Read, 0, iLine, nXSize, 1,
484 : pabyLine, nXSize, 1, GDT_Byte,
485 350 : nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
486 350 : if( eErr != CE_None )
487 0 : break;
488 :
489 : /***** read the mask band line back in *****/
490 :
491 350 : if (bSetMask) {
492 :
493 : eErr = GDALRasterIO ( hMaskBand, GF_Read, 0, iLine, nXSize, 1,
494 : pabyMask, nXSize, 1, GDT_Byte,
495 100 : 0, 0 );
496 :
497 :
498 100 : if( eErr != CE_None )
499 0 : break;
500 : }
501 :
502 :
503 : ProcessLine( pabyLine, pabyMask, 0, nXSize-1, nBands, nDstBands,
504 : nNearDist, nMaxNonBlack, bNearWhite, &oColors,
505 : panLastLineCounts,
506 : TRUE, // bDoHorizontalCheck
507 : TRUE, // bDoVerticalCheck
508 : TRUE // bBottomUp
509 350 : );
510 : ProcessLine( pabyLine, pabyMask, nXSize-1, 0, nBands, nDstBands,
511 : nNearDist, nMaxNonBlack, bNearWhite, &oColors,
512 : panLastLineCounts,
513 : TRUE, // bDoHorizontalCheck
514 : FALSE, // bDoVerticalCheck
515 : TRUE // bBottomUp
516 350 : );
517 :
518 : eErr = GDALDatasetRasterIO( hOutDS, GF_Write, 0, iLine, nXSize, 1,
519 : pabyLine, nXSize, 1, GDT_Byte,
520 350 : nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
521 350 : if( eErr != CE_None )
522 0 : break;
523 :
524 : /***** write out the mask band line *****/
525 :
526 350 : if (bSetMask) {
527 :
528 : eErr = GDALRasterIO ( hMaskBand, GF_Write, 0, iLine, nXSize, 1,
529 : pabyMask, nXSize, 1, GDT_Byte,
530 100 : 0, 0 );
531 :
532 :
533 100 : if( eErr != CE_None )
534 0 : break;
535 : }
536 :
537 :
538 350 : if (!bQuiet)
539 : GDALTermProgress( 0.5 + 0.5 * (nYSize-iLine) / (double) nYSize,
540 300 : NULL, NULL );
541 : }
542 :
543 7 : CPLFree(pabyLine);
544 7 : if (bSetMask)
545 2 : CPLFree(pabyMask);
546 :
547 7 : CPLFree( panLastLineCounts );
548 :
549 7 : GDALClose( hOutDS );
550 7 : if( hInDS != hOutDS )
551 5 : GDALClose( hInDS );
552 7 : GDALDumpOpenDatasets( stderr );
553 7 : CSLDestroy( argv );
554 7 : CSLDestroy( papszCreationOptions );
555 7 : GDALDestroyDriverManager();
556 :
557 7 : return 0;
558 : }
559 :
560 : /************************************************************************/
561 : /* ProcessLine() */
562 : /* */
563 : /* Process a single scanline of image data. */
564 : /************************************************************************/
565 :
566 1400 : static void ProcessLine( GByte *pabyLine, GByte *pabyMask, int iStart,
567 : int iEnd, int nSrcBands, int nDstBands, int nNearDist,
568 : int nMaxNonBlack, int bNearWhite, Colors *poColors,
569 : int *panLastLineCounts, int bDoHorizontalCheck,
570 : int bDoVerticalCheck, int bBottomUp )
571 : {
572 : int iDir, i;
573 1400 : GByte nReplacevalue = 0;
574 1400 : if( bNearWhite )
575 200 : nReplacevalue = 255;
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* Vertical checking. */
579 : /* -------------------------------------------------------------------- */
580 :
581 1400 : if( bDoVerticalCheck )
582 : {
583 700 : int nXSize = MAX(iStart+1,iEnd+1);
584 :
585 35700 : for( i = 0; i < nXSize; i++ )
586 : {
587 :
588 : // are we already terminated for this column?
589 :
590 35000 : if( panLastLineCounts[i] > nMaxNonBlack )
591 24487 : continue;
592 :
593 : /***** is the pixel valid data? ****/
594 :
595 10513 : int bIsNonBlack = FALSE;
596 :
597 : /***** loop over the colors *****/
598 :
599 : int iColor;
600 10513 : for (iColor = 0; iColor < (int)poColors->size(); iColor++) {
601 :
602 12061 : Color oColor = (*poColors)[iColor];
603 :
604 12061 : bIsNonBlack = FALSE;
605 :
606 : /***** loop over the bands *****/
607 :
608 : int iBand;
609 41931 : for( iBand = 0; iBand < nSrcBands; iBand++ )
610 : {
611 32002 : int nPix = pabyLine[i * nDstBands + iBand];
612 :
613 32002 : if( oColor[iBand] - nPix > nNearDist ||
614 : nPix > nNearDist + oColor[iBand] )
615 : {
616 2132 : bIsNonBlack = TRUE;
617 2132 : break;
618 : }
619 : }
620 :
621 12061 : if (bIsNonBlack == FALSE)
622 : break;
623 : }
624 :
625 10513 : if (bIsNonBlack) {
626 584 : panLastLineCounts[i]++;
627 :
628 584 : if( panLastLineCounts[i] > nMaxNonBlack )
629 552 : continue;
630 : }
631 : //else
632 : // panLastLineCounts[i] = 0; // not sure this even makes sense
633 :
634 : /***** replace the pixel values *****/
635 :
636 : int iBand;
637 39844 : for( iBand = 0; iBand < nSrcBands; iBand++ )
638 29883 : pabyLine[i * nDstBands + iBand] = nReplacevalue;
639 :
640 : /***** alpha *****/
641 :
642 9961 : if( nDstBands > nSrcBands )
643 2457 : pabyLine[i * nDstBands + nDstBands - 1] = 0;
644 :
645 : /***** mask *****/
646 :
647 9961 : if (pabyMask != NULL)
648 1968 : pabyMask[i] = 0;
649 : }
650 : }
651 :
652 : /* -------------------------------------------------------------------- */
653 : /* Horizontal Checking. */
654 : /* -------------------------------------------------------------------- */
655 :
656 1400 : if( bDoHorizontalCheck )
657 : {
658 1400 : int nNonBlackPixels = 0;
659 :
660 : /***** on a bottom up pass assume nMaxNonBlack is 0 *****/
661 :
662 1400 : if (bBottomUp)
663 700 : nMaxNonBlack = 0;
664 :
665 1400 : if( iStart < iEnd )
666 700 : iDir = 1;
667 : else
668 700 : iDir = -1;
669 1400 : int bDoTest = TRUE;
670 :
671 70000 : for( i = iStart; i != iEnd; i += iDir )
672 : {
673 :
674 : /***** not seen any valid data? *****/
675 :
676 68600 : if ( bDoTest ) {
677 :
678 : /***** is the pixel valid data? ****/
679 :
680 23001 : int bIsNonBlack = FALSE;
681 :
682 : /***** loop over the colors *****/
683 :
684 : int iColor;
685 23001 : for (iColor = 0; iColor < (int)poColors->size(); iColor++) {
686 :
687 23161 : Color oColor = (*poColors)[iColor];
688 :
689 23161 : bIsNonBlack = FALSE;
690 :
691 : /***** loop over the bands *****/
692 :
693 : int iBand;
694 88333 : for( iBand = 0; iBand < nSrcBands; iBand++ )
695 : {
696 66664 : int nPix = pabyLine[i * nDstBands + iBand];
697 :
698 66664 : if( oColor[iBand] - nPix > nNearDist ||
699 : nPix > nNearDist + oColor[iBand] )
700 : {
701 1492 : bIsNonBlack = TRUE;
702 1492 : break;
703 : }
704 : }
705 :
706 23161 : if (bIsNonBlack == FALSE)
707 : break;
708 : }
709 :
710 23001 : if (bIsNonBlack) {
711 :
712 : /***** use nNonBlackPixels in grey areas *****/
713 : /***** from the verical pass's grey areas ****/
714 :
715 1332 : if( panLastLineCounts[i] <= nMaxNonBlack )
716 0 : nNonBlackPixels = panLastLineCounts[i];
717 : else
718 1332 : nNonBlackPixels++;
719 : }
720 :
721 23001 : if( nNonBlackPixels > nMaxNonBlack ) {
722 1300 : bDoTest = FALSE;
723 1300 : continue;
724 : }
725 :
726 : /***** replace the pixel values *****/
727 :
728 : int iBand;
729 86804 : for( iBand = 0; iBand < nSrcBands; iBand++ )
730 65103 : pabyLine[i * nDstBands + iBand] = nReplacevalue;
731 :
732 : /***** alpha *****/
733 :
734 21701 : if( nDstBands > nSrcBands )
735 5586 : pabyLine[i * nDstBands + nDstBands - 1] = 0;
736 :
737 : /***** mask *****/
738 :
739 21701 : if (pabyMask != NULL)
740 4362 : pabyMask[i] = 0;
741 : }
742 :
743 : /***** seen valid data but test if the *****/
744 : /***** vertical pass saw any non valid data *****/
745 :
746 45599 : else if( panLastLineCounts[i] == 0 ) {
747 700 : bDoTest = TRUE;
748 700 : nNonBlackPixels = 0;
749 : }
750 : }
751 : }
752 :
753 1400 : }
754 :
|