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