Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: ECW driver
5 : * Author: Even Rouault, <even.rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, Even Rouault, <even.rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : // ncsjpcbuffer.h needs the min and max macros.
30 : #undef NOMINMAX
31 :
32 : #include "ecwdrivercore.h"
33 :
34 : #include "ecwsdk_headers.h"
35 :
36 : constexpr unsigned char jpc_header[] = {0xff, 0x4f, 0xff,
37 : 0x51}; // SOC + RSIZ markers
38 : constexpr unsigned char jp2_header[] = {0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50,
39 : 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a};
40 :
41 : /* Needed for v4.3 and v5.0 */
42 : #if !defined(NCS_ECWSDK_VERSION_STRING) && defined(NCS_ECWJP2_VERSION_STRING)
43 : #define NCS_ECWSDK_VERSION_STRING NCS_ECWJP2_VERSION_STRING
44 : #endif
45 :
46 : /************************************************************************/
47 : /* IdentifyECW() */
48 : /* */
49 : /* Identify method that only supports ECW files. */
50 : /************************************************************************/
51 :
52 51112 : int ECWDatasetIdentifyECW(GDALOpenInfo *poOpenInfo)
53 :
54 : {
55 : /* -------------------------------------------------------------------- */
56 : /* This has to either be a file on disk ending in .ecw or a */
57 : /* ecwp: protocol url. */
58 : /* -------------------------------------------------------------------- */
59 51112 : if ((!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "ecw") ||
60 125 : poOpenInfo->nHeaderBytes == 0) &&
61 102283 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "ecwp:") &&
62 51046 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "ecwps:"))
63 51047 : return FALSE;
64 :
65 65 : return TRUE;
66 : }
67 :
68 : /************************************************************************/
69 : /* ECWDriverSetCommonMetadata() */
70 : /************************************************************************/
71 :
72 1230 : void ECWDriverSetCommonMetadata(GDALDriver *poDriver)
73 : {
74 1230 : poDriver->SetDescription(ECW_DRIVER_NAME);
75 1230 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
76 :
77 2460 : CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
78 :
79 : #ifdef NCS_ECWSDK_VERSION_STRING
80 : osLongName += NCS_ECWSDK_VERSION_STRING;
81 : #else
82 1230 : osLongName += "3.x";
83 : #endif
84 1230 : osLongName += ")";
85 :
86 1230 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, osLongName);
87 1230 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ecw.html");
88 1230 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ecw");
89 :
90 1230 : poDriver->pfnIdentify = ECWDatasetIdentifyECW;
91 1230 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
92 : #ifdef HAVE_COMPRESS
93 : // The create method does not work with SDK 3.3 ( crash in
94 : // CNCSJP2FileView::WriteLineBIL() due to m_pFile being nullptr ).
95 : #if ECWSDK_VERSION >= 50
96 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
97 : #endif
98 1230 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
99 : #if ECWSDK_VERSION >= 50
100 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16");
101 : #else
102 1230 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
103 : #endif
104 1230 : poDriver->SetMetadataItem(
105 : GDAL_DMD_CREATIONOPTIONLIST,
106 : "<CreationOptionList>"
107 : " <Option name='TARGET' type='float' description='Compression "
108 : "Percentage' />"
109 : " <Option name='PROJ' type='string' description='ECW Projection "
110 : "Name'/>"
111 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
112 :
113 : #if ECWSDK_VERSION < 40
114 : " <Option name='LARGE_OK' type='boolean' description='Enable "
115 : "compressing 500+MB files'/>"
116 : #else
117 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM "
118 : "Compress Key from ERDAS.'/>"
119 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM "
120 : "Company Name.'/>"
121 : #endif
122 :
123 : #if ECWSDK_VERSION >= 50
124 : " <Option name='ECW_FORMAT_VERSION' type='integer' description='ECW "
125 : "format version (2 or 3).' default='2'/>"
126 : #endif
127 :
128 1230 : "</CreationOptionList>");
129 : #else
130 : // In read-only mode, we support VirtualIO. This is not the case
131 : // for ECWCreateCopyECW().
132 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
133 : #endif
134 1230 : }
135 :
136 : /************************************************************************/
137 : /* IdentifyJPEG2000() */
138 : /* */
139 : /* Identify method that only supports JPEG2000 files. */
140 : /************************************************************************/
141 :
142 56720 : int ECWDatasetIdentifyJPEG2000(GDALOpenInfo *poOpenInfo)
143 :
144 : {
145 56720 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "J2K_SUBFILE:"))
146 0 : return TRUE;
147 :
148 56720 : else if (poOpenInfo->nHeaderBytes >= 16 &&
149 9752 : (memcmp(poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header)) ==
150 9697 : 0 ||
151 9697 : memcmp(poOpenInfo->pabyHeader, jp2_header, sizeof(jp2_header)) ==
152 : 0))
153 147 : return TRUE;
154 :
155 : else
156 56573 : return FALSE;
157 : }
158 :
159 : /************************************************************************/
160 : /* JP2ECWDriverSetCommonMetadata() */
161 : /************************************************************************/
162 :
163 1230 : void JP2ECWDriverSetCommonMetadata(GDALDriver *poDriver)
164 : {
165 1230 : poDriver->SetDescription(JP2ECW_DRIVER_NAME);
166 1230 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
167 1230 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
168 :
169 2460 : CPLString osLongName = "ERDAS JPEG2000 (SDK ";
170 :
171 : #ifdef NCS_ECWSDK_VERSION_STRING
172 : osLongName += NCS_ECWSDK_VERSION_STRING;
173 : #else
174 1230 : osLongName += "3.x";
175 : #endif
176 1230 : osLongName += ")";
177 :
178 1230 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, osLongName);
179 1230 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jp2ecw.html");
180 1230 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "jp2");
181 1230 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
182 :
183 1230 : poDriver->pfnIdentify = ECWDatasetIdentifyJPEG2000;
184 1230 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
185 :
186 1230 : poDriver->SetMetadataItem(
187 : GDAL_DMD_OPENOPTIONLIST,
188 : "<OpenOptionList>"
189 : " <Option name='1BIT_ALPHA_PROMOTION' type='boolean' "
190 : "description='Whether a 1-bit alpha channel should be promoted to "
191 : "8-bit' default='YES'/>"
192 : " <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether "
193 : "to load remote vector layers referenced by a link in a GMLJP2 v2 box' "
194 : "default='NO'/>"
195 : " <Option name='GEOREF_SOURCES' type='string' description='Comma "
196 : "separated list made with values "
197 : "INTERNAL/GMLJP2/GEOJP2/WORLDFILE/PAM/NONE that describe the priority "
198 : "order for georeferencing' default='PAM,GEOJP2,GMLJP2,WORLDFILE'/>"
199 1230 : "</OpenOptionList>");
200 :
201 : #ifdef HAVE_COMPRESS
202 1230 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
203 1230 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
204 1230 : poDriver->SetMetadataItem(
205 : GDAL_DMD_CREATIONDATATYPES,
206 : "Byte UInt16 Int16 UInt32 Int32 "
207 : "Float32 "
208 : #if ECWSDK_VERSION >= 40
209 : // Crashes for sure with 3.3. Didn't try other versions
210 : "Float64"
211 : #endif
212 1230 : );
213 1230 : poDriver->SetMetadataItem(
214 : GDAL_DMD_CREATIONOPTIONLIST,
215 : "<CreationOptionList>"
216 : " <Option name='TARGET' type='float' description='Compression "
217 : "Percentage' />"
218 : " <Option name='PROJ' type='string' description='ECW Projection "
219 : "Name'/>"
220 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
221 : " <Option name='UNITS' type='string-select' description='ECW "
222 : "Projection Units'>"
223 : " <Value>METERS</Value>"
224 : " <Value>FEET</Value>"
225 : " </Option>"
226 :
227 : #if ECWSDK_VERSION < 40
228 : " <Option name='LARGE_OK' type='boolean' description='Enable "
229 : "compressing 500+MB files'/>"
230 : #else
231 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM "
232 : "Compress Key from ERDAS.'/>"
233 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM "
234 : "Company Name.'/>"
235 : #endif
236 :
237 : " <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
238 : " <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
239 : " <Option name='GMLJP2V2_DEF' type='string' description='Definition "
240 : "file to describe how a GMLJP2 v2 box should be generated. If set to "
241 : "YES, a minimal instance will be created'/>"
242 : " <Option name='PROFILE' type='string-select'>"
243 : " <Value>BASELINE_0</Value>"
244 : " <Value>BASELINE_1</Value>"
245 : " <Value>BASELINE_2</Value>"
246 : " <Value>NPJE</Value>"
247 : " <Value>EPJE</Value>"
248 : " </Option>"
249 : " <Option name='PROGRESSION' type='string-select'>"
250 : " <Value>LRCP</Value>"
251 : " <Value>RLCP</Value>"
252 : " <Value>RPCL</Value>"
253 : " </Option>"
254 : " <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 "
255 : "wrapper'/>"
256 : " <Option name='NBITS' type='int' description='Bits (precision) for "
257 : "sub-byte files (1-7), sub-uint16 (9-15)'/>"
258 : " <Option name='LEVELS' type='int'/>"
259 : " <Option name='LAYERS' type='int'/>"
260 : " <Option name='PRECINCT_WIDTH' type='int'/>"
261 : " <Option name='PRECINCT_HEIGHT' type='int'/>"
262 : " <Option name='TILE_WIDTH' type='int'/>"
263 : " <Option name='TILE_HEIGHT' type='int'/>"
264 : " <Option name='INCLUDE_SOP' type='boolean'/>"
265 : " <Option name='INCLUDE_EPH' type='boolean'/>"
266 : " <Option name='DECOMPRESS_LAYERS' type='int'/>"
267 : " <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
268 : " <Option name='WRITE_METADATA' type='boolean' description='Whether "
269 : "metadata should be written, in a dedicated JP2 XML box' default='NO'/>"
270 : " <Option name='MAIN_MD_DOMAIN_ONLY' type='boolean' "
271 : "description='(Only if WRITE_METADATA=YES) Whether only metadata from "
272 : "the main domain should be written' default='NO'/>"
273 1230 : "</CreationOptionList>");
274 : #endif
275 1230 : }
276 :
277 : /************************************************************************/
278 : /* DeclareDeferredECWPlugin() */
279 : /************************************************************************/
280 :
281 : #ifdef PLUGIN_FILENAME
282 1520 : void DeclareDeferredECWPlugin()
283 : {
284 1520 : if (GDALGetDriverByName(ECW_DRIVER_NAME) != nullptr)
285 : {
286 301 : return;
287 : }
288 : {
289 1219 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
290 : #ifdef PLUGIN_INSTALLATION_MESSAGE
291 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
292 : PLUGIN_INSTALLATION_MESSAGE);
293 : #endif
294 1219 : ECWDriverSetCommonMetadata(poDriver);
295 1219 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
296 : }
297 : {
298 1219 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
299 : #ifdef PLUGIN_INSTALLATION_MESSAGE
300 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
301 : PLUGIN_INSTALLATION_MESSAGE);
302 : #endif
303 1219 : JP2ECWDriverSetCommonMetadata(poDriver);
304 1219 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
305 : }
306 : }
307 : #endif
|