/src/graphicsmagick/coders/braille.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2019-2026 GraphicsMagick Group |
3 | | % |
4 | | % This program is covered by multiple licenses, which are described in |
5 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
6 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
7 | | % |
8 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
9 | | % % |
10 | | % % |
11 | | % BBBB RRRR AAA IIIII L L EEEEE % |
12 | | % B B R R A A I L L E % |
13 | | % BBBB RRRR AAAAA I L L EEE % |
14 | | % B B R R A A I L L E % |
15 | | % BBBB R R A A IIIII LLLLL LLLLL EEEEE % |
16 | | % % |
17 | | % % |
18 | | % Read/Write Braille Format % |
19 | | % % |
20 | | % Samuel Thibault % |
21 | | % February 2008 % |
22 | | % % |
23 | | % % |
24 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
25 | | % |
26 | | % |
27 | | */ |
28 | | |
29 | | /* |
30 | | Include declarations. |
31 | | */ |
32 | | #include "magick/studio.h" |
33 | | #include "magick/blob.h" |
34 | | #include "magick/magick.h" |
35 | | #include "magick/pixel_cache.h" |
36 | | #include "magick/utility.h" |
37 | | #include "magick/static.h" |
38 | | |
39 | | /* |
40 | | Forward declarations. |
41 | | */ |
42 | | static unsigned int |
43 | | WriteBRAILLEImage(const ImageInfo *,Image *); |
44 | | |
45 | | |
46 | | /* |
47 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
48 | | % % |
49 | | % % |
50 | | % % |
51 | | % R e g i s t e r B R A I L L E I m a g e % |
52 | | % % |
53 | | % % |
54 | | % % |
55 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
56 | | % |
57 | | % RegisterBRAILLEImage() adds values for the Braille format to |
58 | | % the list of supported formats. The values include the image format |
59 | | % tag, a method to read and/or write the format, whether the format |
60 | | % supports the saving of more than one frame to the same file or blob, |
61 | | % whether the format supports native in-memory I/O, and a brief |
62 | | % description of the format. |
63 | | % |
64 | | % The format of the RegisterBRAILLEImage method is: |
65 | | % |
66 | | % size_t RegisterBRAILLEImage(void) |
67 | | % |
68 | | */ |
69 | | ModuleExport void RegisterBRAILLEImage(void) |
70 | 0 | { |
71 | 0 | MagickInfo |
72 | 0 | *entry; |
73 | |
|
74 | 0 | entry=SetMagickInfo("BRF"); |
75 | 0 | entry->encoder=(EncoderHandler) WriteBRAILLEImage; |
76 | 0 | entry->adjoin=False; |
77 | 0 | entry->description="BRF ASCII Braille format"; |
78 | 0 | entry->module="BRAILLE"; |
79 | 0 | (void) RegisterMagickInfo(entry); |
80 | 0 | entry=SetMagickInfo("UBRL"); |
81 | 0 | entry->encoder=(EncoderHandler) WriteBRAILLEImage; |
82 | 0 | entry->adjoin=False; |
83 | 0 | entry->description="Unicode Text format"; |
84 | 0 | entry->module="BRAILLE"; |
85 | 0 | (void) RegisterMagickInfo(entry); |
86 | 0 | entry=SetMagickInfo("UBRL6"); |
87 | 0 | entry->encoder=(EncoderHandler) WriteBRAILLEImage; |
88 | 0 | entry->adjoin=False; |
89 | 0 | entry->description="Unicode Text format 6dot"; |
90 | 0 | entry->module="BRAILLE"; |
91 | 0 | (void) RegisterMagickInfo(entry); |
92 | 0 | entry=SetMagickInfo("ISOBRL"); |
93 | 0 | entry->encoder=(EncoderHandler) WriteBRAILLEImage; |
94 | 0 | entry->adjoin=False; |
95 | 0 | entry->description="ISO/TR 11548-1 format"; |
96 | 0 | entry->module="BRAILLE"; |
97 | 0 | (void) RegisterMagickInfo(entry); |
98 | 0 | entry=SetMagickInfo("ISOBRL6"); |
99 | 0 | entry->encoder=(EncoderHandler) WriteBRAILLEImage; |
100 | 0 | entry->adjoin=False; |
101 | 0 | entry->description="ISO/TR 11548-1 format 6dot"; |
102 | 0 | entry->module="BRAILLE"; |
103 | 0 | (void) RegisterMagickInfo(entry); |
104 | 0 | } |
105 | | |
106 | | /* |
107 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
108 | | % % |
109 | | % % |
110 | | % % |
111 | | % U n r e g i s t e r B R A I L L E I m a g e % |
112 | | % % |
113 | | % % |
114 | | % % |
115 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
116 | | % |
117 | | % UnregisterBRAILLEImage() removes format registrations made by the |
118 | | % BRAILLE module from the list of supported formats. |
119 | | % |
120 | | % The format of the UnregisterBRAILLEImage method is: |
121 | | % |
122 | | % UnregisterBRAILLEImage(void) |
123 | | % |
124 | | */ |
125 | | ModuleExport void UnregisterBRAILLEImage(void) |
126 | 0 | { |
127 | 0 | (void) UnregisterMagickInfo("BRF"); |
128 | 0 | (void) UnregisterMagickInfo("UBRL"); |
129 | 0 | (void) UnregisterMagickInfo("UBRL6"); |
130 | 0 | (void) UnregisterMagickInfo("ISOBRL"); |
131 | 0 | (void) UnregisterMagickInfo("ISOBRL6"); |
132 | 0 | } |
133 | | |
134 | | /* |
135 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
136 | | % % |
137 | | % % |
138 | | % % |
139 | | % W r i t e B R A I L L E I m a g e % |
140 | | % % |
141 | | % % |
142 | | % % |
143 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
144 | | % |
145 | | % WriteBRAILLEImage() writes an image to a file in the Braille format. |
146 | | % |
147 | | % The format of the WriteBRAILLEImage method is: |
148 | | % |
149 | | % unsigned int WriteBRAILLEImage(const ImageInfo *image_info, |
150 | | % Image *image) |
151 | | % |
152 | | % A description of each parameter follows. |
153 | | % |
154 | | % o image_info: The image info. |
155 | | % |
156 | | % o image: The image. |
157 | | % |
158 | | */ |
159 | | static unsigned int WriteBRAILLEImage(const ImageInfo *image_info, |
160 | | Image *image) |
161 | 0 | { |
162 | 0 | char |
163 | 0 | buffer[MaxTextExtent]; |
164 | |
|
165 | 0 | IndexPacket |
166 | 0 | polarity; |
167 | |
|
168 | 0 | int |
169 | 0 | unicode = 0, |
170 | 0 | iso_11548_1 = 0; |
171 | |
|
172 | 0 | MagickPassFail |
173 | 0 | status = MagickPass; |
174 | |
|
175 | 0 | register const IndexPacket |
176 | 0 | *indexes; |
177 | |
|
178 | 0 | register const PixelPacket |
179 | 0 | *p; |
180 | |
|
181 | 0 | register unsigned long |
182 | 0 | x; |
183 | |
|
184 | 0 | unsigned long |
185 | 0 | cell_height = 4; |
186 | |
|
187 | 0 | unsigned long |
188 | 0 | y; |
189 | |
|
190 | 0 | assert(image_info != (const ImageInfo *) NULL); |
191 | 0 | assert(image != (Image *) NULL); |
192 | |
|
193 | 0 | if (SetImageType(image,BilevelType) == MagickFail) |
194 | 0 | ThrowWriterException(CoderError,UnableToSetImageType,image); |
195 | | |
196 | | /* |
197 | | Open output image file. |
198 | | */ |
199 | 0 | if (LocaleCompare(image_info->magick,"UBRL") == 0) |
200 | 0 | unicode=1; |
201 | 0 | else if (LocaleCompare(image_info->magick,"UBRL6") == 0) |
202 | 0 | { |
203 | 0 | unicode=1; |
204 | 0 | cell_height=3; |
205 | 0 | } |
206 | 0 | else if (LocaleCompare(image_info->magick,"ISOBRL") == 0) |
207 | 0 | iso_11548_1=1; |
208 | 0 | else if (LocaleCompare(image_info->magick,"ISOBRL6") == 0) |
209 | 0 | { |
210 | 0 | iso_11548_1=1; |
211 | 0 | cell_height=3; |
212 | 0 | } |
213 | 0 | else |
214 | 0 | cell_height=3; |
215 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
216 | 0 | if (status == False) |
217 | 0 | return(status); |
218 | 0 | if (!iso_11548_1) |
219 | 0 | { |
220 | 0 | if (image->page.x != 0) |
221 | 0 | { |
222 | 0 | (void) MagickFormatString(buffer,sizeof(buffer),"X: %.20g\n",(double) |
223 | 0 | image->page.x); |
224 | 0 | (void) WriteBlobString(image,buffer); |
225 | 0 | } |
226 | 0 | if (image->page.y != 0) |
227 | 0 | { |
228 | 0 | (void) MagickFormatString(buffer,sizeof(buffer),"Y: %.20g\n",(double) |
229 | 0 | image->page.y); |
230 | 0 | (void) WriteBlobString(image,buffer); |
231 | 0 | } |
232 | 0 | (void) MagickFormatString(buffer,sizeof(buffer),"Width: %.20g\n",(double) |
233 | 0 | image->columns+(image->columns % 2)); |
234 | 0 | (void) WriteBlobString(image,buffer); |
235 | 0 | (void) MagickFormatString(buffer,sizeof(buffer),"Height: %.20g\n",(double) |
236 | 0 | image->rows); |
237 | 0 | (void) WriteBlobString(image,buffer); |
238 | 0 | (void) WriteBlobString(image,"\n"); |
239 | 0 | } |
240 | 0 | polarity=PixelIntensityToQuantum(&image->colormap[0]) >= (MaxRGB/2); |
241 | 0 | if (image->colors == 2) |
242 | 0 | polarity=PixelIntensityToQuantum(&image->colormap[0]) >= |
243 | 0 | PixelIntensityToQuantum(&image->colormap[1]); |
244 | 0 | for (y=0; y < image->rows; y+=cell_height) |
245 | 0 | { |
246 | 0 | if ((y+cell_height) > image->rows) |
247 | 0 | cell_height = (image->rows-y); |
248 | 0 | p=AcquireImagePixels(image,0,y,image->columns,cell_height,&image->exception); |
249 | 0 | if (p == (const PixelPacket *) NULL) |
250 | 0 | break; |
251 | 0 | indexes=AccessImmutableIndexes(image); |
252 | 0 | for (x=0; x < image->columns; x+=2) |
253 | 0 | { |
254 | 0 | unsigned char cell = 0; |
255 | 0 | unsigned long two_columns = x+1 < image->columns; |
256 | |
|
257 | 0 | do |
258 | 0 | { |
259 | 0 | #define do_cell(dx,dy,bit) do { \ |
260 | 0 | cell |= (indexes[x+dx+dy*image->columns] == polarity) << bit; \ |
261 | 0 | } while (0) |
262 | |
|
263 | 0 | do_cell(0,0,0); |
264 | 0 | if (two_columns) |
265 | 0 | do_cell(1,0,3); |
266 | 0 | if (cell_height < 2) |
267 | 0 | break; |
268 | | |
269 | 0 | do_cell(0,1,1); |
270 | 0 | if (two_columns) |
271 | 0 | do_cell(1,1,4); |
272 | 0 | if (cell_height < 3) |
273 | 0 | break; |
274 | | |
275 | 0 | do_cell(0,2,2); |
276 | 0 | if (two_columns) |
277 | 0 | do_cell(1,2,5); |
278 | 0 | if (cell_height < 4) |
279 | 0 | break; |
280 | | |
281 | 0 | do_cell(0,3,6); |
282 | 0 | if (two_columns) |
283 | 0 | do_cell(1,3,7); |
284 | 0 | } while(0); |
285 | |
|
286 | 0 | if (unicode) |
287 | 0 | { |
288 | 0 | unsigned char utf8[3]; |
289 | | /* Unicode text */ |
290 | 0 | utf8[0] = (unsigned char) (0xe0|((0x28>>4)&0x0f)); |
291 | 0 | utf8[1] = 0x80|((0x28<<2)&0x3f)|(cell>>6); |
292 | 0 | utf8[2] = 0x80|(cell&0x3f); |
293 | 0 | (void) WriteBlob(image,3,utf8); |
294 | 0 | } |
295 | 0 | else if (iso_11548_1) |
296 | 0 | { |
297 | | /* ISO/TR 11548-1 binary */ |
298 | 0 | (void) WriteBlobByte(image,cell); |
299 | 0 | } |
300 | 0 | else |
301 | 0 | { |
302 | | /* BRF */ |
303 | 0 | static const unsigned char iso_to_brf[64] = { |
304 | 0 | ' ', 'A', '1', 'B', '\'', 'K', '2', 'L', |
305 | 0 | '@', 'C', 'I', 'F', '/', 'M', 'S', 'P', |
306 | 0 | '"', 'E', '3', 'H', '9', 'O', '6', 'R', |
307 | 0 | '^', 'D', 'J', 'G', '>', 'N', 'T', 'Q', |
308 | 0 | ',', '*', '5', '<', '-', 'U', '8', 'V', |
309 | 0 | '.', '%', '[', '$', '+', 'X', '!', '&', |
310 | 0 | ';', ':', '4', '\\', '0', 'Z', '7', '(', |
311 | 0 | '_', '?', 'W', ']', '#', 'Y', ')', '=' |
312 | 0 | }; |
313 | 0 | if (cell >= 64) |
314 | 0 | cell = 0; |
315 | 0 | (void) WriteBlobByte(image,iso_to_brf[cell]); |
316 | 0 | } |
317 | 0 | } |
318 | 0 | if (iso_11548_1 == 0) |
319 | 0 | (void) WriteBlobByte(image,'\n'); |
320 | 0 | } |
321 | 0 | status &= CloseBlob(image); |
322 | 0 | return(status); |
323 | 0 | } |