/src/graphicsmagick/coders/jnx.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2012-2025 GraphicsMagick Group |
3 | | % |
4 | | % This program is covered by multiple licenses, which are described in |
5 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
6 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
7 | | % |
8 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
9 | | % % |
10 | | % % |
11 | | % J NN N X X % |
12 | | % J N N N X X % |
13 | | % J N N N XX % |
14 | | % JJ J N N N X X % |
15 | | % JJ N NN X X % |
16 | | % % |
17 | | % % |
18 | | % JNX: Garmin proprietary Image Format. % |
19 | | % % |
20 | | % % |
21 | | % Software Design % |
22 | | % Jaroslav Fojtik % |
23 | | % 2012 - 2018 % |
24 | | % % |
25 | | % % |
26 | | % % |
27 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
28 | | % |
29 | | % |
30 | | */ |
31 | | |
32 | | /* |
33 | | Include declarations. |
34 | | */ |
35 | | #include "magick/studio.h" |
36 | | #include "magick/blob.h" |
37 | | #include "magick/colormap.h" |
38 | | #include "magick/constitute.h" |
39 | | #include "magick/log.h" |
40 | | #include "magick/magick.h" |
41 | | #include "magick/monitor.h" |
42 | | #include "magick/pixel_cache.h" |
43 | | #include "magick/utility.h" |
44 | | #include "magick/tempfile.h" |
45 | | #include "magick/magic.h" |
46 | | #include "magick/resource.h" |
47 | | #include "magick/attribute.h" |
48 | | #include "magick/static.h" |
49 | | |
50 | | typedef struct |
51 | | { |
52 | | int lat, lon; |
53 | | } TJNXPoint; |
54 | | |
55 | | typedef struct |
56 | | { |
57 | | TJNXPoint NorthEast, SouthWest; |
58 | | } TJNXRect; |
59 | | |
60 | | typedef struct |
61 | | { |
62 | | unsigned Version; |
63 | | unsigned DeviceSN; |
64 | | TJNXRect MapBounds; |
65 | | unsigned Levels; |
66 | | unsigned Expiration; |
67 | | unsigned ProductID; |
68 | | unsigned CRC; |
69 | | unsigned SigVersion; |
70 | | unsigned SigOffset; |
71 | | unsigned ZOrder; |
72 | | } TJNXHeader; |
73 | | |
74 | | typedef struct |
75 | | { |
76 | | unsigned TileCount; |
77 | | unsigned TilesOffset; |
78 | | unsigned Scale; |
79 | | char *Copyright; |
80 | | unsigned Dummy; |
81 | | } TJNXLevelInfo; |
82 | | |
83 | | typedef struct |
84 | | { |
85 | | TJNXRect TileBounds; |
86 | | unsigned short PicWidth, PicHeight; |
87 | | unsigned PicSize; |
88 | | unsigned PicOffset; |
89 | | } TJNXTileInfo; |
90 | | |
91 | | |
92 | | static Image * |
93 | | ExtractTileJPG(Image * image, const ImageInfo * image_info, |
94 | | TJNXTileInfo *TileInfo, ExceptionInfo * exception) |
95 | 24.3k | { |
96 | 24.3k | size_t |
97 | 24.3k | alloc_size; |
98 | | |
99 | 24.3k | unsigned char |
100 | 24.3k | *blob; |
101 | | |
102 | 24.3k | char img_label_str[MaxTextExtent]; |
103 | | |
104 | | |
105 | 24.3k | alloc_size = (size_t) TileInfo->PicSize + 2; |
106 | | |
107 | 24.3k | if (image->logging) |
108 | 24.3k | (void) LogMagickEvent(CoderEvent, GetMagickModule(), |
109 | 24.3k | "JNX tile offset %u, size %u bytes", |
110 | 24.3k | TileInfo->PicOffset, TileInfo->PicSize); |
111 | | |
112 | 24.3k | if ((alloc_size > TileInfo->PicSize) && |
113 | 24.3k | (blob = MagickAllocateResourceLimitedMemory(unsigned char *,alloc_size)) != NULL) |
114 | 24.3k | { |
115 | | /* Add missing JPEG header bytes */ |
116 | 24.3k | blob[0] = 0xFF; |
117 | 24.3k | blob[1] = 0xD8; |
118 | | |
119 | | /* Copy JPG to memory blob */ |
120 | 24.3k | if (SeekBlob(image, TileInfo->PicOffset, SEEK_SET) == TileInfo->PicOffset) |
121 | 24.3k | { |
122 | 24.3k | if (ReadBlob(image,TileInfo->PicSize,blob+2) == TileInfo->PicSize) |
123 | 24.2k | { |
124 | 24.2k | Image |
125 | 24.2k | *image2; |
126 | | |
127 | 24.2k | ImageInfo |
128 | 24.2k | *clone_info; |
129 | | |
130 | 24.2k | clone_info=CloneImageInfo(image_info); |
131 | | |
132 | | /* BlobToFile("/tmp/jnx-tile.jpg", blob,alloc_size,exception); */ |
133 | | |
134 | 24.2k | (void) strlcpy(clone_info->filename,"JPEG:",sizeof(clone_info->filename)); |
135 | 24.2k | if ((image2 = BlobToImage(clone_info,blob,alloc_size,exception)) |
136 | 24.2k | != NULL) |
137 | 5.19k | { |
138 | | /* |
139 | | Replace current image with new image while copying |
140 | | base image attributes. |
141 | | */ |
142 | 5.19k | (void) strlcpy(image2->filename, image->filename, |
143 | 5.19k | sizeof(image2->filename)); |
144 | 5.19k | (void) strlcpy(image2->magick_filename, image->magick_filename, |
145 | 5.19k | sizeof(image2->magick_filename)); |
146 | 5.19k | (void) strlcpy(image2->magick, image->magick, |
147 | 5.19k | sizeof(image2->magick)); |
148 | 5.19k | DestroyBlob(image2); |
149 | 5.19k | image2->blob = ReferenceBlob(image->blob); |
150 | | |
151 | 5.19k | if ((image->rows == 0) || (image->columns == 0)) |
152 | 2.26k | DeleteImageFromList(&image); |
153 | | |
154 | 5.19k | FormatString(img_label_str, "%.20g;%.20g", |
155 | 5.19k | (double) TileInfo->TileBounds.NorthEast.lat*180.0/0x7FFFFFFF, |
156 | 5.19k | (double) TileInfo->TileBounds.NorthEast.lon*180.0/0x7FFFFFFF); |
157 | 5.19k | SetImageAttribute(image2, "jnx:northeast", img_label_str); |
158 | | |
159 | 5.19k | FormatString(img_label_str, "%.20g;%.20g", |
160 | 5.19k | (double) TileInfo->TileBounds.SouthWest.lat*180.0/0x7FFFFFFF, |
161 | 5.19k | (double) TileInfo->TileBounds.SouthWest.lon*180.0/0x7FFFFFFF); |
162 | 5.19k | SetImageAttribute(image2, "jnx:southwest", img_label_str); |
163 | | |
164 | 5.19k | AppendImageToList(&image, image2); |
165 | 5.19k | } |
166 | 24.2k | DestroyImageInfo(clone_info); |
167 | 24.2k | clone_info = (ImageInfo *) NULL; |
168 | 24.2k | } |
169 | 10 | else |
170 | 10 | { |
171 | | /* Failed to read enough data from input */ |
172 | 10 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
173 | 10 | image->filename); |
174 | 10 | } |
175 | 24.3k | } |
176 | 0 | else |
177 | 0 | { |
178 | | /* Failed to seek in input */ |
179 | 0 | ThrowException(exception,BlobError,UnableToSeekToOffset, |
180 | 0 | image->filename); |
181 | 0 | } |
182 | 24.3k | MagickFreeResourceLimitedMemory(unsigned char *,blob); |
183 | 24.3k | } |
184 | 0 | else |
185 | 0 | { |
186 | | /* Failed to allocate memory */ |
187 | 0 | ThrowException(exception,ResourceLimitError,MemoryAllocationFailed, |
188 | 0 | image->filename); |
189 | 0 | } |
190 | | |
191 | 24.3k | return(image); |
192 | 24.3k | } |
193 | | |
194 | | /* |
195 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
196 | | % % |
197 | | % % |
198 | | % % |
199 | | % R e a d J N X I m a g e % |
200 | | % % |
201 | | % % |
202 | | % % |
203 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
204 | | % |
205 | | % Method ReadJNXImage reads an JNX X image file and returns it. It |
206 | | % allocates the memory necessary for the new Image structure and returns a |
207 | | % pointer to the new image. |
208 | | % |
209 | | % The format of the ReadJNXImage method is: |
210 | | % |
211 | | % Image *ReadJNXImage(const ImageInfo *image_info,ExceptionInfo *exception) |
212 | | % |
213 | | % A description of each parameter follows: |
214 | | % |
215 | | % o image: Method ReadJNXImage returns a pointer to the image after |
216 | | % reading. A null image is returned if there is a memory shortage or if |
217 | | % the image cannot be read. |
218 | | % |
219 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
220 | | % |
221 | | % o exception: return any errors or warnings in this structure. |
222 | | % |
223 | | */ |
224 | | static Image * |
225 | | ReadJNXImage(const ImageInfo * image_info, ExceptionInfo * exception) |
226 | 6.99k | { |
227 | 6.99k | Image |
228 | 6.99k | *image; |
229 | | |
230 | 6.99k | unsigned int |
231 | 6.99k | i, |
232 | 6.99k | j; |
233 | | |
234 | 6.99k | TJNXHeader |
235 | 6.99k | JNXHeader; |
236 | | |
237 | 6.99k | TJNXLevelInfo |
238 | 6.99k | JNXLevelInfo[20]; |
239 | | |
240 | 6.99k | unsigned int |
241 | 6.99k | status; |
242 | | |
243 | 6.99k | TJNXTileInfo |
244 | 6.99k | *PositionList = NULL; |
245 | | |
246 | 6.99k | int |
247 | 6.99k | logging; |
248 | | |
249 | 6.99k | magick_int64_t |
250 | 6.99k | SaveLimit; |
251 | | |
252 | 6.99k | unsigned int |
253 | 6.99k | total_tiles, |
254 | 6.99k | current_tile; |
255 | | |
256 | 6.99k | magick_off_t |
257 | 6.99k | file_size; |
258 | | |
259 | | /* Open image file. */ |
260 | 6.99k | assert(image_info != (const ImageInfo *) NULL); |
261 | 6.99k | assert(image_info->signature == MagickSignature); |
262 | 6.99k | assert(exception != (ExceptionInfo *) NULL); |
263 | 6.99k | assert(exception->signature == MagickSignature); |
264 | 6.99k | logging = LogMagickEvent(CoderEvent, GetMagickModule(), "enter"); |
265 | | |
266 | 6.99k | image = AllocateImage(image_info); |
267 | 6.99k | image->rows = 0; |
268 | 6.99k | image->columns = 0; |
269 | 6.99k | status = OpenBlob(image_info, image, ReadBinaryBlobMode, exception); |
270 | 6.99k | if (status == False) |
271 | 6.99k | ThrowReaderException(FileOpenError, UnableToOpenFile, image); |
272 | | |
273 | | /* Read JNX image header. */ |
274 | 6.99k | (void) memset(&JNXHeader, 0, sizeof(JNXHeader)); |
275 | 6.99k | JNXHeader.Version = ReadBlobLSBLong(image); |
276 | 6.99k | if (JNXHeader.Version > 4) |
277 | 6.95k | ThrowReaderException(CorruptImageError, ImproperImageHeader, image); |
278 | 6.95k | JNXHeader.DeviceSN = ReadBlobLSBLong(image); |
279 | 6.95k | JNXHeader.MapBounds.NorthEast.lat = ReadBlobLSBLong(image); |
280 | 6.95k | JNXHeader.MapBounds.NorthEast.lon = ReadBlobLSBLong(image); |
281 | 6.95k | JNXHeader.MapBounds.SouthWest.lat = ReadBlobLSBLong(image); |
282 | 6.95k | JNXHeader.MapBounds.SouthWest.lon = ReadBlobLSBLong(image); |
283 | 6.95k | JNXHeader.Levels = ReadBlobLSBLong(image); |
284 | 6.95k | JNXHeader.Expiration = ReadBlobLSBLong(image); |
285 | 6.95k | JNXHeader.ProductID = ReadBlobLSBLong(image); |
286 | 6.95k | JNXHeader.CRC = ReadBlobLSBLong(image); |
287 | 6.95k | JNXHeader.SigVersion = ReadBlobLSBLong(image); |
288 | 6.95k | JNXHeader.SigOffset = ReadBlobLSBLong(image); |
289 | 6.95k | if (JNXHeader.Version >= 4) |
290 | 41 | JNXHeader.ZOrder = ReadBlobLSBLong(image); |
291 | | |
292 | 6.95k | if (EOFBlob(image)) |
293 | 6.92k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
294 | | |
295 | 6.92k | file_size = GetBlobSize(image); |
296 | | |
297 | 6.92k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
298 | 6.92k | "JNX Header:\n" |
299 | 6.92k | " Version: %u\n" |
300 | 6.92k | " DeviceSN: %u\n" |
301 | 6.92k | " MapBounds:\n" |
302 | 6.92k | " NorthEast: lat = %u, lon = %u\n" |
303 | 6.92k | " SouthWest: lat = %u, lon = %u\n" |
304 | 6.92k | " Levels: %u\n" |
305 | 6.92k | " Expiration: %u\n" |
306 | 6.92k | " ProductID: %u\n" |
307 | 6.92k | " CRC: %u\n" |
308 | 6.92k | " SigVersion: %u\n" |
309 | 6.92k | " SigOffset: %u\n" |
310 | 6.92k | " ZOrder: %u", |
311 | 6.92k | JNXHeader.Version, |
312 | 6.92k | JNXHeader.DeviceSN, |
313 | 6.92k | JNXHeader.MapBounds.NorthEast.lat, |
314 | 6.92k | JNXHeader.MapBounds.NorthEast.lon, |
315 | 6.92k | JNXHeader.MapBounds.SouthWest.lat, |
316 | 6.92k | JNXHeader.MapBounds.SouthWest.lon, |
317 | 6.92k | JNXHeader.Levels, |
318 | 6.92k | JNXHeader.Expiration, |
319 | 6.92k | JNXHeader.ProductID, |
320 | 6.92k | JNXHeader.CRC, |
321 | 6.92k | JNXHeader.SigVersion, |
322 | 6.92k | JNXHeader.SigOffset, |
323 | 6.92k | JNXHeader.ZOrder); |
324 | | |
325 | 6.92k | if (JNXHeader.Levels > 20) |
326 | 6.88k | ThrowReaderException(CorruptImageError, ImproperImageHeader, image); |
327 | | |
328 | | /* Read JNX image level info. */ |
329 | 6.88k | memset(JNXLevelInfo, 0, sizeof(JNXLevelInfo)); |
330 | 6.88k | total_tiles = 0; |
331 | 6.88k | current_tile = 0; |
332 | 46.7k | for (i = 0; i < JNXHeader.Levels; i++) |
333 | 39.8k | { |
334 | 39.8k | JNXLevelInfo[i].TileCount = ReadBlobLSBLong(image); |
335 | 39.8k | JNXLevelInfo[i].TilesOffset = ReadBlobLSBLong(image); |
336 | 39.8k | JNXLevelInfo[i].Scale = ReadBlobLSBLong(image); |
337 | 39.8k | total_tiles += JNXLevelInfo[i].TileCount; |
338 | | |
339 | 39.8k | if (JNXHeader.Version >= 4) |
340 | 267 | { |
341 | 267 | JNXLevelInfo[i].Dummy = ReadBlobLSBLong(image); |
342 | 267 | JNXLevelInfo[i].Copyright = NULL; |
343 | 3.07M | while (ReadBlobLSBShort(image) != 0) |
344 | 3.07M | { |
345 | | /* char *Copyright; */ |
346 | 3.07M | } |
347 | 267 | } |
348 | 39.6k | else |
349 | 39.6k | { |
350 | 39.6k | JNXLevelInfo[i].Copyright = NULL; |
351 | 39.6k | } |
352 | | |
353 | 39.8k | if (EOFBlob(image)) |
354 | 39.8k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
355 | | |
356 | 39.8k | if (image->logging) |
357 | 39.8k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
358 | 39.8k | "Level[%u] Info:" |
359 | 39.8k | " TileCount: %4u" |
360 | 39.8k | " TilesOffset: %6u" |
361 | 39.8k | " Scale: %04u", |
362 | 39.8k | i, |
363 | 39.8k | JNXLevelInfo[i].TileCount, |
364 | 39.8k | JNXLevelInfo[i].TilesOffset, |
365 | 39.8k | JNXLevelInfo[i].Scale |
366 | 39.8k | ); |
367 | 39.8k | } |
368 | | |
369 | | /* Get the current limit */ |
370 | 6.83k | SaveLimit = GetMagickResourceLimit(MapResource); |
371 | | |
372 | | /* Temporarily set the limit to zero */ |
373 | 6.83k | SetMagickResourceLimit(MapResource, 0); |
374 | | |
375 | | /* Read JNX image data. */ |
376 | 30.7k | for (i = 0; i < JNXHeader.Levels; i++) |
377 | 27.7k | { |
378 | | /* |
379 | | Validate TileCount against remaining file data |
380 | | */ |
381 | 27.7k | const magick_off_t current_offset = TellBlob(image); |
382 | 27.7k | const size_t pos_list_entry_size = |
383 | 27.7k | sizeof(magick_uint32_t) + sizeof(magick_uint32_t) + sizeof(magick_uint32_t) + |
384 | 27.7k | sizeof(magick_uint32_t) + sizeof(magick_uint16_t) + sizeof(magick_uint16_t) + |
385 | 27.7k | sizeof(magick_uint32_t) + sizeof(magick_uint32_t); |
386 | 27.7k | const magick_off_t remaining = file_size-current_offset; |
387 | 27.7k | const size_t needed = MagickArraySize(pos_list_entry_size,JNXLevelInfo[i].TileCount); |
388 | | |
389 | 27.7k | if ((needed == 0U) || (remaining <= 0) || (remaining < (magick_off_t) needed)) |
390 | 3.43k | { |
391 | 3.43k | (void) SetMagickResourceLimit(MapResource, SaveLimit); |
392 | 3.43k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
393 | 0 | } |
394 | | |
395 | 24.3k | PositionList = MagickAllocateResourceLimitedArray(TJNXTileInfo *, |
396 | 24.3k | JNXLevelInfo[i].TileCount, |
397 | 24.3k | sizeof(TJNXTileInfo)); |
398 | 24.3k | if (PositionList == NULL) |
399 | 0 | { |
400 | 0 | (void) SetMagickResourceLimit(MapResource, SaveLimit); |
401 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed, |
402 | 0 | image); |
403 | 0 | } |
404 | | |
405 | 24.3k | (void) SeekBlob(image, JNXLevelInfo[i].TilesOffset, SEEK_SET); |
406 | 49.9k | for (j = 0; j < JNXLevelInfo[i].TileCount; j++) |
407 | 26.0k | { |
408 | 26.0k | PositionList[j].TileBounds.NorthEast.lat = ReadBlobLSBLong(image); |
409 | 26.0k | PositionList[j].TileBounds.NorthEast.lon = ReadBlobLSBLong(image); |
410 | 26.0k | PositionList[j].TileBounds.SouthWest.lat = ReadBlobLSBLong(image); |
411 | 26.0k | PositionList[j].TileBounds.SouthWest.lon = ReadBlobLSBLong(image); |
412 | 26.0k | PositionList[j].PicWidth = ReadBlobLSBShort(image); |
413 | 26.0k | PositionList[j].PicHeight = ReadBlobLSBShort(image); |
414 | 26.0k | PositionList[j].PicSize = ReadBlobLSBLong(image); |
415 | 26.0k | PositionList[j].PicOffset = ReadBlobLSBLong(image); |
416 | | |
417 | 26.0k | if (EOFBlob(image) || |
418 | 25.6k | ((magick_off_t) PositionList[j].PicOffset + |
419 | 25.6k | PositionList[j].PicSize > file_size)) |
420 | 455 | { |
421 | 455 | (void) SetMagickResourceLimit(MapResource, SaveLimit); |
422 | 455 | MagickFreeResourceLimitedMemory(TJNXTileInfo *,PositionList); |
423 | 455 | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
424 | 0 | } |
425 | 26.0k | } |
426 | | |
427 | 29.0k | for (j = 0; j < JNXLevelInfo[i].TileCount; j++) |
428 | 24.3k | { |
429 | 24.3k | MonitorHandler |
430 | 24.3k | previous_handler; |
431 | | |
432 | | /* Disable progress monitor while loading individual tiles */ |
433 | 24.3k | previous_handler = SetMonitorHandler(0); |
434 | 24.3k | image = ExtractTileJPG(image, image_info, PositionList+j, exception); |
435 | 24.3k | (void) SetMonitorHandler(previous_handler); |
436 | | |
437 | 24.3k | if (exception->severity >= ErrorException) |
438 | 19.1k | break; |
439 | | |
440 | 5.19k | current_tile++; |
441 | 5.19k | if (QuantumTick(current_tile,total_tiles)) |
442 | 2.39k | if (!MagickMonitorFormatted(current_tile,total_tiles,exception, |
443 | 2.39k | LoadImageText,image->filename, |
444 | 2.39k | image->columns,image->rows)) |
445 | 0 | break; |
446 | 5.19k | } |
447 | | |
448 | 23.8k | MagickFreeResourceLimitedMemory(TJNXTileInfo *,PositionList); |
449 | 23.8k | } |
450 | | |
451 | 2.94k | CloseBlob(image); |
452 | | |
453 | | /* Restore the previous limit */ |
454 | 2.94k | (void) SetMagickResourceLimit(MapResource, SaveLimit); |
455 | | |
456 | 2.94k | { |
457 | 2.94k | Image *p; |
458 | 2.94k | long scene = 0; |
459 | | |
460 | | /* Rewind list, removing any empty images while rewinding. */ |
461 | 2.94k | p = image; |
462 | 2.94k | image = NULL; |
463 | 6.75k | while (p != (Image *) NULL) |
464 | 3.81k | { |
465 | 3.81k | Image *tmp = p; |
466 | 3.81k | if ((p->rows == 0) || (p->columns == 0)) |
467 | 1.83k | { |
468 | 1.83k | p = p->previous; |
469 | 1.83k | DeleteImageFromList(&tmp); |
470 | 1.83k | } |
471 | 1.97k | else |
472 | 1.97k | { |
473 | 1.97k | image = p; |
474 | 1.97k | p = p->previous; |
475 | 1.97k | } |
476 | 3.81k | } |
477 | | |
478 | | /* Fix scene numbers */ |
479 | 4.92k | for (p = image; p != (Image *) NULL; p = p->next) |
480 | 1.97k | p->scene = scene++; |
481 | 2.94k | } |
482 | | |
483 | 2.94k | if (logging) |
484 | 0 | (void) LogMagickEvent(CoderEvent, GetMagickModule(), "return"); |
485 | 2.94k | if (image == NULL) |
486 | 1.83k | ThrowReaderException(CorruptImageError, ImageFileDoesNotContainAnyImageData, |
487 | 2.94k | image); |
488 | | |
489 | 1.10k | return (image); |
490 | 2.94k | } |
491 | | |
492 | | /* |
493 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
494 | | % % |
495 | | % % |
496 | | % % |
497 | | % W r i t e J N X I m a g e % |
498 | | % % |
499 | | % % |
500 | | % % |
501 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
502 | | % |
503 | | % Function WriteJNXImage writes an JNX image to a file. |
504 | | % |
505 | | % The format of the WriteJNXImage method is: |
506 | | % |
507 | | % unsigned int WriteJNXImage(const ImageInfo *image_info,Image *image) |
508 | | % |
509 | | % A description of each parameter follows. |
510 | | % |
511 | | % o status: Function WriteJNXImage return True if the image is written. |
512 | | % False is returned is there is a memory shortage or if the image file |
513 | | % fails to write. |
514 | | % |
515 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
516 | | % |
517 | | % o image: A pointer to an Image structure. |
518 | | % |
519 | | */ |
520 | | /* |
521 | | static MagickPassFail WriteJNXImage(const ImageInfo *image_info,Image *image) |
522 | | { |
523 | | return(0); |
524 | | } |
525 | | */ |
526 | | |
527 | | /* |
528 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
529 | | % % |
530 | | % % |
531 | | % % |
532 | | % R e g i s t e r J N X I m a g e % |
533 | | % % |
534 | | % % |
535 | | % % |
536 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
537 | | % |
538 | | % Method RegisterJNXImage adds attributes for the JNX image format to |
539 | | % the list of supported formats. The attributes include the image format |
540 | | % tag, a method to read and/or write the format, whether the format |
541 | | % supports the saving of more than one frame to the same file or blob, |
542 | | % whether the format supports native in-memory I/O, and a brief |
543 | | % description of the format. |
544 | | % |
545 | | % The format of the RegisterJNXImage method is: |
546 | | % |
547 | | % RegisterJNXImage(void) |
548 | | % |
549 | | */ |
550 | | ModuleExport void RegisterJNXImage(void) |
551 | 1 | { |
552 | 1 | MagickInfo |
553 | 1 | *entry; |
554 | | |
555 | 1 | entry = SetMagickInfo("JNX"); |
556 | 1 | entry->decoder = (DecoderHandler) ReadJNXImage; |
557 | | /* entry->encoder = (EncoderHandler)WriteJNXImage; */ |
558 | 1 | entry->description = "JNX: Garmin tile storage format"; |
559 | 1 | entry->module = "JNX"; |
560 | 1 | (void) RegisterMagickInfo(entry); |
561 | 1 | } |
562 | | |
563 | | /* |
564 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
565 | | % % |
566 | | % % |
567 | | % % |
568 | | % U n r e g i s t e r J N X I m a g e % |
569 | | % % |
570 | | % % |
571 | | % % |
572 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
573 | | % |
574 | | % Method UnregisterJNXImage removes format registrations made by the |
575 | | % JNX module from the list of supported formats. |
576 | | % |
577 | | % The format of the UnregisterJNXImage method is: |
578 | | % |
579 | | % UnregisterJNXImage(void) |
580 | | % |
581 | | */ |
582 | | ModuleExport void UnregisterJNXImage(void) |
583 | 0 | { |
584 | 0 | (void) UnregisterMagickInfo("JNX"); |
585 | 0 | } |