Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: JPEG JFIF Driver 4 : * Purpose: Implement GDAL JPEG Support based on IJG libjpeg. 5 : * Author: Frank Warmerdam, warmerdam@pobox.com 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2000, Frank Warmerdam 9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com> 10 : * 11 : * Portions Copyright (c) Her majesty the Queen in right of Canada as 12 : * represented by the Minister of National Defence, 2006. 13 : * 14 : * Permission is hereby granted, free of charge, to any person obtaining a 15 : * copy of this software and associated documentation files (the "Software"), 16 : * to deal in the Software without restriction, including without limitation 17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 : * and/or sell copies of the Software, and to permit persons to whom the 19 : * Software is furnished to do so, subject to the following conditions: 20 : * 21 : * The above copyright notice and this permission notice shall be included 22 : * in all copies or substantial portions of the Software. 23 : * 24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 : * DEALINGS IN THE SOFTWARE. 31 : ****************************************************************************/ 32 : 33 : #include "jpegdrivercore.h" 34 : 35 : // So that D_LOSSLESS_SUPPORTED is visible if defined in jmorecfg of libjpeg-turbo >= 2.2 36 : #define JPEG_INTERNAL_OPTIONS 37 : #include "jpeglib.h" 38 : 39 : /************************************************************************/ 40 : /* JPEGDatasetIsJPEGLS() */ 41 : /************************************************************************/ 42 : 43 6075 : bool JPEGDatasetIsJPEGLS(GDALOpenInfo *poOpenInfo) 44 : 45 : { 46 6075 : GByte *pabyHeader = poOpenInfo->pabyHeader; 47 6075 : int nHeaderBytes = poOpenInfo->nHeaderBytes; 48 : 49 6075 : if (nHeaderBytes < 10) 50 0 : return false; 51 : 52 6075 : if (pabyHeader[0] != 0xff || pabyHeader[1] != 0xd8) 53 0 : return false; 54 : 55 27455 : for (int nOffset = 2; nOffset + 4 < nHeaderBytes;) 56 : { 57 23017 : if (pabyHeader[nOffset] != 0xFF) 58 0 : return false; 59 : 60 23017 : int nMarker = pabyHeader[nOffset + 1]; 61 23017 : if (nMarker == 0xDA) 62 1637 : return false; 63 : 64 21380 : if (nMarker == 0xF7) // JPEG Extension 7, JPEG-LS. 65 0 : return true; 66 21380 : if (nMarker == 0xF8) // JPEG Extension 8, JPEG-LS Extension. 67 0 : return true; 68 21380 : if (nMarker == 0xC3) // Start of Frame 3 (Lossless Huffman) 69 0 : return true; 70 21380 : if (nMarker == 71 : 0xC7) // Start of Frame 7 (Differential Lossless Huffman) 72 0 : return true; 73 21380 : if (nMarker == 0xCB) // Start of Frame 11 (Lossless Arithmetic) 74 0 : return true; 75 21380 : if (nMarker == 76 : 0xCF) // Start of Frame 15 (Differential Lossless Arithmetic) 77 0 : return true; 78 : 79 21380 : nOffset += 2 + pabyHeader[nOffset + 2] * 256 + pabyHeader[nOffset + 3]; 80 : } 81 : 82 4438 : return false; 83 : } 84 : 85 : /************************************************************************/ 86 : /* JPEGDriverIdentify() */ 87 : /************************************************************************/ 88 : 89 55459 : int JPEGDriverIdentify(GDALOpenInfo *poOpenInfo) 90 : 91 : { 92 : // If it is a subfile, read the JPEG header. 93 55459 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "JPEG_SUBFILE:")) 94 60 : return TRUE; 95 55399 : if (STARTS_WITH(poOpenInfo->pszFilename, "JPEG:")) 96 10 : return TRUE; 97 : 98 : // First we check to see if the file has the expected header bytes. 99 55389 : const int nHeaderBytes = poOpenInfo->nHeaderBytes; 100 : 101 55389 : if (nHeaderBytes < 10) 102 45770 : return FALSE; 103 : 104 9619 : GByte *const pabyHeader = poOpenInfo->pabyHeader; 105 9619 : if (pabyHeader[0] != 0xff || pabyHeader[1] != 0xd8 || pabyHeader[2] != 0xff) 106 3544 : return FALSE; 107 : 108 : // libjpeg-turbo >= 2.2 supports lossless mode 109 : #if !defined(D_LOSSLESS_SUPPORTED) 110 6075 : if (JPEGDatasetIsJPEGLS(poOpenInfo)) 111 : { 112 0 : return FALSE; 113 : } 114 : #endif 115 : 116 : // Some files like 117 : // http://dionecanali.hd.free.fr/~mdione/mapzen/N65E039.hgt.gz could be 118 : // mis-identfied as JPEG 119 12150 : CPLString osFilenameLower = CPLString(poOpenInfo->pszFilename).tolower(); 120 12150 : if (osFilenameLower.endsWith(".hgt") || 121 24300 : osFilenameLower.endsWith(".hgt.gz") || 122 12150 : osFilenameLower.endsWith(".hgt.zip")) 123 : { 124 0 : return FALSE; 125 : } 126 : 127 6075 : return TRUE; 128 : } 129 : 130 : /************************************************************************/ 131 : /* JPEGDriverSetCommonMetadata() */ 132 : /************************************************************************/ 133 : 134 1219 : void JPEGDriverSetCommonMetadata(GDALDriver *poDriver) 135 : { 136 1219 : poDriver->SetDescription(DRIVER_NAME); 137 1219 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 138 1219 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "JPEG JFIF"); 139 1219 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jpeg.html"); 140 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "jpg"); 141 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "jpg jpeg"); 142 1219 : poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/jpeg"); 143 : 144 : #if defined(JPEG_LIB_MK1_OR_12BIT) || defined(JPEG_DUAL_MODE_8_12) 145 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16"); 146 : #else 147 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); 148 : #endif 149 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 150 : 151 1219 : const char *pszOpenOptions = 152 : "<OpenOptionList>\n" 153 : " <Option name='USE_INTERNAL_OVERVIEWS' type='boolean' " 154 : "description='whether to use implicit internal overviews' " 155 : "default='YES'/>\n" 156 : " <Option name='APPLY_ORIENTATION' type='boolean' " 157 : "description='whether to take into account EXIF Orientation to " 158 : "rotate/flip the image' default='NO'/>\n" 159 : "</OpenOptionList>\n"; 160 1219 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, pszOpenOptions); 161 : 162 : #ifdef D_LOSSLESS_SUPPORTED 163 : // For autotest purposes 164 : poDriver->SetMetadataItem("LOSSLESS_JPEG_SUPPORTED", "YES", "JPEG"); 165 : #endif 166 : 167 1219 : poDriver->pfnIdentify = JPEGDriverIdentify; 168 1219 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 169 1219 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 170 1219 : } 171 : 172 : /************************************************************************/ 173 : /* DeclareDeferredJPEGPlugin() */ 174 : /************************************************************************/ 175 : 176 : #ifdef PLUGIN_FILENAME 177 : void DeclareDeferredJPEGPlugin() 178 : { 179 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 180 : { 181 : return; 182 : } 183 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 184 : #ifdef PLUGIN_INSTALLATION_MESSAGE 185 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 186 : PLUGIN_INSTALLATION_MESSAGE); 187 : #endif 188 : JPEGDriverSetCommonMetadata(poDriver); 189 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 190 : } 191 : #endif