1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % RRRR GGG FFFFF %
7 % R R G F %
8 % RRRR G GG FFF %
9 % R R G G F %
10 % R R GGG F %
11 % %
12 % %
13 % Read/Write LEGO Mindstorms EV3 Robot Graphics File %
14 % %
15 % Software Design %
16 % Brian Wheeler %
17 % August 2013 %
18 % %
19 % %
20 % Copyright 1999-2019 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/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colormap.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/image.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/monitor.h"
59 #include "MagickCore/monitor-private.h"
60 #include "MagickCore/pixel-accessor.h"
61 #include "MagickCore/quantum-private.h"
62 #include "MagickCore/static.h"
63 #include "MagickCore/string_.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/utility.h"
66
67 /*
68 Forward declarations.
69 */
70 static MagickBooleanType
71 WriteRGFImage(const ImageInfo *,Image *,ExceptionInfo *);
72
73 /*
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 % %
76 % %
77 % %
78 % R e a d X B M I m a g e %
79 % %
80 % %
81 % %
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 %
84 % ReadRGFImage() reads an RGF bitmap image file and returns it. It
85 % allocates the memory necessary for the new Image structure and returns a
86 % pointer to the new image.
87 %
88 % The format of the ReadRGFImage method is:
89 %
90 % Image *ReadRGFImage(const ImageInfo *image_info,ExceptionInfo *exception)
91 %
92 % A description of each parameter follows:
93 %
94 % o image_info: the image info.
95 %
96 % o exception: return any errors or warnings in this structure.
97 %
98 */
ReadRGFImage(const ImageInfo * image_info,ExceptionInfo * exception)99 static Image *ReadRGFImage(const ImageInfo *image_info,ExceptionInfo *exception)
100 {
101 Image
102 *image;
103
104 int
105 bit;
106
107 MagickBooleanType
108 status;
109
110 register ssize_t
111 i,
112 x;
113
114 register Quantum
115 *q;
116
117 register unsigned char
118 *p;
119
120 ssize_t
121 y;
122
123 unsigned char
124 byte,
125 *data;
126
127 /*
128 Open image file.
129 */
130 assert(image_info != (const ImageInfo *) NULL);
131 assert(image_info->signature == MagickCoreSignature);
132 if (image_info->debug != MagickFalse)
133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
134 image_info->filename);
135 assert(exception != (ExceptionInfo *) NULL);
136 assert(exception->signature == MagickCoreSignature);
137 image=AcquireImage(image_info,exception);
138 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
139 if (status == MagickFalse)
140 {
141 image=DestroyImageList(image);
142 return((Image *) NULL);
143 }
144 /*
145 Read RGF header.
146 */
147 image->columns = (unsigned long) ReadBlobByte(image);
148 image->rows = (unsigned long) ReadBlobByte(image);
149 image->depth=8;
150 image->storage_class=PseudoClass;
151 image->colors=2;
152 /*
153 Initialize image structure.
154 */
155 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
156 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
157 /*
158 Initialize colormap.
159 */
160 image->colormap[0].red=QuantumRange;
161 image->colormap[0].green=QuantumRange;
162 image->colormap[0].blue=QuantumRange;
163 image->colormap[1].red=(Quantum) 0;
164 image->colormap[1].green=(Quantum) 0;
165 image->colormap[1].blue=(Quantum) 0;
166 if (image_info->ping != MagickFalse)
167 {
168 (void) CloseBlob(image);
169 return(GetFirstImageInList(image));
170 }
171 status=SetImageExtent(image,image->columns,image->rows,exception);
172 if (status == MagickFalse)
173 return(DestroyImageList(image));
174 /*
175 Read hex image data.
176 */
177 data=(unsigned char *) AcquireQuantumMemory(image->rows,image->columns*
178 sizeof(*data));
179 if (data == (unsigned char *) NULL)
180 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
181 p=data;
182 for (i=0; i < (ssize_t) (image->columns * image->rows); i++)
183 {
184 *p++=ReadBlobByte(image);
185 }
186
187 /*
188 Convert RGF image to pixel packets.
189 */
190 p=data;
191 for (y=0; y < (ssize_t) image->rows; y++)
192 {
193 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
194 if (q == (Quantum *) NULL)
195 break;
196 bit=0;
197 byte=0;
198 for (x=0; x < (ssize_t) image->columns; x++)
199 {
200 if (bit == 0)
201 byte=(size_t) (*p++);
202 SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q);
203 bit++;
204 byte>>=1;
205 if (bit == 8)
206 bit=0;
207 q+=GetPixelChannels(image);
208 }
209 if (SyncAuthenticPixels(image,exception) == MagickFalse)
210 break;
211 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
212 image->rows);
213 if (status == MagickFalse)
214 break;
215 }
216 data=(unsigned char *) RelinquishMagickMemory(data);
217 (void) SyncImage(image,exception);
218 (void) CloseBlob(image);
219 return(GetFirstImageInList(image));
220 }
221
222 /*
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 % %
225 % %
226 % %
227 % R e g i s t e r R G F I m a g e %
228 % %
229 % %
230 % %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 %
233 % RegisterRGFImage() adds attributes for the RGF image format to
234 % the list of supported formats. The attributes include the image format
235 % tag, a method to read and/or write the format, whether the format
236 % supports the saving of more than one frame to the same file or blob,
237 % whether the format supports native in-memory I/O, and a brief
238 % description of the format.
239 %
240 % The format of the RegisterRGFImage method is:
241 %
242 % size_t RegisterRGFImage(void)
243 %
244 */
RegisterRGFImage(void)245 ModuleExport size_t RegisterRGFImage(void)
246 {
247 MagickInfo
248 *entry;
249
250 entry=AcquireMagickInfo("RGF","RGF",
251 "LEGO Mindstorms EV3 Robot Graphic Format (black and white)");
252 entry->decoder=(DecodeImageHandler *) ReadRGFImage;
253 entry->encoder=(EncodeImageHandler *) WriteRGFImage;
254 entry->flags^=CoderAdjoinFlag;
255 (void) RegisterMagickInfo(entry);
256 return(MagickImageCoderSignature);
257 }
258
259 /*
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 % %
262 % %
263 % %
264 % U n r e g i s t e r R G F I m a g e %
265 % %
266 % %
267 % %
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 %
270 % UnregisterRGFImage() removes format registrations made by the
271 % RGF module from the list of supported formats.
272 %
273 % The format of the UnregisterRGFImage method is:
274 %
275 % UnregisterRGFImage(void)
276 %
277 */
UnregisterRGFImage(void)278 ModuleExport void UnregisterRGFImage(void)
279 {
280 (void) UnregisterMagickInfo("RGF");
281 }
282
283 /*
284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 % %
286 % %
287 % %
288 % W r i t e R G F I m a g e %
289 % %
290 % %
291 % %
292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293 %
294 % WriteRGFImage() writes an image to a file in the X bitmap format.
295 %
296 % The format of the WriteRGFImage method is:
297 %
298 % MagickBooleanType WriteRGFImage(const ImageInfo *image_info,
299 % Image *image,ExceptionInfo *exception)
300 %
301 % A description of each parameter follows.
302 %
303 % o image_info: the image info.
304 %
305 % o image: The image.
306 %
307 % o exception: return any errors or warnings in this structure.
308 %
309 */
WriteRGFImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)310 static MagickBooleanType WriteRGFImage(const ImageInfo *image_info,Image *image,
311 ExceptionInfo *exception)
312 {
313 MagickBooleanType
314 status;
315
316 register const Quantum
317 *p;
318
319 register ssize_t
320 x;
321
322 size_t
323 bit,
324 byte;
325
326 ssize_t
327 y;
328
329 /*
330 Open output image file.
331 */
332 assert(image_info != (const ImageInfo *) NULL);
333 assert(image_info->signature == MagickCoreSignature);
334 assert(image != (Image *) NULL);
335 assert(image->signature == MagickCoreSignature);
336 if (image->debug != MagickFalse)
337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
338 assert(exception != (ExceptionInfo *) NULL);
339 assert(exception->signature == MagickCoreSignature);
340 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
341 if (status == MagickFalse)
342 return(status);
343 (void) TransformImageColorspace(image,sRGBColorspace,exception);
344 if((image->columns > 255L) || (image->rows > 255L))
345 ThrowWriterException(ImageError,"Dimensions must be less than 255x255");
346 /*
347 Write header (just the image dimensions)
348 */
349 (void) WriteBlobByte(image,image->columns & 0xff);
350 (void) WriteBlobByte(image,image->rows & 0xff);
351 /*
352 Convert MIFF to bit pixels.
353 */
354 (void) SetImageType(image,BilevelType,exception);
355 x=0;
356 y=0;
357 for (y=0; y < (ssize_t) image->rows; y++)
358 {
359 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
360 if (p == (const Quantum *) NULL)
361 break;
362 bit=0;
363 byte=0;
364 for (x=0; x < (ssize_t) image->columns; x++)
365 {
366 byte>>=1;
367 if (GetPixelLuma(image,p) < (QuantumRange/2.0))
368 byte|=0x80;
369 bit++;
370 if (bit == 8)
371 {
372 /*
373 Write a bitmap byte to the image file.
374 */
375 (void) WriteBlobByte(image,(unsigned char) byte);
376 bit=0;
377 byte=0;
378 }
379 p+=GetPixelChannels(image);
380 }
381 if (bit != 0)
382 {
383 byte >>= 8 - bit;
384 (void) WriteBlobByte(image,(unsigned char) byte);
385 }
386 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
387 image->rows);
388 if (status == MagickFalse)
389 break;
390 }
391 (void) CloseBlob(image);
392 return(MagickTrue);
393 }
394