blob: afc5344c1c87d271d28166f1ee50ac58f44b87b1 [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% %
Cristy7ce65e72015-12-12 18:03:16 -050018% Copyright 1999-2016 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"
cristy8941c702012-06-21 01:30:15 +000041#include "MagickCore/attribute.h"
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/blob.h"
43#include "MagickCore/blob-private.h"
44#include "MagickCore/cache.h"
45#include "MagickCore/color-private.h"
46#include "MagickCore/colorspace.h"
47#include "MagickCore/constitute.h"
48#include "MagickCore/exception.h"
49#include "MagickCore/exception-private.h"
50#include "MagickCore/image.h"
51#include "MagickCore/image-private.h"
52#include "MagickCore/list.h"
53#include "MagickCore/magick.h"
54#include "MagickCore/memory_.h"
55#include "MagickCore/module.h"
56#include "MagickCore/monitor.h"
57#include "MagickCore/monitor-private.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/property.h"
60#include "MagickCore/quantize.h"
61#include "MagickCore/static.h"
62#include "MagickCore/string_.h"
63#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000064
65/*
66 Forward declarations.
67*/
68static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000069 WriteBRAILLEImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000070
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73% %
74% %
75% %
76% R e g i s t e r B R A I L L E I m a g e %
77% %
78% %
79% %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82% RegisterBRAILLEImage() adds values for the Braille format to
83% the list of supported formats. The values include the image format
84% tag, a method to read and/or write the format, whether the format
85% supports the saving of more than one frame to the same file or blob,
86% whether the format supports native in-memory I/O, and a brief
87% description of the format.
88%
89% The format of the RegisterBRAILLEImage method is:
90%
cristybb503372010-05-27 20:51:26 +000091% size_t RegisterBRAILLEImage(void)
cristy3ed852e2009-09-05 21:47:34 +000092%
93*/
cristybb503372010-05-27 20:51:26 +000094ModuleExport size_t RegisterBRAILLEImage(void)
cristy3ed852e2009-09-05 21:47:34 +000095{
96 MagickInfo
97 *entry;
98
dirk06b627a2015-04-06 18:59:17 +000099 entry=AcquireMagickInfo("BRAILLE","BRF","BRF ASCII Braille format");
cristy3ed852e2009-09-05 21:47:34 +0000100 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
dirk08e9a112015-02-22 01:51:41 +0000101 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000102 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000103 entry=AcquireMagickInfo("BRAILLE","UBRL","Unicode Text format");
cristy3ed852e2009-09-05 21:47:34 +0000104 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
dirk08e9a112015-02-22 01:51:41 +0000105 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000106 (void) RegisterMagickInfo(entry);
Samuel Thibault531aa152015-11-01 23:36:24 +0100107 entry=AcquireMagickInfo("BRAILLE","UBRL6","Unicode Text format 6dot");
108 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
109 entry->flags^=CoderAdjoinFlag;
110 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000111 entry=AcquireMagickInfo("BRAILLE","ISOBRL","ISO/TR 11548-1 format");
cristy3ed852e2009-09-05 21:47:34 +0000112 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
dirk08e9a112015-02-22 01:51:41 +0000113 entry->flags^=CoderAdjoinFlag;
cristy3ed852e2009-09-05 21:47:34 +0000114 (void) RegisterMagickInfo(entry);
Samuel Thibault531aa152015-11-01 23:36:24 +0100115 entry=AcquireMagickInfo("BRAILLE","ISOBRL6","ISO/TR 11548-1 format 6dot");
116 entry->encoder=(EncodeImageHandler *) WriteBRAILLEImage;
117 entry->flags^=CoderAdjoinFlag;
118 (void) RegisterMagickInfo(entry);
cristy3ed852e2009-09-05 21:47:34 +0000119 return(MagickImageCoderSignature);
120}
121
122/*
123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124% %
125% %
126% %
127% U n r e g i s t e r B R A I L L E I m a g e %
128% %
129% %
130% %
131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132%
133% UnregisterBRAILLEImage() removes format registrations made by the
134% BRAILLE module from the list of supported formats.
135%
136% The format of the UnregisterBRAILLEImage method is:
137%
138% UnregisterBRAILLEImage(void)
139%
140*/
141ModuleExport void UnregisterBRAILLEImage(void)
142{
143 (void) UnregisterMagickInfo("BRF");
144 (void) UnregisterMagickInfo("UBRL");
Samuel Thibault531aa152015-11-01 23:36:24 +0100145 (void) UnregisterMagickInfo("UBRL6");
cristy3ed852e2009-09-05 21:47:34 +0000146 (void) UnregisterMagickInfo("ISOBRL");
Samuel Thibault531aa152015-11-01 23:36:24 +0100147 (void) UnregisterMagickInfo("ISOBRL6");
cristy3ed852e2009-09-05 21:47:34 +0000148}
149
150/*
151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152% %
153% %
154% %
155% W r i t e B R A I L L E I m a g e %
156% %
157% %
158% %
159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160%
161% WriteBRAILLEImage() writes an image to a file in the Braille format.
162%
163% The format of the WriteBRAILLEImage method is:
164%
165% MagickBooleanType WriteBRAILLEImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000166% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000167%
168% A description of each parameter follows.
169%
170% o image_info: The image info.
171%
172% o image: The image.
173%
cristy1e178e72011-08-28 19:44:34 +0000174% o exception: return any errors or warnings in this structure.
175%
cristy3ed852e2009-09-05 21:47:34 +0000176*/
177static MagickBooleanType WriteBRAILLEImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000178 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000179{
180 char
cristy151b66d2015-04-15 10:50:31 +0000181 buffer[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000182
183 const char
184 *value;
185
cristy706146e2009-10-23 14:43:35 +0000186 int
187 unicode = 0,
188 iso_11548_1 = 0;
189
cristy3ed852e2009-09-05 21:47:34 +0000190 MagickBooleanType
191 status;
192
cristy4c08aed2011-07-01 19:47:50 +0000193 Quantum
194 polarity;
cristy3ed852e2009-09-05 21:47:34 +0000195
cristy4c08aed2011-07-01 19:47:50 +0000196 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000197 *p;
198
cristybb503372010-05-27 20:51:26 +0000199 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000200 x;
201
cristybb503372010-05-27 20:51:26 +0000202 size_t
cristy3ed852e2009-09-05 21:47:34 +0000203 cell_height = 4;
cristy3ed852e2009-09-05 21:47:34 +0000204
cristy4e82e512011-04-24 01:33:42 +0000205 ssize_t
206 y;
207
cristy3ed852e2009-09-05 21:47:34 +0000208 /*
209 Open output image file.
210 */
211 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000212 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000213 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000214 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000215 if (LocaleCompare(image_info->magick, "UBRL") == 0)
cristy706146e2009-10-23 14:43:35 +0000216 unicode=1;
Samuel Thibault531aa152015-11-01 23:36:24 +0100217 else if (LocaleCompare(image_info->magick, "UBRL6") == 0)
218 {
219 unicode=1;
cristy706146e2009-10-23 14:43:35 +0000220 cell_height=3;
Samuel Thibault531aa152015-11-01 23:36:24 +0100221 }
222 else if (LocaleCompare(image_info->magick, "ISOBRL") == 0)
223 iso_11548_1=1;
224 else if (LocaleCompare(image_info->magick, "ISOBRL6") == 0)
225 {
226 iso_11548_1=1;
227 cell_height=3;
228 }
229 else
230 cell_height=3;
cristy3ed852e2009-09-05 21:47:34 +0000231 if (image->debug != MagickFalse)
232 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000233 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000234 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000235 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000236 if (status == MagickFalse)
237 return(status);
cristy3ed852e2009-09-05 21:47:34 +0000238 if (!iso_11548_1)
239 {
cristyd15e6592011-10-15 00:13:06 +0000240 value=GetImageProperty(image,"label",exception);
cristy4e82e512011-04-24 01:33:42 +0000241 if (value != (const char *) NULL)
242 {
cristy151b66d2015-04-15 10:50:31 +0000243 (void) FormatLocaleString(buffer,MagickPathExtent,"Title: %s\n", value);
cristy4e82e512011-04-24 01:33:42 +0000244 (void) WriteBlobString(image,buffer);
245 }
246 if (image->page.x != 0)
247 {
cristy151b66d2015-04-15 10:50:31 +0000248 (void) FormatLocaleString(buffer,MagickPathExtent,"X: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000249 image->page.x);
250 (void) WriteBlobString(image,buffer);
251 }
252 if (image->page.y != 0)
253 {
cristy151b66d2015-04-15 10:50:31 +0000254 (void) FormatLocaleString(buffer,MagickPathExtent,"Y: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000255 image->page.y);
256 (void) WriteBlobString(image,buffer);
257 }
cristy151b66d2015-04-15 10:50:31 +0000258 (void) FormatLocaleString(buffer,MagickPathExtent,"Width: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000259 (image->columns+(image->columns % 2)));
cristy3ed852e2009-09-05 21:47:34 +0000260 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +0000261 (void) FormatLocaleString(buffer,MagickPathExtent,"Height: %.20g\n",(double)
cristy4e82e512011-04-24 01:33:42 +0000262 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000263 (void) WriteBlobString(image,buffer);
cristy3ed852e2009-09-05 21:47:34 +0000264 (void) WriteBlobString(image,"\n");
265 }
cristy018f07f2011-09-04 21:15:19 +0000266 (void) SetImageType(image,BilevelType,exception);
cristy79f18992009-10-28 01:42:22 +0000267 polarity = 0;
cristy706146e2009-10-23 14:43:35 +0000268 if (image->storage_class == PseudoClass) {
cristy11a06d32015-01-04 12:03:27 +0000269 polarity=(Quantum) (GetPixelInfoIntensity(image,&image->colormap[0]) >=
cristy9eeb7f02015-02-28 22:20:09 +0000270 (QuantumRange/2.0));
cristy706146e2009-10-23 14:43:35 +0000271 if (image->colors == 2)
cristy11a06d32015-01-04 12:03:27 +0000272 polarity=(Quantum) (GetPixelInfoIntensity(image,&image->colormap[0]) >=
273 GetPixelInfoIntensity(image,&image->colormap[1]));
cristy706146e2009-10-23 14:43:35 +0000274 }
cristy0b29b252010-05-30 01:59:46 +0000275 for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) cell_height)
cristy3ed852e2009-09-05 21:47:34 +0000276 {
277 if ((y+cell_height) > image->rows)
cristybb503372010-05-27 20:51:26 +0000278 cell_height = (size_t) (image->rows-y);
cristy3ed852e2009-09-05 21:47:34 +0000279
cristy1e178e72011-08-28 19:44:34 +0000280 p=GetVirtualPixels(image,0,y,image->columns,cell_height,exception);
cristy4c08aed2011-07-01 19:47:50 +0000281 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000282 break;
cristybb503372010-05-27 20:51:26 +0000283 for (x=0; x < (ssize_t) image->columns; x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000284 {
285 unsigned char cell = 0;
cristybb503372010-05-27 20:51:26 +0000286 int two_columns = x+1 < (ssize_t) image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000287
288 do
289 {
cristy706146e2009-10-23 14:43:35 +0000290#define do_cell(dx,dy,bit) do { \
291 if (image->storage_class == PseudoClass) \
cristy4c08aed2011-07-01 19:47:50 +0000292 cell |= (GetPixelIndex(image,p+x+dx+dy*image->columns) == polarity) << bit; \
cristy706146e2009-10-23 14:43:35 +0000293 else \
cristy4c08aed2011-07-01 19:47:50 +0000294 cell |= (GetPixelGreen(image,p+x+dx+dy*image->columns) == 0) << bit; \
dirk93b02b72013-11-16 16:03:36 +0000295DisableMSCWarning(4127) \
296} while (0) \
297RestoreMSCWarning
cristy3ed852e2009-09-05 21:47:34 +0000298
299 do_cell(0,0,0);
300 if (two_columns)
301 do_cell(1,0,3);
302 if (cell_height < 2)
303 break;
304
305 do_cell(0,1,1);
306 if (two_columns)
307 do_cell(1,1,4);
308 if (cell_height < 3)
309 break;
310
311 do_cell(0,2,2);
312 if (two_columns)
313 do_cell(1,2,5);
314 if (cell_height < 4)
315 break;
316
317 do_cell(0,3,6);
318 if (two_columns)
319 do_cell(1,3,7);
dirk93b02b72013-11-16 16:03:36 +0000320DisableMSCWarning(4127)
cristy3ed852e2009-09-05 21:47:34 +0000321 } while(0);
dirk93b02b72013-11-16 16:03:36 +0000322RestoreMSCWarning
cristy3ed852e2009-09-05 21:47:34 +0000323
324 if (unicode)
325 {
326 unsigned char utf8[3];
327 /* Unicode text */
328 utf8[0] = (unsigned char) (0xe0|((0x28>>4)&0x0f));
329 utf8[1] = 0x80|((0x28<<2)&0x3f)|(cell>>6);
330 utf8[2] = 0x80|(cell&0x3f);
331 (void) WriteBlob(image,3,utf8);
332 }
333 else if (iso_11548_1)
334 {
335 /* ISO/TR 11548-1 binary */
336 (void) WriteBlobByte(image,cell);
337 }
338 else
339 {
340 /* BRF */
341 static const unsigned char iso_to_brf[64] = {
342 ' ', 'A', '1', 'B', '\'', 'K', '2', 'L',
343 '@', 'C', 'I', 'F', '/', 'M', 'S', 'P',
344 '"', 'E', '3', 'H', '9', 'O', '6', 'R',
345 '^', 'D', 'J', 'G', '>', 'N', 'T', 'Q',
346 ',', '*', '5', '<', '-', 'U', '8', 'V',
347 '.', '%', '[', '$', '+', 'X', '!', '&',
348 ';', ':', '4', '\\', '0', 'Z', '7', '(',
349 '_', '?', 'W', ']', '#', 'Y', ')', '='
350 };
351 (void) WriteBlobByte(image,iso_to_brf[cell]);
352 }
353 }
cristy4e82e512011-04-24 01:33:42 +0000354 if (iso_11548_1 == 0)
cristy3ed852e2009-09-05 21:47:34 +0000355 (void) WriteBlobByte(image,'\n');
cristycee97112010-05-28 00:44:52 +0000356 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy4e82e512011-04-24 01:33:42 +0000357 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000358 if (status == MagickFalse)
359 break;
360 }
361 (void) CloseBlob(image);
362 return(MagickTrue);
363}