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