Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: OpenGIS Simple Features Reference Implementation 4 : * Purpose: Implementation of PMTiles 5 : * Author: Even Rouault <even.rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2023, Planet Labs 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "ogr_pmtiles.h" 14 : 15 : #include "vsipmtiles.h" 16 : 17 : #include "ogrpmtilesfrommbtiles.h" 18 : 19 : #ifdef HAVE_MVT_WRITE_SUPPORT 20 : #include "mvtutils.h" 21 : #endif 22 : 23 : /************************************************************************/ 24 : /* OGRPMTilesDriverIdentify() */ 25 : /************************************************************************/ 26 : 27 43110 : static int OGRPMTilesDriverIdentify(GDALOpenInfo *poOpenInfo) 28 : { 29 43110 : if (poOpenInfo->nHeaderBytes < 127 || !poOpenInfo->fpL) 30 42315 : return FALSE; 31 795 : return memcmp(poOpenInfo->pabyHeader, "PMTiles\x03", 8) == 0; 32 : } 33 : 34 : /************************************************************************/ 35 : /* OGRPMTilesDriverOpen() */ 36 : /************************************************************************/ 37 : 38 42 : static GDALDataset *OGRPMTilesDriverOpen(GDALOpenInfo *poOpenInfo) 39 : { 40 42 : if (!OGRPMTilesDriverIdentify(poOpenInfo)) 41 0 : return nullptr; 42 84 : auto poDS = std::make_unique<OGRPMTilesDataset>(); 43 42 : if (!poDS->Open(poOpenInfo)) 44 8 : return nullptr; 45 34 : return poDS.release(); 46 : } 47 : 48 : /************************************************************************/ 49 : /* OGRPMTilesDriverCanVectorTranslateFrom() */ 50 : /************************************************************************/ 51 : 52 5 : static bool OGRPMTilesDriverCanVectorTranslateFrom( 53 : const char * /*pszDestName*/, GDALDataset *poSourceDS, 54 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons) 55 : { 56 5 : auto poSrcDriver = poSourceDS->GetDriver(); 57 5 : if (!(poSrcDriver && EQUAL(poSrcDriver->GetDescription(), "MBTiles"))) 58 : { 59 1 : if (ppapszFailureReasons) 60 1 : *ppapszFailureReasons = CSLAddString( 61 : *ppapszFailureReasons, "Source driver is not MBTiles"); 62 1 : return false; 63 : } 64 : 65 4 : if (papszVectorTranslateArguments) 66 : { 67 2 : const int nArgs = CSLCount(papszVectorTranslateArguments); 68 4 : for (int i = 0; i < nArgs; ++i) 69 : { 70 2 : if (i + 1 < nArgs && 71 2 : (strcmp(papszVectorTranslateArguments[i], "-f") == 0 || 72 0 : strcmp(papszVectorTranslateArguments[i], "-of") == 0)) 73 : { 74 2 : ++i; 75 : } 76 : else 77 : { 78 0 : if (ppapszFailureReasons) 79 0 : *ppapszFailureReasons = 80 0 : CSLAddString(*ppapszFailureReasons, 81 : "Direct copy from MBTiles does not " 82 : "support GDALVectorTranslate() options"); 83 0 : return false; 84 : } 85 : } 86 : } 87 : 88 4 : return true; 89 : } 90 : 91 : /************************************************************************/ 92 : /* OGRPMTilesDriverVectorTranslateFrom() */ 93 : /************************************************************************/ 94 : 95 2 : static GDALDataset *OGRPMTilesDriverVectorTranslateFrom( 96 : const char *pszDestName, GDALDataset *poSourceDS, 97 : CSLConstList papszVectorTranslateArguments, 98 : GDALProgressFunc /* pfnProgress */, void * /* pProgressData */) 99 : { 100 2 : if (!OGRPMTilesDriverCanVectorTranslateFrom( 101 : pszDestName, poSourceDS, papszVectorTranslateArguments, nullptr)) 102 : { 103 0 : return nullptr; 104 : } 105 : 106 2 : if (!OGRPMTilesConvertFromMBTiles(pszDestName, 107 2 : poSourceDS->GetDescription())) 108 : { 109 0 : return nullptr; 110 : } 111 : 112 4 : GDALOpenInfo oOpenInfo(pszDestName, GA_ReadOnly); 113 2 : return OGRPMTilesDriverOpen(&oOpenInfo); 114 : } 115 : 116 : #ifdef HAVE_MVT_WRITE_SUPPORT 117 : /************************************************************************/ 118 : /* Create() */ 119 : /************************************************************************/ 120 : 121 34 : static GDALDataset *OGRPMTilesDriverCreate(const char *pszFilename, int nXSize, 122 : int nYSize, int nBandsIn, 123 : GDALDataType eDT, 124 : char **papszOptions) 125 : { 126 34 : if (nXSize == 0 && nYSize == 0 && nBandsIn == 0 && eDT == GDT_Unknown) 127 : { 128 68 : auto poDS = std::make_unique<OGRPMTilesWriterDataset>(); 129 34 : if (!poDS->Create(pszFilename, papszOptions)) 130 1 : return nullptr; 131 33 : return poDS.release(); 132 : } 133 0 : return nullptr; 134 : } 135 : #endif 136 : 137 : /************************************************************************/ 138 : /* RegisterOGRPMTiles() */ 139 : /************************************************************************/ 140 : 141 1595 : void RegisterOGRPMTiles() 142 : { 143 1595 : if (GDALGetDriverByName("PMTiles") != nullptr) 144 302 : return; 145 : 146 1293 : VSIPMTilesRegister(); 147 : 148 1293 : GDALDriver *poDriver = new GDALDriver(); 149 : 150 1293 : poDriver->SetDescription("PMTiles"); 151 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 152 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ProtoMap Tiles"); 153 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "pmtiles"); 154 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 155 1293 : "drivers/vector/pmtiles.html"); 156 : 157 1293 : poDriver->SetMetadataItem( 158 : GDAL_DMD_OPENOPTIONLIST, 159 : "<OpenOptionList>" 160 : " <Option name='ZOOM_LEVEL' type='integer' " 161 : "description='Zoom level of full resolution. If not specified, maximum " 162 : "non-empty zoom level'/>" 163 : " <Option name='CLIP' type='boolean' " 164 : "description='Whether to clip geometries to tile extent' " 165 : "default='YES'/>" 166 : " <Option name='ZOOM_LEVEL_AUTO' type='boolean' " 167 : "description='Whether to auto-select the zoom level for vector layers " 168 : "according to spatial filter extent. Only for display purpose' " 169 : "default='NO'/>" 170 : " <Option name='JSON_FIELD' type='boolean' " 171 : "description='For vector layers, " 172 : "whether to put all attributes as a serialized JSon dictionary'/>" 173 1293 : "</OpenOptionList>"); 174 : 175 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 176 : 177 1293 : poDriver->pfnOpen = OGRPMTilesDriverOpen; 178 1293 : poDriver->pfnIdentify = OGRPMTilesDriverIdentify; 179 1293 : poDriver->pfnCanVectorTranslateFrom = 180 : OGRPMTilesDriverCanVectorTranslateFrom; 181 1293 : poDriver->pfnVectorTranslateFrom = OGRPMTilesDriverVectorTranslateFrom; 182 : 183 : #ifdef HAVE_MVT_WRITE_SUPPORT 184 1293 : poDriver->SetMetadataItem( 185 : GDAL_DMD_CREATIONOPTIONLIST, 186 : "<CreationOptionList>" 187 : " <Option name='NAME' scope='raster,vector' type='string' " 188 : "description='Tileset name'/>" 189 : " <Option name='DESCRIPTION' scope='raster,vector' type='string' " 190 : "description='A description of the layer'/>" 191 : " <Option name='TYPE' scope='raster,vector' type='string-select' " 192 : "description='Layer type' default='overlay'>" 193 : " <Value>overlay</Value>" 194 : " <Value>baselayer</Value>" 195 1293 : " </Option>" MVT_MBTILES_PMTILES_COMMON_DSCO "</CreationOptionList>"); 196 : 197 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 198 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 199 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, 200 1293 : "Integer Integer64 Real String"); 201 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 202 1293 : "Boolean Float32"); 203 : 204 1293 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, MVT_LCO); 205 : 206 1293 : poDriver->pfnCreate = OGRPMTilesDriverCreate; 207 : #endif 208 : 209 1293 : GetGDALDriverManager()->RegisterDriver(poDriver); 210 : }