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 12 : int IsInt( const char *pszArg )
52 : {
53 12 : if( pszArg[0] == '-' )
54 0 : pszArg++;
55 :
56 12 : if( *pszArg == '\0' )
57 0 : return FALSE;
58 :
59 48 : while( *pszArg != '\0' )
60 : {
61 24 : if( *pszArg < '0' || *pszArg > '9' )
62 0 : return FALSE;
63 24 : pszArg++;
64 : }
65 :
66 12 : 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 16 : 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 16 : 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 16 : GDALAllRegister();
100 16 : GDALSetCacheMax( 100000000 );
101 16 : argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
102 16 : if( argc < 1 )
103 0 : exit( -argc );
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Parse arguments. */
107 : /* -------------------------------------------------------------------- */
108 : int i;
109 16 : const char *pszOutFile = NULL;
110 16 : const char *pszInFile = NULL;
111 16 : int nMaxNonBlack = 2;
112 16 : int nNearDist = 15;
113 16 : int bNearWhite = FALSE;
114 16 : int bSetAlpha = FALSE;
115 16 : int bSetMask = FALSE;
116 16 : const char* pszDriverName = "HFA";
117 16 : int bFormatExplicitelySet = FALSE;
118 16 : char** papszCreationOptions = NULL;
119 16 : int bQuiet = FALSE;
120 :
121 16 : Colors oColors;
122 :
123 88 : for( i = 1; i < argc; i++ )
124 : {
125 74 : if( EQUAL(argv[i], "--utility_version") )
126 : {
127 : printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
128 2 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
129 2 : return 0;
130 : }
131 82 : else if( EQUAL(argv[i], "-o") && i < argc-1 )
132 10 : pszOutFile = argv[++i];
133 76 : else if( EQUAL(argv[i], "-of") && i < argc-1 )
134 : {
135 14 : pszDriverName = argv[++i];
136 14 : bFormatExplicitelySet = TRUE;
137 : }
138 48 : else if( EQUAL(argv[i], "-white") ) {
139 2 : bNearWhite = TRUE;
140 : }
141 :
142 : /***** -color c1,c2,c3...cn *****/
143 :
144 50 : else if( EQUAL(argv[i], "-color") && i < argc-1 ) {
145 4 : Color oColor;
146 :
147 : /***** tokenize the arg on , *****/
148 :
149 : char **papszTokens;
150 4 : papszTokens = CSLTokenizeString2( argv[++i], ",", 0 );
151 :
152 : /***** loop over the tokens *****/
153 :
154 : int iToken;
155 32 : for( iToken = 0; papszTokens && papszTokens[iToken]; iToken++ )
156 : {
157 :
158 : /***** ensure the token is an int and add it to the color *****/
159 :
160 12 : if ( IsInt( papszTokens[iToken] ) )
161 12 : 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 4 : CSLDestroy( papszTokens );
171 :
172 : /***** check if the number of bands is consistant *****/
173 :
174 4 : 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 4 : oColors.push_back( oColor );
185 :
186 : }
187 :
188 54 : else if( EQUAL(argv[i], "-nb") && i < argc-1 )
189 12 : nMaxNonBlack = atoi(argv[++i]);
190 30 : else if( EQUAL(argv[i], "-near") && i < argc-1 )
191 0 : nNearDist = atoi(argv[++i]);
192 30 : else if( EQUAL(argv[i], "-setalpha") )
193 6 : bSetAlpha = TRUE;
194 24 : else if( EQUAL(argv[i], "-setmask") )
195 4 : bSetMask = TRUE;
196 22 : else if( EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet") )
197 2 : bQuiet = TRUE;
198 22 : else if( EQUAL(argv[i], "-co") && i < argc-1 )
199 4 : papszCreationOptions = CSLAddString(papszCreationOptions, argv[++i]);
200 14 : else if( argv[i][0] == '-' )
201 0 : Usage();
202 14 : else if( pszInFile == NULL )
203 14 : pszInFile = argv[i];
204 : else
205 0 : Usage();
206 : }
207 :
208 14 : if( pszInFile == NULL )
209 0 : Usage();
210 :
211 14 : if( pszOutFile == NULL )
212 4 : pszOutFile = pszInFile;
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Open input file. */
216 : /* -------------------------------------------------------------------- */
217 14 : GDALDatasetH hInDS, hOutDS = NULL;
218 : int nXSize, nYSize, nBands;
219 :
220 14 : if( pszOutFile == pszInFile )
221 4 : hInDS = hOutDS = GDALOpen( pszInFile, GA_Update );
222 : else
223 10 : hInDS = GDALOpen( pszInFile, GA_ReadOnly );
224 :
225 14 : if( hInDS == NULL )
226 0 : exit( 1 );
227 :
228 14 : nXSize = GDALGetRasterXSize( hInDS );
229 14 : nYSize = GDALGetRasterYSize( hInDS );
230 14 : nBands = GDALGetRasterCount( hInDS );
231 14 : int nDstBands = nBands;
232 :
233 14 : 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 14 : if( hOutDS == NULL )
243 : {
244 10 : GDALDriverH hDriver = GDALGetDriverByName( pszDriverName );
245 10 : if (hDriver == NULL)
246 0 : exit(1);
247 :
248 10 : if (!bQuiet && !bFormatExplicitelySet)
249 0 : CheckExtensionConsistency(pszOutFile, pszDriverName);
250 :
251 10 : if (bSetAlpha)
252 : {
253 : /***** fixme there should be a way to preserve alpha band data not in the collar *****/
254 4 : if (nBands == 4)
255 0 : nBands --;
256 : else
257 4 : nDstBands ++;
258 : }
259 :
260 10 : if (bSetMask)
261 : {
262 2 : if (nBands == 4)
263 0 : nDstBands = nBands = 3;
264 : }
265 :
266 : hOutDS = GDALCreate( hDriver, pszOutFile,
267 : nXSize, nYSize, nDstBands, GDT_Byte,
268 10 : papszCreationOptions );
269 10 : if( hOutDS == NULL )
270 0 : exit( 1 );
271 :
272 : double adfGeoTransform[6];
273 :
274 10 : if( GDALGetGeoTransform( hInDS, adfGeoTransform ) == CE_None )
275 : {
276 8 : GDALSetGeoTransform( hOutDS, adfGeoTransform );
277 8 : GDALSetProjection( hOutDS, GDALGetProjectionRef( hInDS ) );
278 : }
279 : }
280 : else
281 : {
282 4 : if (bSetAlpha)
283 : {
284 2 : 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 2 : nBands --;
294 : }
295 :
296 4 : if (bSetMask)
297 : {
298 2 : if (nBands == 4)
299 0 : nDstBands = nBands = 3;
300 : }
301 : }
302 :
303 : /***** set a color if there are no colors set? *****/
304 :
305 14 : if ( oColors.size() == 0) {
306 12 : Color oColor;
307 :
308 : /***** loop over the bands to get the right number of values *****/
309 :
310 : int iBand;
311 48 : for (iBand = 0; iBand < nBands ; iBand++) {
312 :
313 : /***** black or white? *****/
314 :
315 36 : if (bNearWhite)
316 6 : oColor.push_back(255);
317 : else
318 30 : oColor.push_back(0);
319 : }
320 :
321 : /***** add the color to the colors *****/
322 :
323 12 : oColors.push_back(oColor);
324 :
325 : }
326 :
327 : /***** does the number of bands match the number of color values? *****/
328 :
329 14 : 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 14 : 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 56 : for( iBand = 0; iBand < nBands; iBand++ )
349 : {
350 42 : GDALRasterBandH hBand = GDALGetRasterBand(hInDS, iBand+1);
351 42 : 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 42 : 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 14 : GDALRasterBandH hMaskBand = NULL;
365 :
366 14 : if (bSetMask) {
367 :
368 : /***** if there isn't already a mask band on the output file create one *****/
369 :
370 4 : if ( GMF_PER_DATASET != GDALGetMaskFlags( GDALGetRasterBand(hOutDS, 1) ) )
371 : {
372 :
373 2 : 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 4 : if (bSetMask) {
381 4 : hMaskBand = GDALGetMaskBand(GDALGetRasterBand(hOutDS, 1));
382 : }
383 : }
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Allocate a line buffer. */
387 : /* -------------------------------------------------------------------- */
388 : GByte *pabyLine;
389 14 : GByte *pabyMask=NULL;
390 :
391 : int *panLastLineCounts;
392 :
393 14 : pabyLine = (GByte *) CPLMalloc(nXSize * nDstBands);
394 :
395 14 : if (bSetMask)
396 4 : pabyMask = (GByte *) CPLMalloc(nXSize);
397 :
398 14 : panLastLineCounts = (int *) CPLCalloc(sizeof(int),nXSize);
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Processing data one line at a time. */
402 : /* -------------------------------------------------------------------- */
403 : int iLine;
404 :
405 714 : 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 700 : nBands, NULL, nDstBands, nXSize * nDstBands, 1 );
412 700 : if( eErr != CE_None )
413 0 : break;
414 :
415 700 : if (bSetAlpha)
416 : {
417 : int iCol;
418 15300 : for(iCol = 0; iCol < nXSize; iCol ++)
419 : {
420 15000 : pabyLine[iCol * nDstBands + nDstBands - 1] = 255;
421 : }
422 : }
423 :
424 700 : if (bSetMask)
425 : {
426 : int iCol;
427 10200 : for(iCol = 0; iCol < nXSize; iCol ++)
428 : {
429 10000 : 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 700 : );
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 700 : );
447 :
448 : eErr = GDALDatasetRasterIO( hOutDS, GF_Write, 0, iLine, nXSize, 1,
449 : pabyLine, nXSize, 1, GDT_Byte,
450 700 : nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
451 :
452 700 : if( eErr != CE_None )
453 0 : break;
454 :
455 : /***** write out the mask band line *****/
456 :
457 700 : if (bSetMask) {
458 :
459 : eErr = GDALRasterIO ( hMaskBand, GF_Write, 0, iLine, nXSize, 1,
460 : pabyMask, nXSize, 1, GDT_Byte,
461 200 : 0, 0 );
462 :
463 200 : 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 700 : if (!bQuiet)
471 600 : GDALTermProgress( 0.5 * ((iLine+1) / (double) nYSize), NULL, NULL );
472 : }
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Now process from the bottom back up .*/
476 : /* -------------------------------------------------------------------- */
477 14 : memset( panLastLineCounts, 0, sizeof(int) * nXSize);
478 :
479 714 : 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 700 : nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
486 700 : if( eErr != CE_None )
487 0 : break;
488 :
489 : /***** read the mask band line back in *****/
490 :
491 700 : if (bSetMask) {
492 :
493 : eErr = GDALRasterIO ( hMaskBand, GF_Read, 0, iLine, nXSize, 1,
494 : pabyMask, nXSize, 1, GDT_Byte,
495 200 : 0, 0 );
496 :
497 :
498 200 : 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 700 : );
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 700 : );
517 :
518 : eErr = GDALDatasetRasterIO( hOutDS, GF_Write, 0, iLine, nXSize, 1,
519 : pabyLine, nXSize, 1, GDT_Byte,
520 700 : nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
521 700 : if( eErr != CE_None )
522 0 : break;
523 :
524 : /***** write out the mask band line *****/
525 :
526 700 : if (bSetMask) {
527 :
528 : eErr = GDALRasterIO ( hMaskBand, GF_Write, 0, iLine, nXSize, 1,
529 : pabyMask, nXSize, 1, GDT_Byte,
530 200 : 0, 0 );
531 :
532 :
533 200 : if( eErr != CE_None )
534 0 : break;
535 : }
536 :
537 :
538 700 : if (!bQuiet)
539 : GDALTermProgress( 0.5 + 0.5 * (nYSize-iLine) / (double) nYSize,
540 600 : NULL, NULL );
541 : }
542 :
543 14 : CPLFree(pabyLine);
544 14 : if (bSetMask)
545 4 : CPLFree(pabyMask);
546 :
547 14 : CPLFree( panLastLineCounts );
548 :
549 14 : GDALClose( hOutDS );
550 14 : if( hInDS != hOutDS )
551 10 : GDALClose( hInDS );
552 14 : GDALDumpOpenDatasets( stderr );
553 14 : CSLDestroy( argv );
554 14 : CSLDestroy( papszCreationOptions );
555 14 : GDALDestroyDriverManager();
556 :
557 14 : return 0;
558 : }
559 :
560 : /************************************************************************/
561 : /* ProcessLine() */
562 : /* */
563 : /* Process a single scanline of image data. */
564 : /************************************************************************/
565 :
566 2800 : 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 2800 : GByte nReplacevalue = 0;
574 2800 : if( bNearWhite )
575 400 : nReplacevalue = 255;
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* Vertical checking. */
579 : /* -------------------------------------------------------------------- */
580 :
581 2800 : if( bDoVerticalCheck )
582 : {
583 1400 : int nXSize = MAX(iStart+1,iEnd+1);
584 :
585 71400 : for( i = 0; i < nXSize; i++ )
586 : {
587 :
588 : // are we already terminated for this column?
589 :
590 70000 : if( panLastLineCounts[i] > nMaxNonBlack )
591 48974 : continue;
592 :
593 : /***** is the pixel valid data? ****/
594 :
595 21026 : int bIsNonBlack = FALSE;
596 :
597 : /***** loop over the colors *****/
598 :
599 : int iColor;
600 21026 : for (iColor = 0; iColor < (int)poColors->size(); iColor++) {
601 :
602 24122 : Color oColor = (*poColors)[iColor];
603 :
604 24122 : bIsNonBlack = FALSE;
605 :
606 : /***** loop over the bands *****/
607 :
608 : int iBand;
609 83862 : for( iBand = 0; iBand < nSrcBands; iBand++ )
610 : {
611 64004 : int nPix = pabyLine[i * nDstBands + iBand];
612 :
613 64004 : if( oColor[iBand] - nPix > nNearDist ||
614 : nPix > nNearDist + oColor[iBand] )
615 : {
616 4264 : bIsNonBlack = TRUE;
617 4264 : break;
618 : }
619 : }
620 :
621 24122 : if (bIsNonBlack == FALSE)
622 : break;
623 : }
624 :
625 21026 : if (bIsNonBlack) {
626 1168 : panLastLineCounts[i]++;
627 :
628 1168 : if( panLastLineCounts[i] > nMaxNonBlack )
629 1104 : 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 79688 : for( iBand = 0; iBand < nSrcBands; iBand++ )
638 59766 : pabyLine[i * nDstBands + iBand] = nReplacevalue;
639 :
640 : /***** alpha *****/
641 :
642 19922 : if( nDstBands > nSrcBands )
643 4914 : pabyLine[i * nDstBands + nDstBands - 1] = 0;
644 :
645 : /***** mask *****/
646 :
647 19922 : if (pabyMask != NULL)
648 3936 : pabyMask[i] = 0;
649 : }
650 : }
651 :
652 : /* -------------------------------------------------------------------- */
653 : /* Horizontal Checking. */
654 : /* -------------------------------------------------------------------- */
655 :
656 2800 : if( bDoHorizontalCheck )
657 : {
658 2800 : int nNonBlackPixels = 0;
659 :
660 : /***** on a bottom up pass assume nMaxNonBlack is 0 *****/
661 :
662 2800 : if (bBottomUp)
663 1400 : nMaxNonBlack = 0;
664 :
665 2800 : if( iStart < iEnd )
666 1400 : iDir = 1;
667 : else
668 1400 : iDir = -1;
669 2800 : int bDoTest = TRUE;
670 :
671 140000 : for( i = iStart; i != iEnd; i += iDir )
672 : {
673 :
674 : /***** not seen any valid data? *****/
675 :
676 137200 : if ( bDoTest ) {
677 :
678 : /***** is the pixel valid data? ****/
679 :
680 46002 : int bIsNonBlack = FALSE;
681 :
682 : /***** loop over the colors *****/
683 :
684 : int iColor;
685 46002 : for (iColor = 0; iColor < (int)poColors->size(); iColor++) {
686 :
687 46322 : Color oColor = (*poColors)[iColor];
688 :
689 46322 : bIsNonBlack = FALSE;
690 :
691 : /***** loop over the bands *****/
692 :
693 : int iBand;
694 176666 : for( iBand = 0; iBand < nSrcBands; iBand++ )
695 : {
696 133328 : int nPix = pabyLine[i * nDstBands + iBand];
697 :
698 133328 : if( oColor[iBand] - nPix > nNearDist ||
699 : nPix > nNearDist + oColor[iBand] )
700 : {
701 2984 : bIsNonBlack = TRUE;
702 2984 : break;
703 : }
704 : }
705 :
706 46322 : if (bIsNonBlack == FALSE)
707 : break;
708 : }
709 :
710 46002 : if (bIsNonBlack) {
711 :
712 : /***** use nNonBlackPixels in grey areas *****/
713 : /***** from the verical pass's grey areas ****/
714 :
715 2664 : if( panLastLineCounts[i] <= nMaxNonBlack )
716 0 : nNonBlackPixels = panLastLineCounts[i];
717 : else
718 2664 : nNonBlackPixels++;
719 : }
720 :
721 46002 : if( nNonBlackPixels > nMaxNonBlack ) {
722 2600 : bDoTest = FALSE;
723 2600 : continue;
724 : }
725 :
726 : /***** replace the pixel values *****/
727 :
728 : int iBand;
729 173608 : for( iBand = 0; iBand < nSrcBands; iBand++ )
730 130206 : pabyLine[i * nDstBands + iBand] = nReplacevalue;
731 :
732 : /***** alpha *****/
733 :
734 43402 : if( nDstBands > nSrcBands )
735 11172 : pabyLine[i * nDstBands + nDstBands - 1] = 0;
736 :
737 : /***** mask *****/
738 :
739 43402 : if (pabyMask != NULL)
740 8724 : pabyMask[i] = 0;
741 : }
742 :
743 : /***** seen valid data but test if the *****/
744 : /***** vertical pass saw any non valid data *****/
745 :
746 91198 : else if( panLastLineCounts[i] == 0 ) {
747 1400 : bDoTest = TRUE;
748 1400 : nNonBlackPixels = 0;
749 : }
750 : }
751 : }
752 :
753 2800 : }
754 :
|