/src/imagemagick/coders/rgf.c
Line | Count | Source |
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 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 | | */ |
99 | | static Image *ReadRGFImage(const ImageInfo *image_info,ExceptionInfo *exception) |
100 | 693 | { |
101 | 693 | Image |
102 | 693 | *image; |
103 | | |
104 | 693 | int |
105 | 693 | bit; |
106 | | |
107 | 693 | MagickBooleanType |
108 | 693 | status; |
109 | | |
110 | 693 | ssize_t |
111 | 693 | i, |
112 | 693 | x; |
113 | | |
114 | 693 | Quantum |
115 | 693 | *q; |
116 | | |
117 | 693 | unsigned char |
118 | 693 | *p; |
119 | | |
120 | 693 | ssize_t |
121 | 693 | y; |
122 | | |
123 | 693 | unsigned char |
124 | 693 | byte, |
125 | 693 | *data; |
126 | | |
127 | | /* |
128 | | Open image file. |
129 | | */ |
130 | 693 | assert(image_info != (const ImageInfo *) NULL); |
131 | 693 | assert(image_info->signature == MagickCoreSignature); |
132 | 693 | assert(exception != (ExceptionInfo *) NULL); |
133 | 693 | assert(exception->signature == MagickCoreSignature); |
134 | 693 | if (IsEventLogging() != MagickFalse) |
135 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
136 | 0 | image_info->filename); |
137 | 693 | image=AcquireImage(image_info,exception); |
138 | 693 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
139 | 693 | if (status == MagickFalse) |
140 | 326 | { |
141 | 326 | image=DestroyImageList(image); |
142 | 326 | return((Image *) NULL); |
143 | 326 | } |
144 | | /* |
145 | | Read RGF header. |
146 | | */ |
147 | 367 | image->columns = (unsigned long) ReadBlobByte(image); |
148 | 367 | image->rows = (unsigned long) ReadBlobByte(image); |
149 | 367 | image->depth=8; |
150 | 367 | image->storage_class=PseudoClass; |
151 | 367 | image->colors=2; |
152 | | /* |
153 | | Initialize image structure. |
154 | | */ |
155 | 367 | if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) |
156 | 367 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
157 | | /* |
158 | | Initialize colormap. |
159 | | */ |
160 | 367 | image->colormap[0].red=QuantumRange; |
161 | 367 | image->colormap[0].green=QuantumRange; |
162 | 367 | image->colormap[0].blue=QuantumRange; |
163 | 367 | image->colormap[1].red=(Quantum) 0; |
164 | 367 | image->colormap[1].green=(Quantum) 0; |
165 | 367 | image->colormap[1].blue=(Quantum) 0; |
166 | 367 | if (image_info->ping != MagickFalse) |
167 | 0 | { |
168 | 0 | (void) CloseBlob(image); |
169 | 0 | return(GetFirstImageInList(image)); |
170 | 0 | } |
171 | 367 | status=SetImageExtent(image,image->columns,image->rows,exception); |
172 | 367 | if (status == MagickFalse) |
173 | 210 | return(DestroyImageList(image)); |
174 | | /* |
175 | | Read hex image data. |
176 | | */ |
177 | 157 | data=(unsigned char *) AcquireQuantumMemory(image->rows,image->columns* |
178 | 157 | sizeof(*data)); |
179 | 157 | if (data == (unsigned char *) NULL) |
180 | 157 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
181 | 157 | p=data; |
182 | 2.85M | for (i=0; i < (ssize_t) (image->columns * image->rows); i++) |
183 | 2.85M | { |
184 | 2.85M | *p++=(char) ReadBlobByte(image); |
185 | 2.85M | } |
186 | | |
187 | | /* |
188 | | Convert RGF image to pixel packets. |
189 | | */ |
190 | 157 | p=data; |
191 | 17.7k | for (y=0; y < (ssize_t) image->rows; y++) |
192 | 17.6k | { |
193 | 17.6k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
194 | 17.6k | if (q == (Quantum *) NULL) |
195 | 0 | break; |
196 | 17.6k | bit=0; |
197 | 17.6k | byte=0; |
198 | 2.87M | for (x=0; x < (ssize_t) image->columns; x++) |
199 | 2.85M | { |
200 | 2.85M | if (bit == 0) |
201 | 363k | byte=(size_t) (*p++); |
202 | 2.85M | SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q); |
203 | 2.85M | bit++; |
204 | 2.85M | byte>>=1; |
205 | 2.85M | if (bit == 8) |
206 | 348k | bit=0; |
207 | 2.85M | q+=(ptrdiff_t) GetPixelChannels(image); |
208 | 2.85M | } |
209 | 17.6k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
210 | 0 | break; |
211 | 17.6k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
212 | 17.6k | image->rows); |
213 | 17.6k | if (status == MagickFalse) |
214 | 0 | break; |
215 | 17.6k | } |
216 | 157 | data=(unsigned char *) RelinquishMagickMemory(data); |
217 | 157 | (void) SyncImage(image,exception); |
218 | 157 | if (CloseBlob(image) == MagickFalse) |
219 | 0 | status=MagickFalse; |
220 | 157 | if (status == MagickFalse) |
221 | 0 | return(DestroyImageList(image)); |
222 | 157 | return(GetFirstImageInList(image)); |
223 | 157 | } |
224 | | |
225 | | /* |
226 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
227 | | % % |
228 | | % % |
229 | | % % |
230 | | % R e g i s t e r R G F I m a g e % |
231 | | % % |
232 | | % % |
233 | | % % |
234 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
235 | | % |
236 | | % RegisterRGFImage() adds attributes for the RGF image format to |
237 | | % the list of supported formats. The attributes include the image format |
238 | | % tag, a method to read and/or write the format, whether the format |
239 | | % supports the saving of more than one frame to the same file or blob, |
240 | | % whether the format supports native in-memory I/O, and a brief |
241 | | % description of the format. |
242 | | % |
243 | | % The format of the RegisterRGFImage method is: |
244 | | % |
245 | | % size_t RegisterRGFImage(void) |
246 | | % |
247 | | */ |
248 | | ModuleExport size_t RegisterRGFImage(void) |
249 | 9 | { |
250 | 9 | MagickInfo |
251 | 9 | *entry; |
252 | | |
253 | 9 | entry=AcquireMagickInfo("RGF","RGF", |
254 | 9 | "LEGO Mindstorms EV3 Robot Graphic Format (black and white)"); |
255 | 9 | entry->decoder=(DecodeImageHandler *) ReadRGFImage; |
256 | 9 | entry->encoder=(EncodeImageHandler *) WriteRGFImage; |
257 | 9 | entry->flags^=CoderAdjoinFlag; |
258 | 9 | (void) RegisterMagickInfo(entry); |
259 | 9 | return(MagickImageCoderSignature); |
260 | 9 | } |
261 | | |
262 | | /* |
263 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
264 | | % % |
265 | | % % |
266 | | % % |
267 | | % U n r e g i s t e r R G F I m a g e % |
268 | | % % |
269 | | % % |
270 | | % % |
271 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
272 | | % |
273 | | % UnregisterRGFImage() removes format registrations made by the |
274 | | % RGF module from the list of supported formats. |
275 | | % |
276 | | % The format of the UnregisterRGFImage method is: |
277 | | % |
278 | | % UnregisterRGFImage(void) |
279 | | % |
280 | | */ |
281 | | ModuleExport void UnregisterRGFImage(void) |
282 | 0 | { |
283 | 0 | (void) UnregisterMagickInfo("RGF"); |
284 | 0 | } |
285 | | |
286 | | /* |
287 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
288 | | % % |
289 | | % % |
290 | | % % |
291 | | % W r i t e R G F I m a g e % |
292 | | % % |
293 | | % % |
294 | | % % |
295 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
296 | | % |
297 | | % WriteRGFImage() writes an image to a file in the X bitmap format. |
298 | | % |
299 | | % The format of the WriteRGFImage method is: |
300 | | % |
301 | | % MagickBooleanType WriteRGFImage(const ImageInfo *image_info, |
302 | | % Image *image,ExceptionInfo *exception) |
303 | | % |
304 | | % A description of each parameter follows. |
305 | | % |
306 | | % o image_info: the image info. |
307 | | % |
308 | | % o image: The image. |
309 | | % |
310 | | % o exception: return any errors or warnings in this structure. |
311 | | % |
312 | | */ |
313 | | static MagickBooleanType WriteRGFImage(const ImageInfo *image_info,Image *image, |
314 | | ExceptionInfo *exception) |
315 | 157 | { |
316 | 157 | MagickBooleanType |
317 | 157 | status; |
318 | | |
319 | 157 | const Quantum |
320 | 157 | *p; |
321 | | |
322 | 157 | ssize_t |
323 | 157 | x; |
324 | | |
325 | 157 | size_t |
326 | 157 | bit, |
327 | 157 | byte; |
328 | | |
329 | 157 | ssize_t |
330 | 157 | y; |
331 | | |
332 | | /* |
333 | | Open output image file. |
334 | | */ |
335 | 157 | assert(image_info != (const ImageInfo *) NULL); |
336 | 157 | assert(image_info->signature == MagickCoreSignature); |
337 | 157 | assert(image != (Image *) NULL); |
338 | 157 | assert(image->signature == MagickCoreSignature); |
339 | 157 | assert(exception != (ExceptionInfo *) NULL); |
340 | 157 | assert(exception->signature == MagickCoreSignature); |
341 | 157 | if (IsEventLogging() != MagickFalse) |
342 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
343 | 157 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
344 | 157 | if (status == MagickFalse) |
345 | 0 | return(status); |
346 | 157 | if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) |
347 | 0 | (void) TransformImageColorspace(image,sRGBColorspace,exception); |
348 | 157 | if ((image->columns > 255L) || (image->rows > 255L)) |
349 | 157 | ThrowWriterException(ImageError,"Dimensions must be less than 255x255"); |
350 | | /* |
351 | | Write header (just the image dimensions) |
352 | | */ |
353 | 157 | (void) WriteBlobByte(image,image->columns & 0xff); |
354 | 157 | (void) WriteBlobByte(image,image->rows & 0xff); |
355 | | /* |
356 | | Convert MIFF to bit pixels. |
357 | | */ |
358 | 157 | if (IsImageMonochrome(image) == MagickFalse) |
359 | 157 | (void) SetImageType(image,BilevelType,exception); |
360 | 157 | x=0; |
361 | 157 | y=0; |
362 | 17.7k | for (y=0; y < (ssize_t) image->rows; y++) |
363 | 17.6k | { |
364 | 17.6k | p=GetVirtualPixels(image,0,y,image->columns,1,exception); |
365 | 17.6k | if (p == (const Quantum *) NULL) |
366 | 0 | break; |
367 | 17.6k | bit=0; |
368 | 17.6k | byte=0; |
369 | 2.87M | for (x=0; x < (ssize_t) image->columns; x++) |
370 | 2.85M | { |
371 | 2.85M | byte>>=1; |
372 | 2.85M | if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0)) |
373 | 2.75M | byte|=0x80; |
374 | 2.85M | bit++; |
375 | 2.85M | if (bit == 8) |
376 | 348k | { |
377 | | /* |
378 | | Write a bitmap byte to the image file. |
379 | | */ |
380 | 348k | (void) WriteBlobByte(image,(unsigned char) byte); |
381 | 348k | bit=0; |
382 | 348k | byte=0; |
383 | 348k | } |
384 | 2.85M | p+=(ptrdiff_t) GetPixelChannels(image); |
385 | 2.85M | } |
386 | 17.6k | if (bit != 0) |
387 | 15.2k | { |
388 | 15.2k | byte >>= 8 - bit; |
389 | 15.2k | (void) WriteBlobByte(image,(unsigned char) byte); |
390 | 15.2k | } |
391 | 17.6k | status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, |
392 | 17.6k | image->rows); |
393 | 17.6k | if (status == MagickFalse) |
394 | 0 | break; |
395 | 17.6k | } |
396 | 157 | if (CloseBlob(image) == MagickFalse) |
397 | 0 | status=MagickFalse; |
398 | 157 | return(status); |
399 | 157 | } |