blob: 3b78180bcec569c8ec8ec2ce80bd7094aed516aa [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*/
cristy4c08aed2011-07-01 19:47:50 +000040#include "MagickCore/studio.h"
41#include "MagickCore/blob.h"
42#include "MagickCore/blob-private.h"
43#include "MagickCore/cache.h"
44#include "MagickCore/color-private.h"
45#include "MagickCore/colorspace.h"
46#include "MagickCore/constitute.h"
47#include "MagickCore/exception.h"
48#include "MagickCore/exception-private.h"
49#include "MagickCore/image.h"
50#include "MagickCore/image-private.h"
51#include "MagickCore/list.h"
52#include "MagickCore/magick.h"
53#include "MagickCore/memory_.h"
54#include "MagickCore/module.h"
55#include "MagickCore/monitor.h"
56#include "MagickCore/monitor-private.h"
57#include "MagickCore/pixel-accessor.h"
58#include "MagickCore/property.h"
59#include "MagickCore/quantize.h"
60#include "MagickCore/static.h"
61#include "MagickCore/string_.h"
62#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000063
64/*
65 Forward declarations.
66*/
67static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000068 WriteBRAILLEImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000069
70/*
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72% %
73% %
74% %
75% R e g i s t e r B R A I L L E I m a g e %
76% %
77% %
78% %
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%
81% RegisterBRAILLEImage() adds values for the Braille format to
82% the list of supported formats. The values include the image format
83% tag, a method to read and/or write the format, whether the format
84% supports the saving of more than one frame to the same file or blob,
85% whether the format supports native in-memory I/O, and a brief
86% description of the format.
87%
88% The format of the RegisterBRAILLEImage method is:
89%
cristybb503372010-05-27 20:51:26 +000090% size_t RegisterBRAILLEImage(void)
cristy3ed852e2009-09-05 21:47:34 +000091%
92*/
cristybb503372010-05-27 20:51:26 +000093ModuleExport size_t RegisterBRAILLEImage(void)
cristy3ed852e2009-09-05 21:47:34 +000094{
95 MagickInfo
96 *entry;
97
98 entry=SetMagickInfo("BRF");
99 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
100 entry->adjoin=MagickFalse;
101 entry->description=AcquireString("BRF ASCII Braille format");
102 entry->module=AcquireString("BRAILLE");
103 (void) RegisterMagickInfo(entry);
104 entry=SetMagickInfo("UBRL");
105 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
106 entry->adjoin=MagickFalse;
107 entry->description=AcquireString("Unicode Text format");
108 entry->module=AcquireString("BRAILLE");
109 (void) RegisterMagickInfo(entry);
110 entry=SetMagickInfo("ISOBRL");
111 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
112 entry->adjoin=MagickFalse;
113 entry->description=AcquireString("ISO/TR 11548-1 format");
114 entry->module=AcquireString("BRAILLE");
115 (void) RegisterMagickInfo(entry);
116 return(MagickImageCoderSignature);
117}
118
119/*
120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121% %
122% %
123% %
124% U n r e g i s t e r B R A I L L E I m a g e %
125% %
126% %
127% %
128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129%
130% UnregisterBRAILLEImage() removes format registrations made by the
131% BRAILLE module from the list of supported formats.
132%
133% The format of the UnregisterBRAILLEImage method is:
134%
135% UnregisterBRAILLEImage(void)
136%
137*/
138ModuleExport void UnregisterBRAILLEImage(void)
139{
140 (void) UnregisterMagickInfo("BRF");
141 (void) UnregisterMagickInfo("UBRL");
142 (void) UnregisterMagickInfo("ISOBRL");
143}
144
145/*
146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147% %
148% %
149% %
150% W r i t e B R A I L L E I m a g e %
151% %
152% %
153% %
154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155%
156% WriteBRAILLEImage() writes an image to a file in the Braille format.
157%
158% The format of the WriteBRAILLEImage method is:
159%
160% MagickBooleanType WriteBRAILLEImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000161% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000162%
163% A description of each parameter follows.
164%
165% o image_info: The image info.
166%
167% o image: The image.
168%
cristy1e178e72011-08-28 19:44:34 +0000169% o exception: return any errors or warnings in this structure.
170%
cristy3ed852e2009-09-05 21:47:34 +0000171*/
172static MagickBooleanType WriteBRAILLEImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000173 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000174{
175 char
176 buffer[MaxTextExtent];
177
178 const char
179 *value;
180
cristy706146e2009-10-23 14:43:35 +0000181 int
182 unicode = 0,
183 iso_11548_1 = 0;
184
cristy3ed852e2009-09-05 21:47:34 +0000185 MagickBooleanType
186 status;
187
cristy4c08aed2011-07-01 19:47:50 +0000188 Quantum
189 polarity;
cristy3ed852e2009-09-05 21:47:34 +0000190
cristy4c08aed2011-07-01 19:47:50 +0000191 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000192 *p;
193
cristybb503372010-05-27 20:51:26 +0000194 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000195 x;
196
cristybb503372010-05-27 20:51:26 +0000197 size_t
cristy3ed852e2009-09-05 21:47:34 +0000198 cell_height = 4;
cristy3ed852e2009-09-05 21:47:34 +0000199
cristy4e82e512011-04-24 01:33:42 +0000200 ssize_t
201 y;
202
cristy3ed852e2009-09-05 21:47:34 +0000203 /*
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);
cristy3a37efd2011-08-28 20:31:03 +0000219 assert(exception != (ExceptionInfo *) NULL);
220 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000221 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000222 if (status == MagickFalse)
223 return(status);
cristy3ed852e2009-09-05 21:47:34 +0000224 if (!iso_11548_1)
225 {
cristybedb2ab2011-02-27 03:15:58 +0000226 value=GetImageProperty(image,"label");
cristy4e82e512011-04-24 01:33:42 +0000227 if (value != (const char *) NULL)
228 {
cristyb51dff52011-05-19 16:55:47 +0000229 (void) FormatLocaleString(buffer,MaxTextExtent,"Title: %s\n", value);
cristy4e82e512011-04-24 01:33:42 +0000230 (void) WriteBlobString(image,buffer);
231 }
232 if (image->page.x != 0)
233 {
cristyb51dff52011-05-19 16:55:47 +0000234 (void) FormatLocaleString(buffer,MaxTextExtent,"X: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000235 image->page.x);
236 (void) WriteBlobString(image,buffer);
237 }
238 if (image->page.y != 0)
239 {
cristyb51dff52011-05-19 16:55:47 +0000240 (void) FormatLocaleString(buffer,MaxTextExtent,"Y: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000241 image->page.y);
242 (void) WriteBlobString(image,buffer);
243 }
cristyb51dff52011-05-19 16:55:47 +0000244 (void) FormatLocaleString(buffer,MaxTextExtent,"Width: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000245 (image->columns+(image->columns % 2)));
cristy3ed852e2009-09-05 21:47:34 +0000246 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +0000247 (void) FormatLocaleString(buffer,MaxTextExtent,"Height: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000248 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000249 (void) WriteBlobString(image,buffer);
cristy3ed852e2009-09-05 21:47:34 +0000250 (void) WriteBlobString(image,"\n");
251 }
cristy018f07f2011-09-04 21:15:19 +0000252 (void) SetImageType(image,BilevelType,exception);
cristy79f18992009-10-28 01:42:22 +0000253 polarity = 0;
cristy706146e2009-10-23 14:43:35 +0000254 if (image->storage_class == PseudoClass) {
cristy4c08aed2011-07-01 19:47:50 +0000255 polarity=(Quantum) (GetPixelPacketIntensity(&image->colormap[0]) >=
cristy706146e2009-10-23 14:43:35 +0000256 (Quantum) (QuantumRange/2));
257 if (image->colors == 2)
cristy4c08aed2011-07-01 19:47:50 +0000258 polarity=(Quantum) (GetPixelPacketIntensity(&image->colormap[0]) >=
259 GetPixelPacketIntensity(&image->colormap[1]));
cristy706146e2009-10-23 14:43:35 +0000260 }
cristy0b29b252010-05-30 01:59:46 +0000261 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) cell_height)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
263 if ((y+cell_height) > image->rows)
cristybb503372010-05-27 20:51:26 +0000264 cell_height = (size_t) (image->rows-y);
cristy3ed852e2009-09-05 21:47:34 +0000265
cristy1e178e72011-08-28 19:44:34 +0000266 p=GetVirtualPixels(image,0,y,image->columns,cell_height,exception);
cristy4c08aed2011-07-01 19:47:50 +0000267 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000268 break;
cristybb503372010-05-27 20:51:26 +0000269 for (x=0; x < (ssize_t) image->columns; x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000270 {
271 unsigned char cell = 0;
cristybb503372010-05-27 20:51:26 +0000272 int two_columns = x+1 < (ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000273
274 do
275 {
cristy706146e2009-10-23 14:43:35 +0000276#define do_cell(dx,dy,bit) do { \
277 if (image->storage_class == PseudoClass) \
cristy4c08aed2011-07-01 19:47:50 +0000278 cell |= (GetPixelIndex(image,p+x+dx+dy*image->columns) == polarity) << bit; \
cristy706146e2009-10-23 14:43:35 +0000279 else \
cristy4c08aed2011-07-01 19:47:50 +0000280 cell |= (GetPixelGreen(image,p+x+dx+dy*image->columns) == 0) << bit; \
cristy706146e2009-10-23 14:43:35 +0000281} while (0)
cristy3ed852e2009-09-05 21:47:34 +0000282
283 do_cell(0,0,0);
284 if (two_columns)
285 do_cell(1,0,3);
286 if (cell_height < 2)
287 break;
288
289 do_cell(0,1,1);
290 if (two_columns)
291 do_cell(1,1,4);
292 if (cell_height < 3)
293 break;
294
295 do_cell(0,2,2);
296 if (two_columns)
297 do_cell(1,2,5);
298 if (cell_height < 4)
299 break;
300
301 do_cell(0,3,6);
302 if (two_columns)
303 do_cell(1,3,7);
304 } while(0);
305
306 if (unicode)
307 {
308 unsigned char utf8[3];
309 /* Unicode text */
310 utf8[0] = (unsigned char) (0xe0|((0x28>>4)&0x0f));
311 utf8[1] = 0x80|((0x28<<2)&0x3f)|(cell>>6);
312 utf8[2] = 0x80|(cell&0x3f);
313 (void) WriteBlob(image,3,utf8);
314 }
315 else if (iso_11548_1)
316 {
317 /* ISO/TR 11548-1 binary */
318 (void) WriteBlobByte(image,cell);
319 }
320 else
321 {
322 /* BRF */
323 static const unsigned char iso_to_brf[64] = {
324 ' ', 'A', '1', 'B', '\'', 'K', '2', 'L',
325 '@', 'C', 'I', 'F', '/', 'M', 'S', 'P',
326 '"', 'E', '3', 'H', '9', 'O', '6', 'R',
327 '^', 'D', 'J', 'G', '>', 'N', 'T', 'Q',
328 ',', '*', '5', '<', '-', 'U', '8', 'V',
329 '.', '%', '[', '$', '+', 'X', '!', '&',
330 ';', ':', '4', '\\', '0', 'Z', '7', '(',
331 '_', '?', 'W', ']', '#', 'Y', ')', '='
332 };
333 (void) WriteBlobByte(image,iso_to_brf[cell]);
334 }
335 }
cristy4e82e512011-04-24 01:33:42 +0000336 if (iso_11548_1 == 0)
cristy3ed852e2009-09-05 21:47:34 +0000337 (void) WriteBlobByte(image,'\n');
cristycee97112010-05-28 00:44:52 +0000338 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy4e82e512011-04-24 01:33:42 +0000339 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000340 if (status == MagickFalse)
341 break;
342 }
343 (void) CloseBlob(image);
344 return(MagickTrue);
345}