blob: 4e4963eacec715acc33a233a337835d3f69b8b4a [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% BBBB RRRR AAA IIIII L L EEEEE %
6% B B R R A A I L L E %
7% BBBB RRRR AAAAA I L L EEE %
8% B B R R A A I L L E %
9% BBBB R R A A IIIII LLLLL LLLLL EEEEE %
10% %
11% %
12% Read/Write Braille Format %
13% %
14% Samuel Thibault %
15% February 2008 %
16% %
17% %
cristy7e41fe82010-12-04 23:12:08 +000018% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000019% dedicated to making software imaging solutions freely available. %
20% %
21% You may not use this file except in compliance with the License. You may %
22% obtain a copy of the License at %
23% %
24% http://www.imagemagick.org/script/license.php %
25% %
26% Unless required by applicable law or agreed to in writing, software %
27% distributed under the License is distributed on an "AS IS" BASIS, %
28% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
29% See the License for the specific language governing permissions and %
30% limitations under the License. %
31% %
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33%
34%
35*/
36
37/*
38 Include declarations.
39*/
40#include "magick/studio.h"
41#include "magick/blob.h"
42#include "magick/blob-private.h"
43#include "magick/cache.h"
44#include "magick/color-private.h"
45#include "magick/colorspace.h"
46#include "magick/constitute.h"
47#include "magick/exception.h"
48#include "magick/exception-private.h"
49#include "magick/image.h"
50#include "magick/image-private.h"
51#include "magick/list.h"
52#include "magick/magick.h"
53#include "magick/memory_.h"
54#include "magick/module.h"
55#include "magick/monitor.h"
56#include "magick/monitor-private.h"
57#include "magick/property.h"
58#include "magick/quantize.h"
59#include "magick/static.h"
60#include "magick/string_.h"
61#include "magick/utility.h"
62
63/*
64 Forward declarations.
65*/
66static MagickBooleanType
67 WriteBRAILLEImage(const ImageInfo *,Image *);
68
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71% %
72% %
73% %
74% R e g i s t e r B R A I L L E I m a g e %
75% %
76% %
77% %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
80% RegisterBRAILLEImage() adds values for the Braille format to
81% the list of supported formats. The values include the image format
82% tag, a method to read and/or write the format, whether the format
83% supports the saving of more than one frame to the same file or blob,
84% whether the format supports native in-memory I/O, and a brief
85% description of the format.
86%
87% The format of the RegisterBRAILLEImage method is:
88%
cristybb503372010-05-27 20:51:26 +000089% size_t RegisterBRAILLEImage(void)
cristy3ed852e2009-09-05 21:47:34 +000090%
91*/
cristybb503372010-05-27 20:51:26 +000092ModuleExport size_t RegisterBRAILLEImage(void)
cristy3ed852e2009-09-05 21:47:34 +000093{
94 MagickInfo
95 *entry;
96
97 entry=SetMagickInfo("BRF");
98 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
99 entry->adjoin=MagickFalse;
100 entry->description=AcquireString("BRF ASCII Braille format");
101 entry->module=AcquireString("BRAILLE");
102 (void) RegisterMagickInfo(entry);
103 entry=SetMagickInfo("UBRL");
104 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
105 entry->adjoin=MagickFalse;
106 entry->description=AcquireString("Unicode Text format");
107 entry->module=AcquireString("BRAILLE");
108 (void) RegisterMagickInfo(entry);
109 entry=SetMagickInfo("ISOBRL");
110 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
111 entry->adjoin=MagickFalse;
112 entry->description=AcquireString("ISO/TR 11548-1 format");
113 entry->module=AcquireString("BRAILLE");
114 (void) RegisterMagickInfo(entry);
115 return(MagickImageCoderSignature);
116}
117
118/*
119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120% %
121% %
122% %
123% U n r e g i s t e r B R A I L L E I m a g e %
124% %
125% %
126% %
127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128%
129% UnregisterBRAILLEImage() removes format registrations made by the
130% BRAILLE module from the list of supported formats.
131%
132% The format of the UnregisterBRAILLEImage method is:
133%
134% UnregisterBRAILLEImage(void)
135%
136*/
137ModuleExport void UnregisterBRAILLEImage(void)
138{
139 (void) UnregisterMagickInfo("BRF");
140 (void) UnregisterMagickInfo("UBRL");
141 (void) UnregisterMagickInfo("ISOBRL");
142}
143
144/*
145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146% %
147% %
148% %
149% W r i t e B R A I L L E I m a g e %
150% %
151% %
152% %
153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154%
155% WriteBRAILLEImage() writes an image to a file in the Braille format.
156%
157% The format of the WriteBRAILLEImage method is:
158%
159% MagickBooleanType WriteBRAILLEImage(const ImageInfo *image_info,
160% Image *image)
161%
162% A description of each parameter follows.
163%
164% o image_info: The image info.
165%
166% o image: The image.
167%
168*/
169static MagickBooleanType WriteBRAILLEImage(const ImageInfo *image_info,
170 Image *image)
171{
172 char
173 buffer[MaxTextExtent];
174
175 const char
176 *value;
177
cristy706146e2009-10-23 14:43:35 +0000178 int
179 unicode = 0,
180 iso_11548_1 = 0;
181
cristybb503372010-05-27 20:51:26 +0000182 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000183 y;
184
185 MagickBooleanType
186 status;
187
188 register const IndexPacket
189 *indexes;
190
191 register const PixelPacket
192 *p;
193
194 IndexPacket
195 polarity;
196
cristybb503372010-05-27 20:51:26 +0000197 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000198 x;
199
cristybb503372010-05-27 20:51:26 +0000200 size_t
cristy3ed852e2009-09-05 21:47:34 +0000201 cell_height = 4;
cristy3ed852e2009-09-05 21:47:34 +0000202
203 /*
204 Open output image file.
205 */
206 assert(image_info != (const ImageInfo *) NULL);
207 assert(image_info->signature == MagickSignature);
208 assert(image != (Image *) NULL);
209 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +0000210 if (LocaleCompare(image_info->magick, "UBRL") == 0)
cristy706146e2009-10-23 14:43:35 +0000211 unicode=1;
cristy3ed852e2009-09-05 21:47:34 +0000212 else
213 if (LocaleCompare(image_info->magick, "ISOBRL") == 0)
cristy706146e2009-10-23 14:43:35 +0000214 iso_11548_1=1;
cristy3ed852e2009-09-05 21:47:34 +0000215 else
cristy706146e2009-10-23 14:43:35 +0000216 cell_height=3;
cristy3ed852e2009-09-05 21:47:34 +0000217 if (image->debug != MagickFalse)
218 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
219 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
220 if (status == MagickFalse)
221 return(status);
cristy3ed852e2009-09-05 21:47:34 +0000222 if (!iso_11548_1)
223 {
224 value=GetImageProperty(image,"Label");
225 if (value != (const char *) NULL) {
226 (void) FormatMagickString(buffer,MaxTextExtent,"Title: %s\n", value);
227 (void) WriteBlobString(image,buffer);
228 }
229 if (image->page.x)
230 {
cristye8c25f92010-06-03 00:53:06 +0000231 (void) FormatMagickString(buffer,MaxTextExtent,"X: %.20g\n",(double)
cristy706146e2009-10-23 14:43:35 +0000232 image->page.x);
cristy3ed852e2009-09-05 21:47:34 +0000233 (void) WriteBlobString(image,buffer);
234 }
235 if (image->page.y)
236 {
cristye8c25f92010-06-03 00:53:06 +0000237 (void) FormatMagickString(buffer,MaxTextExtent,"Y: %.20g\n",(double)
cristy706146e2009-10-23 14:43:35 +0000238 image->page.y);
cristy3ed852e2009-09-05 21:47:34 +0000239 (void) WriteBlobString(image,buffer);
240 }
cristye8c25f92010-06-03 00:53:06 +0000241 (void) FormatMagickString(buffer,MaxTextExtent,"Width: %.20g\n",
242 (double) (image->columns+(image->columns % 2)));
cristy3ed852e2009-09-05 21:47:34 +0000243 (void) WriteBlobString(image,buffer);
cristye8c25f92010-06-03 00:53:06 +0000244 (void) FormatMagickString(buffer,MaxTextExtent,"Height: %.20g\n",
245 (double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000246 (void) WriteBlobString(image,buffer);
cristy3ed852e2009-09-05 21:47:34 +0000247 (void) WriteBlobString(image,"\n");
248 }
cristy3ed852e2009-09-05 21:47:34 +0000249 (void) SetImageType(image,BilevelType);
cristy79f18992009-10-28 01:42:22 +0000250 polarity = 0;
cristy706146e2009-10-23 14:43:35 +0000251 if (image->storage_class == PseudoClass) {
252 polarity=(IndexPacket) (PixelIntensityToQuantum(&image->colormap[0]) >=
253 (Quantum) (QuantumRange/2));
254 if (image->colors == 2)
255 polarity=(IndexPacket)
256 (PixelIntensityToQuantum(&image->colormap[0]) >=
257 PixelIntensityToQuantum(&image->colormap[1]));
cristy706146e2009-10-23 14:43:35 +0000258 }
cristy0b29b252010-05-30 01:59:46 +0000259 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) cell_height)
cristy3ed852e2009-09-05 21:47:34 +0000260 {
261 if ((y+cell_height) > image->rows)
cristybb503372010-05-27 20:51:26 +0000262 cell_height = (size_t) (image->rows-y);
cristy3ed852e2009-09-05 21:47:34 +0000263
264 p=GetVirtualPixels(image,0,y,image->columns,cell_height,&image->exception);
265 if (p == (const PixelPacket *) NULL)
266 break;
267 indexes=GetVirtualIndexQueue(image);
cristybb503372010-05-27 20:51:26 +0000268 for (x=0; x < (ssize_t) image->columns; x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000269 {
270 unsigned char cell = 0;
cristybb503372010-05-27 20:51:26 +0000271 int two_columns = x+1 < (ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000272
273 do
274 {
cristy706146e2009-10-23 14:43:35 +0000275#define do_cell(dx,dy,bit) do { \
276 if (image->storage_class == PseudoClass) \
277 cell |= (indexes[x+dx+dy*image->columns] == polarity) << bit; \
278 else \
279 cell |= (p[x+dx+dy*image->columns].green == 0) << bit; \
280} while (0)
cristy3ed852e2009-09-05 21:47:34 +0000281
282 do_cell(0,0,0);
283 if (two_columns)
284 do_cell(1,0,3);
285 if (cell_height < 2)
286 break;
287
288 do_cell(0,1,1);
289 if (two_columns)
290 do_cell(1,1,4);
291 if (cell_height < 3)
292 break;
293
294 do_cell(0,2,2);
295 if (two_columns)
296 do_cell(1,2,5);
297 if (cell_height < 4)
298 break;
299
300 do_cell(0,3,6);
301 if (two_columns)
302 do_cell(1,3,7);
303 } while(0);
304
305 if (unicode)
306 {
307 unsigned char utf8[3];
308 /* Unicode text */
309 utf8[0] = (unsigned char) (0xe0|((0x28>>4)&0x0f));
310 utf8[1] = 0x80|((0x28<<2)&0x3f)|(cell>>6);
311 utf8[2] = 0x80|(cell&0x3f);
312 (void) WriteBlob(image,3,utf8);
313 }
314 else if (iso_11548_1)
315 {
316 /* ISO/TR 11548-1 binary */
317 (void) WriteBlobByte(image,cell);
318 }
319 else
320 {
321 /* BRF */
322 static const unsigned char iso_to_brf[64] = {
323 ' ', 'A', '1', 'B', '\'', 'K', '2', 'L',
324 '@', 'C', 'I', 'F', '/', 'M', 'S', 'P',
325 '"', 'E', '3', 'H', '9', 'O', '6', 'R',
326 '^', 'D', 'J', 'G', '>', 'N', 'T', 'Q',
327 ',', '*', '5', '<', '-', 'U', '8', 'V',
328 '.', '%', '[', '$', '+', 'X', '!', '&',
329 ';', ':', '4', '\\', '0', 'Z', '7', '(',
330 '_', '?', 'W', ']', '#', 'Y', ')', '='
331 };
332 (void) WriteBlobByte(image,iso_to_brf[cell]);
333 }
334 }
335 if (!iso_11548_1)
336 (void) WriteBlobByte(image,'\n');
cristycee97112010-05-28 00:44:52 +0000337 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
338 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000339 if (status == MagickFalse)
340 break;
341 }
342 (void) CloseBlob(image);
343 return(MagickTrue);
344}