McidasSatelliteDecoder fix for varying PNG header position

This commit is contained in:
mjames-upc 2018-08-22 10:27:51 -06:00
parent a72a68e164
commit 2d37d15171
5 changed files with 142 additions and 179 deletions

View file

@ -83,11 +83,12 @@ import com.raytheon.uf.edex.plugin.satellite.mcidas.util.McidasSatelliteLookups.
* IDataRecord required by the SatelliteDao
* 12/03/2013 DR 16841 D. Friedman Allow record overwrites
* 09/18/2014 3627 mapeters Updated deprecated method calls.
* 05/11/2015 ---- mjames@ucar PS (south and north) stereogrpahic support added.
* 05/19/2015 ---- mjames@ucar Added decoding of GVAR native projection products
* 07/12/2015 ---- mjames@ucar Account for GOES E and W UNIWISC AREA file numbers
* 01/21/2016 ---- mjames@ucar Cleanup
* 10/24/2017 ---- mjames@ucar Native support for PNG-compressed AREA files.
* 05/11/2015 ---- mjames PS (south and north) stereogrpahic support added.
* 05/19/2015 ---- mjames Added decoding of GVAR native projection products
* 07/12/2015 ---- mjames Account for GOES E and W UNIWISC AREA file numbers
* 01/21/2016 ---- mjames Cleanup
* 10/24/2017 ---- mjames Native support for PNG-compressed AREA files.
* 08/14/2018 ---- mjames Find and use position of PNG header.
* </pre>
*
* @author
@ -107,8 +108,6 @@ public class McidasSatelliteDecoder {
private static final int RADIUS = 6371200;
final int SIZE_OF_AREA = 256;
final int PNG_HEADER_LENGTH = 240;
private final byte[] PNG_HDR = { -119, 80, 78, 71 };
@ -156,10 +155,10 @@ public class McidasSatelliteDecoder {
* @throws Exception
*/
private PluginDataObject[] decodeMcidasArea(byte[] data) throws Exception {
byte[] area = null;
byte[] area = new byte[SIZE_OF_AREA];
byte[] nonAreaBlock = new byte[data.length - SIZE_OF_AREA];
area = new byte[SIZE_OF_AREA];
System.arraycopy(data, 0, area, 0, SIZE_OF_AREA);
System.arraycopy(data, SIZE_OF_AREA, nonAreaBlock, 0,
nonAreaBlock.length);
@ -177,77 +176,76 @@ public class McidasSatelliteDecoder {
formatError(UNEXPECTED_HEADER_VALUE);
}
}
int sensorSourceNumber = buf.getInt(); // W3
int yyyddd = buf.getInt(); // W4
int hhmmss = buf.getInt(); // W5
int ulImageLine = buf.getInt(); // W6
int ulImageElement = buf.getInt(); // W7
buf.getInt(); // reserved // W8
int nLines = buf.getInt(); // W9
int nElementsPerLine = buf.getInt(); // W10
int nBytesPerElement = buf.getInt(); // W11
int lineResolution = buf.getInt(); // W12
int elementResolution = buf.getInt(); // W13
int nBands = buf.getInt(); // W14
int linePrefixLength = buf.getInt(); // W15
/* int projectNumber = */buf.getInt(); // W16
/* int creationYyyddd = */buf.getInt(); // W17
/* int creationHhmmss = */buf.getInt(); // W18
int sensorSourceNumber = buf.getInt(); // W3
int yyyddd = buf.getInt(); // W4
int hhmmss = buf.getInt(); // W5
int ulImageLine = buf.getInt(); // W6
int ulImageElement = buf.getInt(); // W7
buf.getInt(); // W8 reserved
int nLines = buf.getInt(); // W9
int nElementsPerLine = buf.getInt(); // W10
int nBytesPerElement = buf.getInt(); // W11
int lineResolution = buf.getInt(); // W12
int elementResolution = buf.getInt(); // W13
int nBands = buf.getInt(); // W14
int linePrefixLength = buf.getInt(); // W15
/* int projectNumber = */buf.getInt(); // W16
/* int creationYyyddd = */buf.getInt(); // W17
/* int creationHhmmss = */buf.getInt(); // W18
/*
* W19
32-bit filter band map for multichannel
images; if a bit is set, data exists for the band;
band 1 is the least significant byte (rightmost)
32-bit filter band map for multichannel
images; if a bit is set, data exists for the band;
band 1 is the least significant byte (rightmost)
*/
int bandMap1to32 = buf.getInt(); // W19
int bandMap1to32 = buf.getInt(); // W19
/*
* W20-24
satellite specific information
satellite specific information
*/
int bandMap33to64 = buf.getInt(); // W20
buf.position(buf.position() + (4 * 4)); // sensor specific
buf.position(buf.position() + (4 * 8)); // memo
int bandMap33to64 = buf.getInt(); // W20
buf.position(buf.position() + (4 * 4)); // sensor specific
buf.position(buf.position() + (4 * 8)); // memo
int areaNumber = buf.getInt();
int dataBlockOffset = buf.getInt();
int navBlockOffset = buf.getInt();
/* int validityCode = */buf.getInt();
buf.position(buf.position() + (8 * 4)); // PDL
buf.getInt(); // GOES AA band 8
buf.position(buf.position() + (8 * 4)); // PDL
buf.getInt(); // GOES AA band 8
/* int imageYyyddd = */buf.getInt();
/* int imageHhmmssOrMillis = */buf.getInt();
/* int imageStartScan = */buf.getInt();
/* int prefixDocLength = */buf.getInt();
int prefixCalibrationLength = buf.getInt(); // W50
/* int prefixBandListLength = */buf.getInt(); // W51
buf.getInt(); // source type // W52
String calType = get4cc(buf); // cal type // W53
buf.position(buf.position() + (3 * 4)); // reserved
/* int originalSourceType = */buf.getInt(); // actually a 4cc?
/* int units = */buf.getInt(); // also 4cc?
int prefixCalibrationLength = buf.getInt(); // W50
/* int prefixBandListLength = */buf.getInt(); // W51
buf.getInt(); // W52 source type
String calType = get4cc(buf); // W53 cal type
buf.position(buf.position() + (3 * 4)); // reserved
/* int originalSourceType = */buf.getInt(); // actually a 4cc?
/* int units = */buf.getInt(); // also 4cc?
/* int scaling = */buf.getInt();
/* int supplementalBlockOffset = */buf.getInt();
buf.getInt(); // reserved
int calibrationOffset = buf.getInt();
buf.getInt(); // comment cards
buf.getInt(); // reserved
int calibrationOffset = buf.getInt(); // W63
int numberOfComments = buf.getInt(); // W64 comment cards
/* Nav block */
int navsize;
if (calibrationOffset == 0){
navsize = dataBlockOffset - navBlockOffset;
navsize = dataBlockOffset - navBlockOffset;
} else {
navsize = calibrationOffset - navBlockOffset;
navsize = calibrationOffset - navBlockOffset;
}
byte[] navigation = new byte[navsize];
System.arraycopy(nonAreaBlock, 0, navigation, 0, navigation.length);
byte[] nonNavBlock = new byte[nonAreaBlock.length - navsize];
System.arraycopy(nonAreaBlock, 0, navigation, 0, navsize);
System.arraycopy(nonAreaBlock, navsize, nonNavBlock, 0, nonNavBlock.length);
byte[] pngBlock = new byte[nonNavBlock.length - PNG_HEADER_LENGTH];
System.arraycopy(nonNavBlock, PNG_HEADER_LENGTH, pngBlock, 0, pngBlock.length);
/* PNG block */
int PNG_HDR_POS = indexOf(nonNavBlock, PNG_HDR);
byte[] pngBlock = new byte[nonNavBlock.length - PNG_HDR_POS];
System.arraycopy(nonNavBlock, PNG_HDR_POS, pngBlock, 0, pngBlock.length);
long bandBits = ((long) bandMap33to64 << 32) | bandMap1to32;
long bandBitsCount = Long.bitCount(bandBits);
@ -279,28 +277,26 @@ public class McidasSatelliteDecoder {
bitIndex + 1);
rec.setPhysicalElement(pev.name);
rec.setUnits(pev.units);
rec.setSectorID(getAreaName(areaNumber));
rec.setSectorID(getAreaName(sensorSourceNumber, areaNumber));
rec.setCoverage(coverage);
// TODO: Line pad if not a multiple of four bytes
if ((linePrefixLength == 0) && (nBytesPerElement == 1)
&& (nBands == 1)) {
if ((linePrefixLength == 0) && (nBytesPerElement == 1) && (nBands == 1)) {
if (isPngCompressed(pngBlock)) {
byte[] pngBytes = decompressPngSatellite(pngBlock);
rec.setMessageData(pngBytes);
} else {
byte[] imageBytes = new byte[nLines * nElementsPerLine];
buf.position(dataBlockOffset);
buf.get(imageBytes);
rec.setMessageData(imageBytes);
}
byte[] pngBytes = decompressPngSatellite(pngBlock);
rec.setMessageData(pngBytes);
} else {
byte[] imageBytes = new byte[nLines * nElementsPerLine];
buf.position(dataBlockOffset);
buf.get(imageBytes);
rec.setMessageData(imageBytes);
}
} else if (nBytesPerElement == 1) {
byte[] imageBytes = new byte[nLines * nElementsPerLine];
int si = dataBlockOffset + (ri * nBytesPerElement);
int di = 0;
int eincr = nBands * nBytesPerElement;
for (int y = 0; y < nLines; ++y) {
si += linePrefixLength;
for (int x = 0; x < nElementsPerLine; ++x) {
@ -316,7 +312,6 @@ public class McidasSatelliteDecoder {
rec.setPersistenceTime(TimeUtil.newGmtCalendar().getTime());
rec.setOverwriteAllowed(true);
// Set the data into the IDataRecord
// Set the data into the IDataRecord
IDataRecord dataRec = SatelliteRecord.getDataRecord(rec);
if (dataRec != null) {
@ -333,10 +328,33 @@ public class McidasSatelliteDecoder {
result = new PluginDataObject[0];
}
}
return result;
}
/**
*
* from guava/guava/src/com/google/common/primitives/Bytes.java
*
* @param array
* @param target
* @return
*/
public static int indexOf(byte[] array, byte[] target) {
if (target.length == 0) {
return 0;
}
outer:
for (int i = 0; i < array.length - target.length + 1; i++) {
for (int j = 0; j < target.length; j++) {
if (array[i + j] != target[j]) {
continue outer;
}
}
return i;
}
return -1;
}
/**
* Method to check if file is PNG-compressed.
*
@ -344,10 +362,10 @@ public class McidasSatelliteDecoder {
* @return
*/
private boolean isPngCompressed(byte[] messageData) {
byte[] buffer = new byte[4];
System.arraycopy(messageData, 0, buffer, 0, buffer.length);
boolean compressed = Arrays.equals(buffer, PNG_HDR);
return compressed;
byte[] buffer = new byte[4];
System.arraycopy(messageData, 0, buffer, 0, buffer.length);
boolean compressed = Arrays.equals(buffer, PNG_HDR);
return compressed;
}
/**
@ -368,9 +386,9 @@ public class McidasSatelliteDecoder {
byte[] inflated = null;
for (int row=0;row< png.getImgInfo().rows;row++){
ImageLineByte line = png.readRowByte();
byte [] buf = line.getScanlineByte();
bos.write(buf, 0, buf.length);
ImageLineByte line = png.readRowByte();
byte [] buf = line.getScanlineByte();
bos.write(buf, 0, buf.length);
}
inflated = bos.toByteArray();
@ -385,7 +403,7 @@ public class McidasSatelliteDecoder {
*/
private SatMapCoverage decodeNavigation(int xImgRes, int yImgRes, int ulX,
int ulY, int nx, int ny, ByteBuffer buf, byte[] navigation)
throws Exception {
throws Exception {
SatMapCoverage result = new SatMapCoverage();
String navType = get4cc(buf);
int lineOfEquator = buf.getInt();
@ -444,9 +462,9 @@ public class McidasSatelliteDecoder {
(float) clat, la1, lo1, la2, lo2);
} else if (navType.trim().equals("PS")) {
dy = (float) spacingAtStdLatInMeters * yImgRes;
double dxp = (1. - rxp) * dx;
dy = (float) spacingAtStdLatInMeters * yImgRes;
double dxp = (1. - rxp) * dx;
double dyp = (1. - ryp) * dy;
double alpha = 1. + Math.sin(Math.abs(phi0r));
double rm = Math.sqrt(((dxp * dxp) + (dyp * dyp))) / alpha;
@ -457,7 +475,7 @@ public class McidasSatelliteDecoder {
thta = (Math.atan2(dxp, dyp)) * RTD;
lo1 = (float) prnlon((clon + thta));
} else {
lo1 = (float) clon;
lo1 = (float) clon;
}
/*
@ -473,17 +491,17 @@ public class McidasSatelliteDecoder {
thta = (Math.atan2(dxp, dyp)) * RTD;
lo2 = (float) prnlon((clon + thta));
} else {
lo2 = (float) clon;
lo2 = (float) clon;
}
result = SatSpatialFactory.getInstance().getCoverageTwoCorners(
SatSpatialFactory.PROJ_POLAR, nx, ny, (float) clon,
(float) clat, la1, lo1, la2, lo2);
} else {
/*
* Native projection
*/
/*
* Native projection
*/
//unimplemented(String.format("navigation type \"%s\"", navType));
clon = nrmlLonDDMMSS / 10000000.f;
clon = (float) Math.toDegrees(clon);
@ -554,24 +572,12 @@ public class McidasSatelliteDecoder {
"Unknown-%d", bandIndex), null);
}
private String getAreaName(int areaNumber) {
// GOES-West UNIWISC McIDAS AREA files
if ( (1161 < areaNumber && areaNumber <= 1254) ||
(1801 <= areaNumber && areaNumber <= 1854) ){
areaNumber = 1161;
// GOES-East UNIWISC McIDAS AREA files
} else if (1261 < areaNumber && areaNumber <= 1524) {
areaNumber = 1261;
// HIMAWARI-8 McIDAS AREA files
} else if (5900 < areaNumber && areaNumber <= 5999) {
areaNumber = 5900;
// METEOSAT-10 UNIWISC McIDAS AREA files
} else if (6000 < areaNumber && areaNumber <= 6099) {
areaNumber = 6000;
}
String value = McidasSatelliteLookups.getInstance().getAreaName(
areaNumber);
return value != null ? value : String.format("AREA%04d", areaNumber);
private String getAreaName(int ssn, int areaNumber) {
String value = McidasSatelliteLookups.getInstance().getAreaName(ssn);
theHandler.info("Looking up ssn=" + ssn + " for areaNumber=" + areaNumber);
theHandler.info("return value=" + value);
return value != null ? value : String.format("AREA%04d", areaNumber);
}
private void formatError(String message) throws DecoderException {

View file

@ -217,8 +217,8 @@ public class McidasSatelliteLookups {
return creatingEntityLookup.map.get(sensorSource);
}
public String getAreaName(int areaNumber) {
return areaNameLookup.map.get(areaNumber);
public String getAreaName(int sensorSource) {
return areaNameLookup.map.get(sensorSource);
}
private static McidasSatelliteLookups instance;

View file

@ -1,18 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<areaNames>
<map>
<entry><key>7101</key><value>Arctic</value></entry>
<entry><key>1000</key><value>Antarctic</value></entry>
<entry><key>2000</key><value>Antarctic</value></entry>
<entry><key>3000</key><value>Antarctic</value></entry>
<entry><key>10</key><value>GOES-Sounder</value></entry>
<entry><key>11</key><value>GOES-Sounder</value></entry>
<entry><key>12</key><value>GOES-Sounder</value></entry>
<entry><key>13</key><value>GOES-Sounder</value></entry>
<entry><key>14</key><value>GOES-Sounder</value></entry>
<entry><key>15</key><value>GOES-Sounder</value></entry>
<entry><key>1161</key><value>GOES-West</value></entry>
<entry><key>1261</key><value>GOES-East</value></entry>
<entry><key>401</key><value>Arctic</value></entry>
<entry><key>400</key><value>Antarctic</value></entry>
<entry><key>185</key><value>GOES-Sounder</value></entry>
<entry><key>71</key><value>GOES-Sounder</value></entry>
<entry><key>184</key><value>GOES-West</value></entry>
<entry><key>180</key><value>GOES-East</value></entry>
<entry><key>86</key><value>HIMAWARI-8</value></entry>
<entry><key>10</key><value>SSMIS</value></entry>
<entry><key>3</key><value>WINDSAT</value></entry>
<entry><key>3100</key><value>Global</value></entry>
<entry><key>3101</key><value>Global</value></entry>
<entry><key>601</key><value>Mollweide</value></entry>
@ -22,8 +19,5 @@
<entry><key>9056</key><value>GOES-East-West</value></entry>
<entry><key>9059</key><value>GOES-East-West</value></entry>
<entry><key>9062</key><value>GOES-East-West</value></entry>
<entry><key>5931</key><value>HIMAWARI-8 Full Disk</value></entry>
<entry><key>2101</key><value>SSMIS</value></entry>
<entry><key>2100</key><value>WINDSAT</value></entry>
</map>
</areaNames>

View file

@ -1,29 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
This_software_was_developed_and_/_or_modified_by_Raytheon_Company,
pursuant_to_Contract_DG133W-05-CQ-1067_with_the_US_Government.
U.S._EXPORT_CONTROLLED_TECHNICAL_DATA
This_software_product_contains_export-restricted_data_whose
export/transfer/disclosure_is_restricted_by_U.S._law._Dissemination
to_non-U.S._persons_whether_in_the_United_States_or_abroad_requires
a_export_license_or_other_authorization.
Contractor_Name:________Raytheon_Company
Contractor_Address:_____6825_Pine_Street,_Suite_340
________________________Mail_Stop_B8
________________________Omaha,_NE_68106
________________________402.291.0100
See_the_AWIPS_II_Master_Rights_File_("Master_Rights_File.pdf")_for
further_licensing_information.
-->
<!-- Source: http://www.ssec.wisc.edu/mcidas/doc/users_guide/current/app_c-1.html -->
<creatingEntities>
<map>
<entry><key>3</key><value>SOUNDER</value></entry>
<entry><key>9</key><value>COMP</value></entry>
<entry><key>10</key><value>SOUNDER</value></entry>
<entry><key>3</key><value>SOUNDER3</value></entry>
<entry><key>9</key><value>COMP9</value></entry>
<entry><key>10</key><value>SOUNDER10</value></entry>
<entry><key>12</key><value>GMS</value></entry>
<entry><key>13</key><value>GMS</value></entry>
<entry><key>30</key><value>GOES6</value></entry>
@ -40,18 +21,19 @@
<entry><key>57</key><value>METEOSAT6</value></entry>
<entry><key>58</key><value>METEOSAT7</value></entry>
<entry><key>70</key><value>GOES8</value></entry>
<entry><key>71</key><value>SOUNDER</value></entry>
<entry><key>74</key><value>GOES10</value></entry>
<entry><key>76</key><value>GOES-11(L)</value></entry>
<entry><key>77</key><value>DPD</value></entry>
<entry><key>78</key><value>GOES-12(M)</value></entry>
<entry><key>84</key><value>MTSAT-1R</value></entry>
<entry><key>84</key><value>MTSAT-1R</value></entry>
<entry><key>85</key><value>MTSAT-2</value></entry>
<entry><key>86</key><value>HIMAWARI-8</value></entry>
<entry><key>180</key><value>GOES-13(N)</value></entry>
<entry><key>184</key><value>GOES-15(P)</value></entry>
<entry><key>185</key><value>SOUNDER</value></entry>
<entry><key>401</key><value>COMP</value></entry>
<entry><key>72</key><value>COMP</value></entry>
<entry><key>180</key><value>UNIWISC</value></entry>
<entry><key>184</key><value>UNIWISC</value></entry>
<entry><key>185</key><value>UNIWISC</value></entry>
<entry><key>400</key><value>UNIWISC</value></entry>
<entry><key>401</key><value>UNIWISC</value></entry>
<entry><key>71</key><value>UNIWISC</value></entry>
<entry><key>72</key><value>UNIWISC</value></entry>
</map>
</creatingEntities>

View file

@ -1,23 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
This_software_was_developed_and_/_or_modified_by_Raytheon_Company,
pursuant_to_Contract_DG133W-05-CQ-1067_with_the_US_Government.
U.S._EXPORT_CONTROLLED_TECHNICAL_DATA
This_software_product_contains_export-restricted_data_whose
export/transfer/disclosure_is_restricted_by_U.S._law._Dissemination
to_non-U.S._persons_whether_in_the_United_States_or_abroad_requires
a_export_license_or_other_authorization.
Contractor_Name:________Raytheon_Company
Contractor_Address:_____6825_Pine_Street,_Suite_340
________________________Mail_Stop_B8
________________________Omaha,_NE_68106
________________________402.291.0100
See_the_AWIPS_II_Master_Rights_File_("Master_Rights_File.pdf")_for
further_licensing_information.
-->
<!--
Source: http://www.ssec.wisc.edu/mcidas/doc/users_guide/current/app_d-1.html
@ -89,13 +70,13 @@
<entry><key ss="401" band="5"/><value name="Imager 12 micron IR" /></entry>
<!-- Antarctic -->
<entry><key ss="72" band="1"/><value name="Imager Visible" /></entry>
<entry><key ss="72" band="2"/><value name="Imager 3.5-4.0 micron IR (Fog)" units="IRPixel" /> /></entry>
<entry><key ss="72" band="3"/><value name="Imager 6.7-6.5 micron IR (WV)" units="IRPixel" /></entry>
<entry><key ss="72" band="4"/><value name="Imager 11 micron IR" /></entry>
<entry><key ss="72" band="6"/><value name="Imager 12 micron IR" /></entry>
<entry><key ss="400" band="1"/><value name="Imager Visible" /></entry>
<entry><key ss="400" band="2"/><value name="Imager 3.5-4.0 micron IR (Fog)" units="IRPixel" /> /></entry>
<entry><key ss="400" band="3"/><value name="Imager 6.7-6.5 micron IR (WV)" units="IRPixel" /></entry>
<entry><key ss="400" band="4"/><value name="Imager 11 micron IR" /></entry>
<entry><key ss="400" band="5"/><value name="Imager 12 micron IR" /></entry>
<!-- SOUNDER -->
<!-- SOUNDER ??? -->
<entry><key ss="185" band="1"/><value name="Imager Visible" /></entry>
<entry><key ss="185" band="2"/><value name="Imager 11 micron IR" units="IRPixel" /></entry>
<entry><key ss="185" band="3"/><value name="Imager 12 micron IR" units="IRPixel" /></entry>