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