1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M GGGG K K %
7 % MM MM G K K %
8 % M M M G GG KKK %
9 % M M G G K K %
10 % M M GGG K K %
11 % %
12 % %
13 % Read/Write MGK Image Format. %
14 % %
15 % Software Design %
16 % John Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include <MagickCore/studio.h>
43 #include <MagickCore/blob.h>
44 #include <MagickCore/cache.h>
45 #include <MagickCore/colorspace.h>
46 #include <MagickCore/exception.h>
47 #include <MagickCore/image.h>
48 #include <MagickCore/list.h>
49 #include <MagickCore/magick.h>
50 #include <MagickCore/memory_.h>
51 #include <MagickCore/monitor.h>
52 #include <MagickCore/pixel-accessor.h>
53 #include <MagickCore/string_.h>
54 #include <MagickCore/module.h>
55
56 /*
57 Forward declarations.
58 */
59 static MagickBooleanType
60 WriteMGKImage(const ImageInfo *,Image *,ExceptionInfo *);
61
62 /*
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 % %
65 % %
66 % %
67 % I s M G K %
68 % %
69 % %
70 % %
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %
73 % IsMGK() returns MagickTrue if the image format type, identified by the
74 % magick string, is MGK.
75 %
76 % The format of the IsMGK method is:
77 %
78 % MagickBooleanType IsMGK(const unsigned char *magick,const size_t length)
79 %
80 % A description of each parameter follows:
81 %
82 % o magick: This string is generally the first few bytes of an image file
83 % or blob.
84 %
85 % o length: Specifies the length of the magick string.
86 %
87 */
IsMGK(const unsigned char * magick,const size_t length)88 static MagickBooleanType IsMGK(const unsigned char *magick,const size_t length)
89 {
90 if (length < 7)
91 return(MagickFalse);
92 if (LocaleNCompare((char *) magick,"id=mgk",7) == 0)
93 return(MagickTrue);
94 return(MagickFalse);
95 }
96
97 /*
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 % %
100 % %
101 % %
102 % R e a d M G K I m a g e %
103 % %
104 % %
105 % %
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %
108 % ReadMGKImage() reads a MGK image file and returns it. It allocates the
109 % memory necessary for the new Image structure and returns a pointer to the
110 % new image.
111 %
112 % The format of the ReadMGKImage method is:
113 %
114 % Image *ReadMGKImage(const ImageInfo *image_info,
115 % ExceptionInfo *exception)
116 %
117 % A description of each parameter follows:
118 %
119 % o image_info: the image info.
120 %
121 % o exception: return any errors or warnings in this structure.
122 %
123 */
ReadMGKImage(const ImageInfo * image_info,ExceptionInfo * exception)124 static Image *ReadMGKImage(const ImageInfo *image_info,ExceptionInfo *exception)
125 {
126 char
127 buffer[MaxTextExtent];
128
129 Image
130 *image;
131
132 long
133 y;
134
135 MagickBooleanType
136 status;
137
138 register long
139 x;
140
141 register Quantum
142 *q;
143
144 register unsigned char
145 *p;
146
147 ssize_t
148 count;
149
150 unsigned char
151 *pixels;
152
153 unsigned long
154 columns,
155 rows;
156
157 /*
158 Open image file.
159 */
160 assert(image_info != (const ImageInfo *) NULL);
161 assert(image_info->signature == MagickCoreSignature);
162 if (image_info->debug != MagickFalse)
163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
164 image_info->filename);
165 assert(exception != (ExceptionInfo *) NULL);
166 assert(exception->signature == MagickCoreSignature);
167 image=AcquireImage(image_info,exception);
168 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
169 if (status == MagickFalse)
170 {
171 image=DestroyImageList(image);
172 return((Image *) NULL);
173 }
174 /*
175 Read MGK image.
176 */
177 (void) ReadBlobString(image,buffer); /* read magic number */
178 if (IsMGK(buffer,7) == MagickFalse)
179 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
180 (void) ReadBlobString(image,buffer);
181 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows);
182 if (count <= 0)
183 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
184 do
185 {
186 /*
187 Initialize image structure.
188 */
189 image->columns=columns;
190 image->rows=rows;
191 image->depth=8;
192 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
193 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
194 break;
195 /*
196 Convert MGK raster image to pixel packets.
197 */
198 if (SetImageExtent(image,image->columns,image->rows,exception) == MagickFalse)
199 return(DestroyImageList(image));
200 pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->columns,
201 3UL*sizeof(*pixels));
202 if (pixels == (unsigned char *) NULL)
203 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
204 for (y=0; y < (ssize_t) image->rows; y++)
205 {
206 count=(ssize_t) ReadBlob(image,(size_t) (3*image->columns),pixels);
207 if (count != (ssize_t) (3*image->columns))
208 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
209 p=pixels;
210 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
211 if (q == (Quantum *) NULL)
212 break;
213 for (x=0; x < (ssize_t) image->columns; x++)
214 {
215 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
216 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
217 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
218 q+=GetPixelChannels(image);
219 }
220 if (SyncAuthenticPixels(image,exception) == MagickFalse)
221 break;
222 if (image->previous == (Image *) NULL)
223 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
224 (QuantumTick(y,image->rows) != MagickFalse))
225 {
226 status=image->progress_monitor(LoadImageTag,y,image->rows,
227 image->client_data);
228 if (status == MagickFalse)
229 break;
230 }
231 }
232 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
233 if (EOFBlob(image) != MagickFalse)
234 {
235 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
236 image->filename);
237 break;
238 }
239 /*
240 Proceed to next image.
241 */
242 if (image_info->number_scenes != 0)
243 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
244 break;
245 *buffer='\0';
246 (void) ReadBlobString(image,buffer);
247 count=(ssize_t) sscanf(buffer,"%lu %lu\n",&columns,&rows);
248 if (count > 0)
249 {
250 /*
251 Allocate next image structure.
252 */
253 AcquireNextImage(image_info,image,exception);
254 if (GetNextImageInList(image) == (Image *) NULL)
255 {
256 status=MagickFalse;
257 break;
258 }
259 image=SyncNextImageInList(image);
260 if (image->progress_monitor != (MagickProgressMonitor) NULL)
261 {
262 status=SetImageProgress(image,LoadImageTag,TellBlob(image),
263 GetBlobSize(image));
264 if (status == MagickFalse)
265 break;
266 }
267 }
268 } while (count > 0);
269 (void) CloseBlob(image);
270 if (status == MagickFalse)
271 return(DestroyImageList(image));
272 return(GetFirstImageInList(image));
273 }
274
275 /*
276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 % %
278 % %
279 % %
280 % R e g i s t e r M G K I m a g e %
281 % %
282 % %
283 % %
284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 %
286 % RegisterMGKImage() adds attributes for the MGK image format to
287 % the list of supported formats. The attributes include the image format
288 % tag, a method to read and/or write the format, whether the format
289 % supports the saving of more than one frame to the same file or blob,
290 % whether the format supports native in-memory I/O, and a brief
291 % description of the format.
292 %
293 % The format of the RegisterMGKImage method is:
294 %
295 % unsigned long RegisterMGKImage(void)
296 %
297 */
RegisterMGKImage(void)298 ModuleExport unsigned long RegisterMGKImage(void)
299 {
300 MagickInfo
301 *entry;
302
303 entry=AcquireMagickInfo("MGK","MGK","MGK image");
304 entry->decoder=(DecodeImageHandler *) ReadMGKImage;
305 entry->encoder=(EncodeImageHandler *) WriteMGKImage;
306 entry->magick=(IsImageFormatHandler *) IsMGK;
307 (void) RegisterMagickInfo(entry);
308 return(MagickImageCoderSignature);
309 }
310
311 /*
312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 % %
314 % %
315 % %
316 % U n r e g i s t e r M G K I m a g e %
317 % %
318 % %
319 % %
320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 %
322 % UnregisterMGKImage() removes format registrations made by the
323 % MGK module from the list of supported formats.
324 %
325 % The format of the UnregisterMGKImage method is:
326 %
327 % UnregisterMGKImage(void)
328 %
329 */
UnregisterMGKImage(void)330 ModuleExport void UnregisterMGKImage(void)
331 {
332 (void) UnregisterMagickInfo("MGK");
333 }
334
335 /*
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 % %
338 % %
339 % %
340 % W r i t e M G K I m a g e %
341 % %
342 % %
343 % %
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345 %
346 % WriteMGKImage() writes an image to a file in red, green, and blue MGK
347 % rasterfile format.
348 %
349 % The format of the WriteMGKImage method is:
350 %
351 % MagickBooleanType WriteMGKImage(const ImageInfo *image_info,
352 % Image *image)
353 %
354 % A description of each parameter follows.
355 %
356 % o image_info: the image info.
357 %
358 % o image: The image.
359 %
360 % o exception: return any errors or warnings in this structure.
361 %
362 */
WriteMGKImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)363 static MagickBooleanType WriteMGKImage(const ImageInfo *image_info,Image *image,
364 ExceptionInfo *exception)
365 {
366 char
367 buffer[MaxTextExtent];
368
369 long
370 y;
371
372 MagickBooleanType
373 status;
374
375 MagickOffsetType
376 scene;
377
378 register const Quantum
379 *p;
380
381 register long
382 x;
383
384 register unsigned char
385 *q;
386
387 unsigned char
388 *pixels;
389
390 /*
391 Open output image file.
392 */
393 assert(image_info != (const ImageInfo *) NULL);
394 assert(image_info->signature == MagickCoreSignature);
395 assert(image != (Image *) NULL);
396 assert(image->signature == MagickCoreSignature);
397 if (image->debug != MagickFalse)
398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
399 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
400 if (status == MagickFalse)
401 return(status);
402 scene=0;
403 do
404 {
405 /*
406 Allocate memory for pixels.
407 */
408 if (image->colorspace != RGBColorspace)
409 (void) SetImageColorspace(image,RGBColorspace,exception);
410 pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->columns,
411 3UL*sizeof(*pixels));
412 if (pixels == (unsigned char *) NULL)
413 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
414 /*
415 Initialize raster file header.
416 */
417 (void) WriteBlobString(image,"id=mgk\n");
418 (void) FormatLocaleString(buffer,MaxTextExtent,"%lu %lu\n",image->columns,
419 image->rows);
420 (void) WriteBlobString(image,buffer);
421 for (y=0; y < (ssize_t) image->rows; y++)
422 {
423 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
424 if (p == (const Quantum *) NULL)
425 break;
426 q=pixels;
427 for (x=0; x < (ssize_t) image->columns; x++)
428 {
429 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
430 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
431 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
432 p+=GetPixelChannels(image);
433 }
434 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
435 if (image->previous == (Image *) NULL)
436 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
437 (QuantumTick(y,image->rows) != MagickFalse))
438 {
439 status=image->progress_monitor(SaveImageTag,y,image->rows,
440 image->client_data);
441 if (status == MagickFalse)
442 break;
443 }
444 }
445 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
446 if (GetNextImageInList(image) == (Image *) NULL)
447 break;
448 image=SyncNextImageInList(image);
449 status=SetImageProgress(image,SaveImagesTag,scene,
450 GetImageListLength(image));
451 if (status == MagickFalse)
452 break;
453 scene++;
454 } while (image_info->adjoin != MagickFalse);
455 (void) CloseBlob(image);
456 return(MagickTrue);
457 }
458