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 : * SPDX-License-Identifier: MIT 15 : ****************************************************************************/ 16 : 17 : #include "gdal_frmts.h" 18 : #include "gdalplugindriverproxy.h" 19 : 20 : #include "jpegdrivercore.h" 21 : 22 : // So that D_LOSSLESS_SUPPORTED is visible if defined in jmorecfg of libjpeg-turbo >= 2.2 23 : #define JPEG_INTERNAL_OPTIONS 24 : #include "jpeglib.h" 25 : 26 : /************************************************************************/ 27 : /* JPEGDatasetIsJPEGLS() */ 28 : /************************************************************************/ 29 : 30 6634 : bool JPEGDatasetIsJPEGLS(GDALOpenInfo *poOpenInfo) 31 : 32 : { 33 6634 : GByte *pabyHeader = poOpenInfo->pabyHeader; 34 6634 : int nHeaderBytes = poOpenInfo->nHeaderBytes; 35 : 36 6634 : if (nHeaderBytes < 10) 37 0 : return false; 38 : 39 6634 : if (pabyHeader[0] != 0xff || pabyHeader[1] != 0xd8) 40 0 : return false; 41 : 42 30456 : for (int nOffset = 2; nOffset + 4 < nHeaderBytes;) 43 : { 44 26016 : if (pabyHeader[nOffset] != 0xFF) 45 6 : return false; 46 : 47 26010 : int nMarker = pabyHeader[nOffset + 1]; 48 26010 : if (nMarker == 0xDA) 49 2188 : return false; 50 : 51 23822 : if (nMarker == 0xF7) // JPEG Extension 7, JPEG-LS. 52 0 : return true; 53 23822 : if (nMarker == 0xF8) // JPEG Extension 8, JPEG-LS Extension. 54 0 : return true; 55 23822 : if (nMarker == 0xC3) // Start of Frame 3 (Lossless Huffman) 56 0 : return true; 57 23822 : if (nMarker == 58 : 0xC7) // Start of Frame 7 (Differential Lossless Huffman) 59 0 : return true; 60 23822 : if (nMarker == 0xCB) // Start of Frame 11 (Lossless Arithmetic) 61 0 : return true; 62 23822 : if (nMarker == 63 : 0xCF) // Start of Frame 15 (Differential Lossless Arithmetic) 64 0 : return true; 65 : 66 23822 : nOffset += 2 + pabyHeader[nOffset + 2] * 256 + pabyHeader[nOffset + 3]; 67 : } 68 : 69 4440 : return false; 70 : } 71 : 72 : /************************************************************************/ 73 : /* JPEGDriverIdentify() */ 74 : /************************************************************************/ 75 : 76 66155 : int JPEGDriverIdentify(GDALOpenInfo *poOpenInfo) 77 : 78 : { 79 : // If it is a subfile, read the JPEG header. 80 66155 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "JPEG_SUBFILE:")) 81 292 : return TRUE; 82 65863 : if (STARTS_WITH(poOpenInfo->pszFilename, "JPEG:")) 83 20 : return TRUE; 84 : 85 : // First we check to see if the file has the expected header bytes. 86 65843 : const int nHeaderBytes = poOpenInfo->nHeaderBytes; 87 : 88 65843 : if (nHeaderBytes < 10) 89 55272 : return FALSE; 90 : 91 10571 : GByte *const pabyHeader = poOpenInfo->pabyHeader; 92 10571 : if (pabyHeader[0] != 0xff || pabyHeader[1] != 0xd8 || pabyHeader[2] != 0xff) 93 3937 : return FALSE; 94 : 95 : // libjpeg-turbo >= 2.2 supports lossless mode 96 : #if !defined(D_LOSSLESS_SUPPORTED) 97 6634 : if (JPEGDatasetIsJPEGLS(poOpenInfo)) 98 : { 99 0 : return FALSE; 100 : } 101 : #endif 102 : 103 : // Some files like 104 : // http://dionecanali.hd.free.fr/~mdione/mapzen/N65E039.hgt.gz could be 105 : // mis-identfied as JPEG 106 13268 : CPLString osFilenameLower = CPLString(poOpenInfo->pszFilename).tolower(); 107 13267 : if (osFilenameLower.endsWith(".hgt") || 108 26536 : osFilenameLower.endsWith(".hgt.gz") || 109 13268 : osFilenameLower.endsWith(".hgt.zip")) 110 : { 111 0 : return FALSE; 112 : } 113 : 114 6634 : return TRUE; 115 : } 116 : 117 : /************************************************************************/ 118 : /* JPEGDriverSetCommonMetadata() */ 119 : /************************************************************************/ 120 : 121 1750 : void JPEGDriverSetCommonMetadata(GDALDriver *poDriver) 122 : { 123 1750 : poDriver->SetDescription(DRIVER_NAME); 124 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 125 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "JPEG JFIF"); 126 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/jpeg.html"); 127 1750 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "jpg"); 128 1750 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "jpg jpeg"); 129 1750 : poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/jpeg"); 130 : 131 : #if defined(JPEG_LIB_MK1_OR_12BIT) || defined(JPEG_DUAL_MODE_8_12) 132 1750 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16"); 133 : #else 134 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); 135 : #endif 136 1750 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 137 1750 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_ONLY_VISIBLE_AT_CLOSE_TIME, 138 1750 : "YES"); 139 : 140 1750 : const char *pszOpenOptions = 141 : "<OpenOptionList>\n" 142 : " <Option name='USE_INTERNAL_OVERVIEWS' type='boolean' " 143 : "description='whether to use implicit internal overviews' " 144 : "default='YES'/>\n" 145 : " <Option name='APPLY_ORIENTATION' type='boolean' " 146 : "description='whether to take into account EXIF Orientation to " 147 : "rotate/flip the image' default='NO'/>\n" 148 : "</OpenOptionList>\n"; 149 1750 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, pszOpenOptions); 150 : 151 : #ifdef D_LOSSLESS_SUPPORTED 152 : // For autotest purposes 153 : poDriver->SetMetadataItem("LOSSLESS_JPEG_SUPPORTED", "YES", "JPEG"); 154 : #endif 155 : 156 1750 : poDriver->pfnIdentify = JPEGDriverIdentify; 157 1750 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 158 1750 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 159 1750 : } 160 : 161 : /************************************************************************/ 162 : /* DeclareDeferredJPEGPlugin() */ 163 : /************************************************************************/ 164 : 165 : #ifdef PLUGIN_FILENAME 166 : void DeclareDeferredJPEGPlugin() 167 : { 168 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 169 : { 170 : return; 171 : } 172 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 173 : #ifdef PLUGIN_INSTALLATION_MESSAGE 174 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 175 : PLUGIN_INSTALLATION_MESSAGE); 176 : #endif 177 : JPEGDriverSetCommonMetadata(poDriver); 178 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 179 : } 180 : #endif