void import_radarsat2(const char *inBaseName, radiometry_t radiometry, const char *outBaseName, int ampOnly) { FILE *fp; radarsat2_meta *radarsat2; meta_parameters *meta; char **inDataNames=NULL, inDataName[1024], *inMetaName=NULL; char *outDataName=NULL, str[512]; float *amp = NULL, *phase = NULL, *tmp = NULL, re, im; int band, sample; // Check radiometry if (radiometry != r_AMP) { asfPrintWarning("Radiometry other than AMPLITUDE is currently not " "supported.\n"); radiometry = r_AMP; } if (!fileExists(inBaseName)) inMetaName = appendExt(inBaseName, ".xml"); else { inMetaName = (char *) MALLOC(sizeof(char)*1024); strcpy(inMetaName, inBaseName); } outDataName = appendExt(outBaseName, ".img"); radarsat2 = read_radarsat2_meta(inMetaName); asfPrintStatus(" DataType: %s, ProductType: %s\n", radarsat2->dataType, radarsat2->productType); if (strcmp_case(radarsat2->dataType, "COMPLEX") != 0) asfPrintError("Currently only complex data supported!\n"); meta = radarsat2meta(radarsat2); meta_write(meta, outDataName); // Let's check the GeoTIFF data. // Unfortunately, there is no identifier in the GeoTIFF that would identify // the data as Radarsat-2 data. // // The only thing that we can actually do is to look whether the data in the // GeoTIFF file fit the general bill. We can the image dimensions. The data // needs to have 2 bands (I and Q) and 16 bit. The citation geokey needs to // be the really non-descriptive "Uncorrected Satellite Data". TIFF *tiff = NULL; GTIF *gtif = NULL; data_type_t data_type; short sample_format, bits_per_sample, planar_config; short num_bands; int is_scanline_format, is_palette_color_tiff, wrong=FALSE; char *error_message = (char *) MALLOC(sizeof(char)*2048); inDataNames = extract_band_names(meta->general->basename, meta->general->band_count); fp = FOPEN(outDataName, "wb"); int band_count = radarsat2->band_count; if (ampOnly) { strcpy(meta->general->bands, "AMP"); meta->general->band_count = 1; band_count = 1; } for (band=0; band<band_count; band++) { // path from the xml (metadata) file char *path = get_dirname(inBaseName); if (strlen(path)>0) { strcpy(inDataName, path); if (inDataName[strlen(inDataName)-1] != '/') strcat(inDataName, "/"); } else strcpy(inDataName, ""); free(path); strcat(inDataName, inDataNames[band]); tiff = XTIFFOpen(inDataName, "r"); if (!tiff) asfPrintError("Could not open data file (%s)\n", inDataName); gtif = GTIFNew(tiff); if (!gtif) asfPrintError("Could not read GeoTIFF keys from data file (%s)\n", inDataName); // Check image dimensions uint32 tif_sample_count; uint32 tif_line_count; TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &tif_line_count); TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &tif_sample_count); if ((meta->general->sample_count != tif_sample_count) || (meta->general->line_count != tif_line_count)) asfPrintError(error_message, "Problem with image dimensions. Was looking for %d lines " "and %d samples.\nFound %ld lines and %ld samples instead!" "\n", meta->general->line_count, meta->general->sample_count, tif_line_count, tif_sample_count); // Check general TIFF tags get_tiff_data_config(tiff, &sample_format, &bits_per_sample, &planar_config, &data_type, &num_bands, &is_scanline_format, &is_palette_color_tiff, REPORT_LEVEL_WARNING); // The specs say the data is supposed to be unsigned but it is not. // Let is pass as long as we are talking about integer data here strcpy(error_message, ""); if (sample_format != SAMPLEFORMAT_UINT && sample_format != SAMPLEFORMAT_INT) { strcat(error_message, "Problem with sampling format. Was looking for integer, "); if (sample_format == SAMPLEFORMAT_COMPLEXIEEEFP) strcat(error_message, "found complex floating point instead!\n"); else if (sample_format == SAMPLEFORMAT_COMPLEXINT) strcat(error_message, "found complex integer instead!\n"); else if (sample_format == SAMPLEFORMAT_IEEEFP) strcat(error_message, "found floating point instead!\n"); else if (sample_format == SAMPLEFORMAT_VOID) strcat(error_message, "found void instead!\n"); wrong = TRUE; } if (bits_per_sample != 16) { sprintf(str, "Problem with bits per sample. Was looking for 16, found %d " "instead!\n", bits_per_sample); strcat(error_message, str); wrong = TRUE; } if (data_type != INTEGER16) { strcat(error_message, "Problem with data type. Was looking INTEGER16, "); if (data_type == ASF_BYTE) strcat(error_message, "found BYTE instead!\n"); else if (data_type == INTEGER32) strcat(error_message, "found INTEGER32 instead!\n"); else if (data_type == REAL32) strcat(error_message, "found REAL32 instead!\n"); else if (data_type == REAL64) strcat(error_message, "found REAL64 instead!\n"); else if (data_type == COMPLEX_BYTE) strcat(error_message, "found COMPLEX_BYTE instead!\n"); else if (data_type == COMPLEX_INTEGER16) strcat(error_message, "found COMPLEX_INTEGER16 instead!\n"); else if (data_type == COMPLEX_INTEGER32) strcat(error_message, "found COMPLEX_INTEGER32 instead!\n"); else if (data_type == COMPLEX_REAL32) strcat(error_message, "found COMPLEX_REAL32 instead!\n"); else if (data_type == COMPLEX_REAL64) strcat(error_message, "found COMPLEX_REAL64 instead!\n"); wrong = TRUE; } if (num_bands != 2) { sprintf(str, "Problem with number of bands. Was looking for 2, " "found %d instead!\n", num_bands); strcat(error_message, str); wrong = TRUE; } if (wrong) asfPrintError(error_message); // Check GTCitationGeoKey char *citation = NULL; int citation_length, typeSize; tagtype_t citation_type; citation_length = GTIFKeyInfo(gtif, GTCitationGeoKey, &typeSize, &citation_type); if (citation_length > 0) { citation = (char *) MALLOC(citation_length * typeSize); GTIFKeyGet(gtif, GTCitationGeoKey, citation, 0, citation_length); if (citation && strcmp_case(citation, "UNCORRECTED SATELLITE DATA") != 0) { asfPrintError("Problem with GTCitationGeoKey. Was looking for " "'Uncorrected Satellite Data',\nfound '%s' instead!\n", citation); } } else asfPrintError("Problem with GTCitationGeoKey. Was looking for " "'Uncorrected Satellite Data',\ndid not find any key!\n"); tiff_type_t tiffInfo; get_tiff_type(tiff, &tiffInfo); if (tiffInfo.format != SCANLINE_TIFF && tiffInfo.format != STRIP_TIFF && tiffInfo.format != TILED_TIFF) asfPrintError("Can't read the GeoTIFF file (%s). Unrecognized TIFF " "type!\n", inDataNames[band]); // If we made it here, we are reasonably sure that we have the file that // we are looking for. asfPrintStatus("\n Importing %s ...\n", inDataNames[band]); uint32 scanlineSize = TIFFScanlineSize(tiff); tdata_t *tiff_real_buf = _TIFFmalloc(scanlineSize); tdata_t *tiff_imag_buf = _TIFFmalloc(scanlineSize); if (!tiff_real_buf || !tiff_imag_buf) asfPrintError("Can't allocate buffer for reading TIFF lines!\n"); amp = (float *) MALLOC(sizeof(float)*meta->general->sample_count); phase = (float *) MALLOC(sizeof(float)*meta->general->sample_count); // Check whether we need to flip the image in any fashion int flip_vertical = FALSE; if (strcmp_case(radarsat2->lineTimeOrdering, "DECREASING") == 0) { asfPrintStatus(" Data will be flipped vertically while ingesting!\n"); flip_vertical = TRUE; } int flip_horizontal = FALSE; if (strcmp_case(radarsat2->pixelTimeOrdering, "DECREASING") == 0) { asfPrintStatus(" Data will be flipped horizontally while ingesting!\n"); flip_horizontal = TRUE; } if (flip_horizontal) tmp = (float *) MALLOC(sizeof(float)*meta->general->sample_count); // FIXME: still need to implement flipping vertically // Read file line by line uint32 row; int sample_count = meta->general->sample_count; int line_count = meta->general->line_count; for (row=0; row<(uint32)meta->general->line_count; row++) { asfLineMeter(row, meta->general->line_count); if (flip_vertical) { switch (tiffInfo.format) { case SCANLINE_TIFF: TIFFReadScanline(tiff, tiff_real_buf, line_count-row-1, 0); TIFFReadScanline(tiff, tiff_imag_buf, line_count-row-1, 1); break; case STRIP_TIFF: ReadScanline_from_TIFF_Strip(tiff, tiff_real_buf, line_count-row-1, 0); ReadScanline_from_TIFF_Strip(tiff, tiff_imag_buf, line_count-row-1, 1); break; case TILED_TIFF: ReadScanline_from_TIFF_TileRow(tiff, tiff_real_buf, line_count-row-1, 0); ReadScanline_from_TIFF_TileRow(tiff, tiff_imag_buf, line_count-row-1, 1); break; default: asfPrintError("Can't read this TIFF format!\n"); break; } } else { switch (tiffInfo.format) { case SCANLINE_TIFF: TIFFReadScanline(tiff, tiff_real_buf, row, 0); TIFFReadScanline(tiff, tiff_imag_buf, row, 1); break; case STRIP_TIFF: ReadScanline_from_TIFF_Strip(tiff, tiff_real_buf, row, 0); ReadScanline_from_TIFF_Strip(tiff, tiff_imag_buf, row, 1); break; case TILED_TIFF: ReadScanline_from_TIFF_TileRow(tiff, tiff_real_buf, row, 0); ReadScanline_from_TIFF_TileRow(tiff, tiff_imag_buf, row, 1); break; default: asfPrintError("Can't read this TIFF format!\n"); break; } } for (sample=0; sample<sample_count; sample++) { switch (sample_format) { case SAMPLEFORMAT_UINT: re = (float)(((uint16*)tiff_real_buf)[sample]); im = (float)(((uint16*)tiff_imag_buf)[sample]); break; case SAMPLEFORMAT_INT: re = (float)(((int16*)tiff_real_buf)[sample]); im = (float)(((int16*)tiff_imag_buf)[sample]); break; } amp[sample] = sqrt(re*re + im*im); phase[sample] = atan2(im, re); } if (flip_horizontal) { for (sample=0; sample<sample_count; sample++) tmp[sample] = amp[sample]; for (sample=0; sample<sample_count; sample++) amp[sample] = tmp[sample_count-sample-1]; } put_band_float_line(fp, meta, band*2, (int)row, amp); if (!ampOnly) put_band_float_line(fp, meta, band*2+1, (int)row, phase); } FREE(amp); FREE(phase); if (tmp) FREE(tmp); _TIFFfree(tiff_real_buf); _TIFFfree(tiff_imag_buf); GTIFFree(gtif); XTIFFClose(tiff); } // update the name field with directory name char *path = get_dirname(inBaseName); if (strlen(path)<=0) path = g_get_current_dir(); char *p = path, *q = path; while (q) { if ((q = strchr(p, DIR_SEPARATOR)) != NULL) p = q+1; } sprintf(meta->general->basename, "%s", p); FREE(path); meta_write(meta, outDataName); meta_free(meta); FREE(radarsat2); FCLOSE(fp); }
int get_tiff_data_config(TIFF *tif, short *sample_format, short *bits_per_sample, short *planar_config, data_type_t *data_type, short *num_bands, int *is_scanline_format, int *is_palette_color_tiff, report_level_t report_level) { int ret = 0, read_count; uint16 planarConfiguration = 0; uint16 bitsPerSample = 0; uint16 sampleFormat = 0; uint16 samplesPerPixel = 0; *data_type = -1; *num_bands = 0; /*********************************************************/ /* Read all tags and accept them as-is into the fields */ /*********************************************************/ // Required tag for all images ret = 0; tiff_type_t t; get_tiff_type(tif, &t); *is_scanline_format = (t.format == SCANLINE_TIFF) ? 1 : 0; if (t.format != SCANLINE_TIFF && t.format != STRIP_TIFF && t.format != TILED_TIFF) { ret = -1; } read_count = TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); if (read_count) *bits_per_sample = bitsPerSample; read_count += TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleFormat); if (read_count < 2 && (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32)) { asfReport(report_level, "Found missing or invalid sample format. Should be unsigned integer,\n" "integer, or IEEE floating point.\n"); switch (bitsPerSample) { case 8: asfReport(report_level, "Data is 8-bit data ...guessing unsigned integer sample\n" "format and attempting to continue.\n"); sampleFormat = SAMPLEFORMAT_UINT; read_count++; break; case 16: asfReport(report_level, "Data is 16-bit data ...guessing signed integer sample\n" "format and attempting to continue.\n"); sampleFormat = SAMPLEFORMAT_INT; read_count++; break; case 32: asfReport(report_level, "Data is 32-bit data ...guessing IEEE floating point sample\n" "format and attempting to continue.\n"); sampleFormat = SAMPLEFORMAT_IEEEFP; read_count++; break; default: ret = -1; break; } } if (read_count == 2) { *sample_format = sampleFormat; switch (sampleFormat) { case SAMPLEFORMAT_UINT: { switch (bitsPerSample) { case 8: *data_type = BYTE; break; case 16: *data_type = INTEGER32; break; case 32: *data_type = REAL32; break; default: *data_type = 0; break; } } break; case SAMPLEFORMAT_INT: { switch (bitsPerSample) { case 8: case 16: *data_type = INTEGER16; break; case 32: *data_type = INTEGER32; break; default: *data_type = 0; break; } } break; case SAMPLEFORMAT_IEEEFP: { *data_type = REAL32; } break; default: { switch (bitsPerSample) { case 8: // Most likely unsigned 8-bit byte *data_type = BYTE; break; case 16: // Most likely 16-bit integer *data_type = INTEGER16; break; case 32: // Most likely 32-bot float *data_type = REAL32; break; default: *data_type = 0; break; } } break; } } read_count = TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); if (read_count != 1) { samplesPerPixel = 0; } unsigned short *maps[3]; read_count = TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2); *is_palette_color_tiff = 0; if (read_count) { if (samplesPerPixel == 1) { *is_palette_color_tiff = 1; } // NOTE: Do not free the colormaps ...this results in a glib double-free error // when closing the tiff file. } read_count = TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarConfiguration); if (read_count) *planar_config = planarConfiguration; /*********************************************************/ /* Determine health */ /*********************************************************/ if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) { // Only support byte, integer16, integer32, and 32-bit floats ret = -1; } else { *num_bands = samplesPerPixel; } if (sampleFormat != SAMPLEFORMAT_UINT && sampleFormat != SAMPLEFORMAT_INT && sampleFormat != SAMPLEFORMAT_IEEEFP) { ret = -1; } if (samplesPerPixel < 1 || samplesPerPixel > MAX_BANDS) { // Only support 1 through MAX_BANDS bands in the image ret = -1; } if (samplesPerPixel > 1 && planarConfiguration != PLANARCONFIG_CONTIG && planarConfiguration != PLANARCONFIG_SEPARATE) { ret = -1; } // Required tag only for color (multi-band) images if (ret == 0 && samplesPerPixel > 1) { if (planarConfiguration != PLANARCONFIG_CONTIG && planarConfiguration != PLANARCONFIG_SEPARATE) { ret = guess_planar_configuration(tif, planar_config); if (ret == 0) { asfReport(report_level, "Found multi-band TIFF but the planar configuration TIFF tag\n" "is not populated ...GUESSING the planar configuration to be %s\n" "based on calculated scanline lengths for interlaced and band-sequential\n" "TIFFs v. the actual scanline length derived from the TIFF file itself.\n", (*planar_config == PLANARCONFIG_CONTIG) ? "Contiguous Planes (interlaced)" : (*planar_config == PLANARCONFIG_SEPARATE) ? "Separate Planes (band-sequential)" : "Unknown Planar Config (?)"); } } } return ret; }
int read_tiff(const char *filename, int *nlines, int *nsamps, unsigned char **data) { TIFF *tiff = XTIFFOpen(filename, "r"); if (!tiff) { return FALSE; } uint32 width; uint32 height; TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width); *nlines = (int)height; *nsamps = (int)width; unsigned char *dest = CALLOC(width*height*3, sizeof(unsigned char)); data_type_t data_type; tiff_data_config_t data_config; int num_bands, is_scanline_format, is_palette_color_tiff; uint32 row; // Determine what type of TIFF this is (scanline/strip/tiled) if (get_tiff_data_config(tiff, &data_config.sample_format, &data_config.bits_per_sample, &data_config.planar_config, &data_type, &data_config.samples_per_pixel, &is_scanline_format, &is_palette_color_tiff, REPORT_LEVEL_NONE)) { return FALSE; } num_bands = data_config.samples_per_pixel; tiff_type_t tiffInfo; get_tiff_type(tiff, &tiffInfo); if (tiffInfo.imageCount > 1) { ; // Only first image in multi-image files will be utilized - WARN the user here? } if (tiffInfo.imageCount < 1) { // TIFF contains zero images ...fail return FALSE; } if (tiffInfo.format != SCANLINE_TIFF && tiffInfo.format != STRIP_TIFF && tiffInfo.format != TILED_TIFF) { // Unrecognized TIFF type return FALSE; } if (tiffInfo.volume_tiff) { // 3-dimensional (a 'volume tiff') found ...this is unsupported return FALSE; } if (num_bands > 1 && data_config.planar_config != PLANARCONFIG_CONTIG && data_config.planar_config != PLANARCONFIG_SEPARATE) { // Invalid planar configuration setting found in TIFF file... return FALSE; } uint32 scanlineSize = TIFFScanlineSize(tiff); if (scanlineSize <= 0) { // Invalid scanline size found in TIFF file... return FALSE; } if (data_config.bits_per_sample != 8) return FALSE; int is_rgb = data_config.samples_per_pixel >= 3; // Populate the buffer with actual data if (is_rgb) { // TIFF read buffer (red band) tdata_t *rtif_buf = _TIFFmalloc(scanlineSize); // TIFF read buffer (green band) tdata_t *gtif_buf = _TIFFmalloc(scanlineSize); // TIFF read buffer (blue band) tdata_t *btif_buf = _TIFFmalloc(scanlineSize); if (!rtif_buf || !gtif_buf || !btif_buf) return FALSE; for (row=0; row < height; row++) { // Read a scanline and populate r, g, and b tiff buffers // NOTE: Empty bands will have the no_data value populated in the //tiff buffer read_tiff_rgb_scanline(tiff, tiffInfo.format, &data_config, row, scanlineSize, width, 0, 1, 2, rtif_buf, gtif_buf, btif_buf); // Interleave the rgb values into an rgb buffer interleave_byte_rgbScanlines_to_byte_buff(dest, rtif_buf, gtif_buf, btif_buf, 0, 1, 2, row, width, &data_config); } _TIFFfree(rtif_buf); _TIFFfree(gtif_buf); _TIFFfree(btif_buf); } else { // is greyscale // TIFF read buffer (interleaved bands) tdata_t *tif_buf = _TIFFmalloc(scanlineSize); if (!tif_buf) return FALSE; for (row=0; row < height; row++) { // Read a scanline into a tiff buffer (using first non-blank band as // the greyscale image) // NOTE: Since displaying a greyscale band specifically selects a band, // empty or not, the selected band is read as-is. read_tiff_greyscale_scanline(tiff, tiffInfo.format, &data_config, row, scanlineSize, width, 0, tif_buf); copy_byte_scanline_to_byte_buff(dest, tif_buf, row, width, &data_config); } _TIFFfree(tif_buf); } *data = dest; return TRUE; }