Home | History | Annotate | Download | only in coders
      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