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