1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % JJJ N N X X % 7 % J NN N X X % 8 % J N N N X % 9 % J J N NN X X % 10 % JJ N N X X % 11 % % 12 % % 13 % Read/Write Garmin Image Format % 14 % % 15 % Cristy % 16 % July 2012 % 17 % % 18 % % 19 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 20 % dedicated to making software imaging solutions freely available. % 21 % % 22 % You may not use this file except in compliance with the License. You may % 23 % obtain a copy of the License at % 24 % % 25 % http://www.imagemagick.org/script/license.php % 26 % % 27 % Unless required by applicable law or agreed to in writing, software % 28 % distributed under the License is distributed on an "AS IS" BASIS, % 29 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 30 % See the License for the specific language governing permissions and % 31 % limitations under the License. % 32 % % 33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 % 35 % 36 */ 37 38 /* 40 Include declarations. 41 */ 42 43 /* 45 Include declarations. 46 */ 47 #include "MagickCore/studio.h" 48 #include "MagickCore/blob.h" 49 #include "MagickCore/blob-private.h" 50 #include "MagickCore/cache.h" 51 #include "MagickCore/colorspace.h" 52 #include "MagickCore/colorspace-private.h" 53 #include "MagickCore/draw.h" 54 #include "MagickCore/exception.h" 55 #include "MagickCore/exception-private.h" 56 #include "MagickCore/image.h" 57 #include "MagickCore/image-private.h" 58 #include "MagickCore/list.h" 59 #include "MagickCore/magick.h" 60 #include "MagickCore/memory_.h" 61 #include "MagickCore/module.h" 62 #include "MagickCore/monitor.h" 63 #include "MagickCore/monitor-private.h" 64 #include "MagickCore/property.h" 65 #include "MagickCore/pixel-accessor.h" 66 #include "MagickCore/quantum-private.h" 67 #include "MagickCore/static.h" 68 #include "MagickCore/string_.h" 69 70 typedef struct _JNXInfo 72 { 73 int 74 version, 75 serial; 76 77 PointInfo 78 northeast, 79 southwest; 80 81 int 82 levels, 83 expire, 84 id, 85 crc, 86 signature; 87 88 unsigned int 89 offset; 90 91 int 92 order; 93 } JNXInfo; 94 95 typedef struct _JNXLevelInfo 96 { 97 int 98 count, 99 offset; 100 101 unsigned int 102 scale; 103 104 unsigned short 105 copyright[MagickPathExtent]; 106 } JNXLevelInfo; 107 108 /* 110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 % % 112 % % 113 % % 114 % R e a d J N X I m a g e % 115 % % 116 % % 117 % % 118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 119 % 120 % ReadJNXImage() reads an image in the Garmin tile storage format and returns 121 % it. It allocates the memory necessary for the new Image structure and 122 % returns a pointer to the new image. 123 % 124 % The format of the ReadJNXImage method is: 125 % 126 % Image *ReadJNXImage(const ImageInfo *image_info,ExceptionInfo *exception) 127 % 128 % A description of each parameter follows: 129 % 130 % o image_info: the image info. 131 % 132 % o exception: return any errors or warnings in this structure. 133 % 134 */ 135 static Image *ReadJNXImage(const ImageInfo *image_info,ExceptionInfo *exception) 136 { 137 #define JNXMaxLevels 20 138 139 Image 140 *image, 141 *images; 142 143 JNXInfo 144 jnx_info; 145 146 JNXLevelInfo 147 jnx_level_info[JNXMaxLevels]; 148 149 MagickBooleanType 150 status; 151 152 register ssize_t 153 i; 154 155 /* 156 Open image file. 157 */ 158 assert(image_info != (const ImageInfo *) NULL); 159 assert(image_info->signature == MagickCoreSignature); 160 if (image_info->debug != MagickFalse) 161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 162 image_info->filename); 163 assert(exception != (ExceptionInfo *) NULL); 164 assert(exception->signature == MagickCoreSignature); 165 image=AcquireImage(image_info,exception); 166 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 167 if (status == MagickFalse) 168 { 169 image=DestroyImageList(image); 170 return((Image *) NULL); 171 } 172 /* 173 Read JNX header. 174 */ 175 (void) ResetMagickMemory(&jnx_info,0,sizeof(jnx_info)); 176 jnx_info.version=ReadBlobLSBSignedLong(image); 177 if ((jnx_info.version != 3) && (jnx_info.version != 4)) 178 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 179 jnx_info.serial=ReadBlobLSBSignedLong(image); 180 jnx_info.northeast.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 181 jnx_info.northeast.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 182 jnx_info.southwest.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 183 jnx_info.southwest.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 184 jnx_info.levels=ReadBlobLSBSignedLong(image); 185 if (jnx_info.levels > JNXMaxLevels) 186 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 187 jnx_info.expire=ReadBlobLSBSignedLong(image); 188 jnx_info.id=ReadBlobLSBSignedLong(image); 189 jnx_info.crc=ReadBlobLSBSignedLong(image); 190 jnx_info.signature=ReadBlobLSBSignedLong(image); 191 jnx_info.offset=ReadBlobLSBLong(image); 192 if (jnx_info.version > 3) 193 jnx_info.order=ReadBlobLSBSignedLong(image); 194 else 195 if (jnx_info.version == 3) 196 jnx_info.order=30; 197 /* 198 Read JNX levels. 199 */ 200 (void) ResetMagickMemory(&jnx_level_info,0,sizeof(jnx_level_info)); 201 for (i=0; i < (ssize_t) jnx_info.levels; i++) 202 { 203 jnx_level_info[i].count=ReadBlobLSBSignedLong(image); 204 if (jnx_level_info[i].count > 50000) 205 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 206 jnx_level_info[i].offset=ReadBlobLSBSignedLong(image); 207 jnx_level_info[i].scale=ReadBlobLSBLong(image); 208 if (jnx_info.version > 3) 209 { 210 register ssize_t 211 j; 212 213 unsigned short 214 c; 215 216 (void) ReadBlobLSBLong(image); 217 j=0; 218 while ((c=ReadBlobLSBShort(image)) != 0) 219 if (j < (MagickPathExtent-1)) 220 jnx_level_info[i].copyright[j++]=c; 221 jnx_level_info[i].copyright[j]=0; 222 } 223 } 224 /* 225 Read JNX tiles. 226 */ 227 images=NewImageList(); 228 for (i=0; i < (ssize_t) jnx_info.levels; i++) 229 { 230 MagickOffsetType 231 offset; 232 233 register ssize_t 234 j; 235 236 offset=SeekBlob(image,(MagickOffsetType) jnx_level_info[i].offset,SEEK_SET); 237 if (offset != (MagickOffsetType) jnx_level_info[i].offset) 238 continue; 239 for (j=0; j < (ssize_t) jnx_level_info[i].count; j++) 240 { 241 Image 242 *tile_image; 243 244 ImageInfo 245 *read_info; 246 247 int 248 tile_offset; 249 250 MagickOffsetType 251 restore_offset; 252 253 PointInfo 254 northeast, 255 southwest; 256 257 ssize_t 258 count; 259 260 unsigned char 261 *blob; 262 263 unsigned int 264 tile_length; 265 266 northeast.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 267 northeast.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 268 southwest.x=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 269 southwest.y=180.0*ReadBlobLSBSignedLong(image)/0x7fffffff; 270 (void) ReadBlobLSBShort(image); /* width */ 271 (void) ReadBlobLSBShort(image); /* height */ 272 tile_length=ReadBlobLSBLong(image); 273 tile_offset=ReadBlobLSBSignedLong(image); 274 if (tile_offset == -1) 275 continue; 276 restore_offset=TellBlob(image); 277 if (restore_offset < 0) 278 continue; 279 offset=SeekBlob(image,(MagickOffsetType) tile_offset,SEEK_SET); 280 if (offset != (MagickOffsetType) tile_offset) 281 continue; 282 /* 283 Read a tile. 284 */ 285 blob=(unsigned char *) AcquireQuantumMemory((size_t) tile_length+2, 286 sizeof(*blob)); 287 if (blob == (unsigned char *) NULL) 288 { 289 if (images != (Image *) NULL) 290 images=DestroyImageList(images); 291 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 292 } 293 blob[0]=0xFF; 294 blob[1]=0xD8; 295 count=ReadBlob(image,tile_length,blob+2); 296 if (count != (ssize_t) tile_length) 297 { 298 if (images != (Image *) NULL) 299 images=DestroyImageList(images); 300 blob=(unsigned char *) RelinquishMagickMemory(blob); 301 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 302 } 303 read_info=CloneImageInfo(image_info); 304 (void) CopyMagickString(read_info->magick,"JPEG",MagickPathExtent); 305 tile_image=BlobToImage(read_info,blob,tile_length+2,exception); 306 read_info=DestroyImageInfo(read_info); 307 blob=(unsigned char *) RelinquishMagickMemory(blob); 308 offset=SeekBlob(image,restore_offset,SEEK_SET); 309 if (tile_image == (Image *) NULL) 310 continue; 311 (void) CopyMagickString(tile_image->magick,image->magick,MagickPathExtent); 312 (void) FormatImageProperty(tile_image,"jnx:northeast","%.20g,%.20g", 313 northeast.x,northeast.y); 314 (void) FormatImageProperty(tile_image,"jnx:southwest","%.20g,%.20g", 315 southwest.x,southwest.y); 316 AppendImageToList(&images,tile_image); 317 } 318 if (image->progress_monitor != (MagickProgressMonitor) NULL) 319 { 320 MagickBooleanType 321 proceed; 322 323 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType) i, 324 (MagickSizeType) jnx_info.levels); 325 if (proceed == MagickFalse) 326 status=MagickFalse; 327 } 328 } 329 (void) CloseBlob(image); 330 image=DestroyImage(image); 331 if (images == (Image *) NULL) 332 return((Image *) NULL); 333 return(GetFirstImageInList(images)); 334 } 335 336 /* 338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 339 % % 340 % % 341 % % 342 % R e g i s t e r J N X I m a g e % 343 % % 344 % % 345 % % 346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 347 % 348 % RegisterJNXImage() adds attributes for the JNX image format to the list 349 % of supported formats. The attributes include the image format tag, a 350 % method to read and/or write the format, whether the format supports the 351 % saving of more than one frame to the same file or blob, whether the format 352 % supports native in-memory I/O, and a brief description of the format. 353 % 354 % The format of the RegisterJNXImage method is: 355 % 356 % size_t RegisterJNXImage(void) 357 % 358 */ 359 ModuleExport size_t RegisterJNXImage(void) 360 { 361 MagickInfo 362 *entry; 363 364 entry=AcquireMagickInfo("JNX","JNX","Garmin tile format"); 365 entry->decoder=(DecodeImageHandler *) ReadJNXImage; 366 entry->flags|=CoderSeekableStreamFlag; 367 (void) RegisterMagickInfo(entry); 368 return(MagickImageCoderSignature); 369 } 370 371 /* 373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 374 % % 375 % % 376 % % 377 % U n r e g i s t e r J N X I m a g e % 378 % % 379 % % 380 % % 381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 382 % 383 % UnregisterJNXImage() removes format registrations made by the 384 % JNX module from the list of supported formats. 385 % 386 % The format of the UnregisterJNXImage method is: 387 % 388 % UnregisterJNXImage(void) 389 % 390 */ 391 ModuleExport void UnregisterJNXImage(void) 392 { 393 (void) UnregisterMagickInfo("JNX"); 394 } 395