337 lines
12 KiB
C
337 lines
12 KiB
C
/******************************************************************************
|
|
*
|
|
* Project: GDAL Utilities
|
|
* Purpose: GDAL mask flattening utility
|
|
* Author: Even Rouault, <even dot rouault at spatialys.com>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
****************************************************************************/
|
|
|
|
#include "gdal.h"
|
|
#include "cpl_conv.h"
|
|
#include "cpl_string.h"
|
|
|
|
/************************************************************************/
|
|
/* Usage() */
|
|
/************************************************************************/
|
|
|
|
static void Usage()
|
|
{
|
|
printf("Usage: gdalflattenmask [--help] [--help-general] [-of "
|
|
"<output_format>] \n"
|
|
" [-co <NAME>=<VALUE>]... [-set_alpha] "
|
|
"[-a_nodata <val>] \n"
|
|
" <srcdatasetname> <dstdatasetname>\n"
|
|
"\n"
|
|
"This utility is intended to produce a new file that merges regular "
|
|
"data\n"
|
|
"bands with the mask bands, for applications not being able to use "
|
|
"the mask band concept.\n"
|
|
"* If -set_alpha is not specified, this utility will use the mask "
|
|
"band(s)\n"
|
|
" to create a new dataset with empty values where the mask has "
|
|
"null values.\n"
|
|
"* If -set_alpha is specified, a new alpha band is added to the "
|
|
"destination\n"
|
|
" dataset with the content of the global dataset mask band.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* main() */
|
|
/************************************************************************/
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
const char *pszFormat = "GTiff";
|
|
const char *pszSrcFilename = NULL;
|
|
const char *pszDstFilename = NULL;
|
|
int i;
|
|
int nBands, nXSize, nYSize;
|
|
GDALDriverH hDriver;
|
|
GDALDatasetH hSrcDS;
|
|
GDALDatasetH hDstDS;
|
|
char **papszCreateOptions = NULL;
|
|
int bSetNoData = FALSE;
|
|
double dfDstNoData = 0;
|
|
int bSetAlpha = FALSE;
|
|
double adfGeoTransform[6];
|
|
const char *pszProjectionRef;
|
|
GByte *pabyMaskBuffer;
|
|
char **papszMetadata;
|
|
|
|
GDALAllRegister();
|
|
|
|
argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
|
|
if (argc < 1)
|
|
exit(-argc);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Parse arguments. */
|
|
/* -------------------------------------------------------------------- */
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (EQUAL(argv[i], "-of") && i + 1 < argc)
|
|
{
|
|
pszFormat = argv[++i];
|
|
}
|
|
else if (EQUAL(argv[i], "--help"))
|
|
{
|
|
Usage();
|
|
}
|
|
else if (EQUAL(argv[i], "-co") && i < argc - 1)
|
|
{
|
|
papszCreateOptions = CSLAddString(papszCreateOptions, argv[++i]);
|
|
}
|
|
else if (EQUAL(argv[i], "-a_nodata") && i < argc - 1)
|
|
{
|
|
bSetNoData = TRUE;
|
|
dfDstNoData = CPLAtof(argv[++i]);
|
|
}
|
|
else if (EQUAL(argv[i], "-set_alpha"))
|
|
{
|
|
bSetAlpha = TRUE;
|
|
}
|
|
else if (argv[i][0] == '-')
|
|
Usage();
|
|
else if (pszSrcFilename == NULL)
|
|
pszSrcFilename = argv[i];
|
|
else if (pszDstFilename == NULL)
|
|
pszDstFilename = argv[i];
|
|
else
|
|
Usage();
|
|
}
|
|
|
|
if (pszSrcFilename == NULL || pszDstFilename == NULL)
|
|
Usage();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Open source dataset */
|
|
/* -------------------------------------------------------------------- */
|
|
hSrcDS = GDALOpen(pszSrcFilename, GA_ReadOnly);
|
|
if (hSrcDS == NULL)
|
|
{
|
|
fprintf(stderr, "Can't open %s\n", pszSrcFilename);
|
|
exit(1);
|
|
}
|
|
|
|
nBands = GDALGetRasterCount(hSrcDS);
|
|
nXSize = GDALGetRasterXSize(hSrcDS);
|
|
nYSize = GDALGetRasterYSize(hSrcDS);
|
|
|
|
for (i = 0; i < nBands; i++)
|
|
{
|
|
GDALRasterBandH hSrcBand = GDALGetRasterBand(hSrcDS, i + 1);
|
|
GDALDataType eDataType = GDALGetRasterDataType(hSrcBand);
|
|
|
|
if (bSetAlpha)
|
|
{
|
|
if (nBands > 1 &&
|
|
(GDALGetMaskFlags(hSrcBand) & GMF_PER_DATASET) == 0)
|
|
{
|
|
fprintf(stderr,
|
|
"When -set_alpha is specified, all source bands must "
|
|
"share the same mask band (PER_DATASET mask)\n");
|
|
exit(1);
|
|
}
|
|
if (GDALGetRasterColorInterpretation(hSrcBand) == GCI_AlphaBand)
|
|
{
|
|
fprintf(stderr,
|
|
"The source dataset has already an alpha band\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (eDataType != GDT_Byte)
|
|
{
|
|
fprintf(stderr,
|
|
"Only GDT_Byte type supported for source dataset\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create destination dataset */
|
|
/* -------------------------------------------------------------------- */
|
|
hDriver = GDALGetDriverByName(pszFormat);
|
|
if (hDriver == NULL)
|
|
{
|
|
fprintf(stderr, "Can't find driver %s\n", pszFormat);
|
|
exit(1);
|
|
}
|
|
|
|
hDstDS = GDALCreate(hDriver, pszDstFilename, nXSize, nYSize,
|
|
nBands + ((bSetAlpha) ? 1 : 0), GDT_Byte,
|
|
papszCreateOptions);
|
|
if (hDstDS == NULL)
|
|
{
|
|
fprintf(stderr, "Can't create %s\n", pszDstFilename);
|
|
exit(1);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write geotransform, projection, color interpretations, no data */
|
|
/* values, color tables, metadata, etc. before the file is */
|
|
/* crystallized. */
|
|
/* -------------------------------------------------------------------- */
|
|
if (GDALGetGeoTransform(hSrcDS, adfGeoTransform) == CE_None)
|
|
{
|
|
GDALSetGeoTransform(hDstDS, adfGeoTransform);
|
|
}
|
|
|
|
pszProjectionRef = GDALGetProjectionRef(hSrcDS);
|
|
if (pszProjectionRef && pszProjectionRef[0])
|
|
{
|
|
GDALSetProjection(hDstDS, pszProjectionRef);
|
|
}
|
|
|
|
if (bSetAlpha)
|
|
{
|
|
GDALRasterBandH hDstAlphaBand = GDALGetRasterBand(hDstDS, nBands + 1);
|
|
GDALSetRasterColorInterpretation(hDstAlphaBand, GCI_AlphaBand);
|
|
}
|
|
|
|
papszMetadata = GDALGetMetadata(hSrcDS, NULL);
|
|
GDALSetMetadata(hDstDS, papszMetadata, NULL);
|
|
|
|
for (i = 0; i < nBands; i++)
|
|
{
|
|
GDALRasterBandH hSrcBand, hDstBand;
|
|
GDALColorTableH hColorTable;
|
|
GDALColorInterp eColorInterpretation;
|
|
int bHasNoData;
|
|
double dfNoDataValue;
|
|
|
|
hSrcBand = GDALGetRasterBand(hSrcDS, i + 1);
|
|
hDstBand = GDALGetRasterBand(hDstDS, i + 1);
|
|
|
|
dfNoDataValue = GDALGetRasterNoDataValue(hSrcBand, &bHasNoData);
|
|
if (!bHasNoData)
|
|
dfNoDataValue = dfDstNoData;
|
|
if (!bSetAlpha && (bHasNoData || bSetNoData))
|
|
GDALSetRasterNoDataValue(hDstBand, dfNoDataValue);
|
|
|
|
hColorTable = GDALGetRasterColorTable(hSrcBand);
|
|
if (hColorTable)
|
|
{
|
|
GDALSetRasterColorTable(hDstBand, hColorTable);
|
|
}
|
|
|
|
papszMetadata = GDALGetMetadata(hSrcBand, NULL);
|
|
GDALSetMetadata(hDstBand, papszMetadata, NULL);
|
|
|
|
eColorInterpretation = GDALGetRasterColorInterpretation(hSrcBand);
|
|
GDALSetRasterColorInterpretation(hDstBand, eColorInterpretation);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write the data values now */
|
|
/* -------------------------------------------------------------------- */
|
|
pabyMaskBuffer = (GByte *)CPLMalloc(nXSize);
|
|
|
|
for (i = 0; i < nBands; i++)
|
|
{
|
|
GDALRasterBandH hSrcBand, hDstBand, hMaskBand;
|
|
GDALDataType eDataType;
|
|
GByte *pabyBuffer;
|
|
int iCol, iLine;
|
|
int bHasNoData;
|
|
double dfNoDataValue;
|
|
int nMaskFlag;
|
|
|
|
hSrcBand = GDALGetRasterBand(hSrcDS, i + 1);
|
|
hDstBand = GDALGetRasterBand(hDstDS, i + 1);
|
|
hMaskBand = GDALGetMaskBand(hSrcBand);
|
|
nMaskFlag = GDALGetMaskFlags(hSrcBand);
|
|
|
|
eDataType = GDALGetRasterDataType(hSrcBand);
|
|
pabyBuffer =
|
|
(GByte *)CPLMalloc(nXSize * GDALGetDataTypeSize(eDataType));
|
|
dfNoDataValue = GDALGetRasterNoDataValue(hSrcBand, &bHasNoData);
|
|
if (!bHasNoData)
|
|
dfNoDataValue = dfDstNoData;
|
|
|
|
for (iLine = 0; iLine < nYSize; iLine++)
|
|
{
|
|
GDALRasterIO(hSrcBand, GF_Read, 0, iLine, nXSize, 1, pabyBuffer,
|
|
nXSize, 1, eDataType, 0, 0);
|
|
if (!bSetAlpha)
|
|
{
|
|
GDALRasterIO(hMaskBand, GF_Read, 0, iLine, nXSize, 1,
|
|
pabyMaskBuffer, nXSize, 1, GDT_Byte, 0, 0);
|
|
switch (eDataType)
|
|
{
|
|
case GDT_Byte:
|
|
{
|
|
for (iCol = 0; iCol < nXSize; iCol++)
|
|
{
|
|
/* If the mask is 1-bit and the value is 0,
|
|
or if the mask is 8-bit and the value < 128,
|
|
then replace the value of the pixel by the
|
|
transparent value */
|
|
if (pabyMaskBuffer[iCol] == 0 ||
|
|
((nMaskFlag & GMF_ALPHA) != 0 &&
|
|
pabyMaskBuffer[iCol] < 128))
|
|
pabyBuffer[iCol] = (GByte)dfNoDataValue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
CPLAssert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
GDALRasterIO(hDstBand, GF_Write, 0, iLine, nXSize, 1, pabyBuffer,
|
|
nXSize, 1, eDataType, 0, 0);
|
|
}
|
|
|
|
CPLFree(pabyBuffer);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the alpha band if -set_alpha is specified */
|
|
/* -------------------------------------------------------------------- */
|
|
if (bSetAlpha)
|
|
{
|
|
GDALRasterBandH hSrcBand = GDALGetRasterBand(hSrcDS, 1);
|
|
GDALRasterBandH hDstAlphaBand = GDALGetRasterBand(hDstDS, nBands + 1);
|
|
GDALRasterBandH hMaskBand = GDALGetMaskBand(hSrcBand);
|
|
int nMaskFlag = GDALGetMaskFlags(hSrcBand);
|
|
|
|
int iCol;
|
|
int iLine;
|
|
for (iLine = 0; iLine < nYSize; iLine++)
|
|
{
|
|
GDALRasterIO(hMaskBand, GF_Read, 0, iLine, nXSize, 1,
|
|
pabyMaskBuffer, nXSize, 1, GDT_Byte, 0, 0);
|
|
for (iCol = 0; iCol < nXSize; iCol++)
|
|
{
|
|
/* If the mask is 1-bit, expand 1 to 255 */
|
|
if (pabyMaskBuffer[iCol] == 1 && (nMaskFlag & GMF_ALPHA) == 0)
|
|
pabyMaskBuffer[iCol] = 255;
|
|
}
|
|
GDALRasterIO(hDstAlphaBand, GF_Write, 0, iLine, nXSize, 1,
|
|
pabyMaskBuffer, nXSize, 1, GDT_Byte, 0, 0);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Cleanup */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLFree(pabyMaskBuffer);
|
|
|
|
GDALClose(hSrcDS);
|
|
GDALClose(hDstDS);
|
|
GDALDumpOpenDatasets(stderr);
|
|
GDALDestroyDriverManager();
|
|
CSLDestroy(argv);
|
|
CSLDestroy(papszCreateOptions);
|
|
|
|
return 0;
|
|
}
|