KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > pdfbox > filter > CCITTFaxDecodeFilter


1 /**
2  * Copyright (c) 2003-2005, www.pdfbox.org
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. Neither the name of pdfbox; nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * http://www.pdfbox.org
29  *
30  */

31 package org.pdfbox.filter;
32
33 import java.io.ByteArrayOutputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.io.OutputStream JavaDoc;
37 import java.text.SimpleDateFormat JavaDoc;
38 import java.util.Date JavaDoc;
39
40 import org.pdfbox.cos.COSDictionary;
41 import org.pdfbox.cos.COSName;
42
43 /**
44  * This is a filter for the CCITTFax Decoder.
45  *
46  * @author <a HREF="mailto:ben@benlitchfield.com">Ben Litchfield</a>
47  * @author Marcel Kammer
48  * @author Paul King
49  * @version $Revision: 1.12 $
50  */

51 public class CCITTFaxDecodeFilter implements Filter
52 {
53     // Filter will write 15 TAG's
54
// If you add or remove TAG's you will have to modify this value
55
private static final int TAG_COUNT = 15;
56
57     // HEADERLENGTH(fix 8 Bytes) plus ImageLength(variable)
58
private int offset = 8;
59
60     // Bytecounter for Bytes that will be written after the TAG-DICTIONARY
61
private int tailingBytesCount = 0;
62
63     // Bytes to write after TAG-DICTIONARY
64
private final ByteArrayOutputStream JavaDoc tailer = new ByteArrayOutputStream JavaDoc();
65
66     /**
67      * Constructor.
68      */

69     public CCITTFaxDecodeFilter()
70     {
71     }
72
73     /**
74      * This will decode some compressed data.
75      *
76      * @param compressedData
77      * The compressed byte stream.
78      * @param result
79      * The place to write the uncompressed byte stream.
80      * @param options
81      * The options to use to encode the data.
82      *
83      * @throws IOException
84      * If there is an error decompressing the stream.
85      */

86     public void decode(InputStream JavaDoc compressedData, OutputStream JavaDoc result, COSDictionary options) throws IOException JavaDoc
87     {
88         // log.warn( "Warning: CCITTFaxDecode.decode is not implemented yet,
89
// skipping this stream." );
90

91
92         // Get ImageParams from PDF
93
COSDictionary dict = (COSDictionary) options.getDictionaryObject("DecodeParms");
94         int width = options.getInt("Width");
95         int height = options.getInt("Height");
96         int length = options.getInt(COSName.LENGTH);
97         int compressionType = dict.getInt("K");
98         boolean blackIs1 = dict.getBoolean("BlackIs1", false);
99         
100         
101         // HEADER-INFO and starting point of TAG-DICTIONARY
102
writeTagHeader(result, length);
103
104         // IMAGE-DATA
105
int i = 0;
106         //int sum = 0;
107
byte[] buffer = new byte[32768];
108         int lentoread = length;
109         
110         while ((lentoread > 0) && ((i = compressedData.read(buffer, 0, Math.min(lentoread, 32768))) != -1))
111         {
112             //sum += i;
113
result.write(buffer, 0, i);
114             lentoread = lentoread - i;
115         }
116         
117         // If lentoread is > 0 then we need to write out some padding to equal the header
118
// We'll use what we have in the buffer it's just padding after all
119
while (lentoread > 0)
120         {
121             result.write(buffer, 0, Math.min(lentoread, 32768));
122             lentoread = lentoread - Math.min(lentoread, 32738);
123         }
124         //System.out.println("Gelesen: " + sum);
125

126         // TAG-COUNT
127
writeTagCount(result);
128
129         // WIDTH 0x0100
130
writeTagWidth(result, width);
131
132         // HEIGHT 0x0101
133
writeTagHeight(result, height);
134
135         // BITSPERSAMPLE 0x0102
136
// Always 1 for CCITTFax
137
writeTagBitsPerSample(result, 1);
138
139         // COMPRESSION 0x0103
140
writeTagCompression(result, compressionType);
141
142         // PHOTOMETRIC 0x0106
143
writeTagPhotometric(result, blackIs1);
144
145         // STRIPOFFSET 0x0111
146
// HERE ALWAYS 8, because ImageData comes before TAG-DICTIONARY
147
writeTagStripOffset(result, 8);
148
149         // ORIENTATION 0x0112
150
writeTagOrientation(result, 1);
151
152         // SamplesPerPixel 0x0115
153
writeTagSamplesPerPixel(result, 1);
154
155         // RowsPerStrip 0x0116
156
writeTagRowsPerStrip(result, height);
157
158         // Stripcount 0x0117
159
writeTagStripByteCount(result, length);
160
161         // XRESOLUTION 0x011A
162
// HERE: 200 DPI
163
writeTagXRes(result, 200, 1);
164
165         // YRESOLITION 0x011B
166
// HERE: 200 DPI
167
writeTagYRes(result, 200, 1);
168
169         // ResolutionUnit 0x0128
170
// HERE: DPI
171
writeTagResolutionUnit(result, 2);
172
173         // SOFTWARE 0x0131
174
// minimum 4 chars
175
writeTagSoftware(result, "pdfbox".getBytes());
176
177         // DATE AND TIME 0x0132
178
writeTagDateTime(result, new Date JavaDoc());
179
180         // END OF TAG-DICT
181
writeTagTailer(result);
182     }
183
184     private void writeTagHeader(OutputStream JavaDoc result, int length) throws IOException JavaDoc
185     {
186         byte[] header = { 'M', 'M', 0, '*' };// Big-endian
187
result.write(header);
188
189
190         // Add imagelength to offset
191
offset += length;
192
193         // OFFSET TAG-DICTIONARY
194
int i1 = offset/16777216;//=value/(256*256*256)
195
int i2 = (offset-i1*16777216)/65536;
196         int i3 = (offset-i1*16777216-i2*65536)/256;
197         int i4 = offset % 256;
198         result.write(i1);
199         result.write(i2);
200         result.write(i3);
201         result.write(i4);
202     }
203
204     private void writeTagCount(OutputStream JavaDoc result) throws IOException JavaDoc
205     {
206         result.write(TAG_COUNT / 256);
207         result.write(TAG_COUNT % 256);// tagCount
208
}
209
210     private void writeTagWidth(OutputStream JavaDoc result, int width) throws IOException JavaDoc
211     {
212         // @todo width berechnen
213

214         // TAG-ID 100
215
result.write(1);
216         result.write(0);
217
218
219         // TAG-TYPE SHORT=3
220
result.write(0);
221         result.write(3);
222
223
224         // TAG-LENGTH = 1
225
result.write(0);
226         result.write(0);
227         result.write(0);
228         result.write(1);
229
230
231         // TAG-VALUE = width
232
result.write(width/256);
233         result.write(width%256);
234         result.write(0);// SHORT=0
235
result.write(0);// SHORT=0
236

237     }
238
239     private void writeTagHeight(OutputStream JavaDoc result, int height) throws IOException JavaDoc
240     {
241         //@todo height berechnen
242
// TAG-ID 101
243
result.write(1);
244         result.write(1);
245     
246
247         // TAG-TYPE SHORT=3
248
result.write(0);
249         result.write(3);
250         
251
252         // TAG-LENGTH = 1
253
result.write(0);
254         result.write(0);
255         result.write(0);
256         result.write(1);
257         
258
259         // TAG-VALUE
260
result.write(height/256);
261         result.write(height%256);
262         result.write(0);// SHORT=0
263
result.write(0);// SHORT=0
264

265     }
266
267     private void writeTagBitsPerSample(OutputStream JavaDoc result, int value) throws IOException JavaDoc
268     {
269         // TAG-ID 102
270
result.write(1);
271         result.write(2);
272         
273
274         // TAG-TYPE SHORT=3
275
result.write(0);
276         result.write(3);
277     
278         // TAG-LENGTH = 1
279
result.write(0);
280         result.write(0);
281         result.write(0);
282         result.write(1);
283         
284
285         // TAG-VALUE
286
result.write(value/256);
287         result.write(value%256);
288         result.write(0);//SHORT=0
289
result.write(0);//SHORT=0
290

291     }
292     
293     /**
294      * Write the tag compression.
295      *
296      * @param result The stream to write to.
297      * @param type The type to write.
298      * @throws IOException If there is an error writing to the stream.
299      */

300     public void writeTagCompression(OutputStream JavaDoc result, int type) throws IOException JavaDoc
301     {
302         // TAG-ID 103
303
result.write(1);
304         result.write(3);
305         
306         // TAG-TYPE SHORT=3
307
result.write(0);
308         result.write(3);
309         
310
311         // TAG-LEGNTH = 1
312
result.write(0);
313         result.write(0);
314         result.write(0);
315         result.write(1);
316         
317         // TAG-VALUE
318
//@todo typ eintragen; hier immer 4
319
result.write(0);
320         if (type < 0)
321         {
322             result.write(4);// G4
323
}
324         else if (type == 0)
325         {
326             result.write(3);// G3-1D
327
}
328         else
329         {
330             result.write(2);// G3-2D
331
}
332         result.write(0);
333         result.write(0);
334         
335     }
336
337     private void writeTagPhotometric(OutputStream JavaDoc result, boolean blackIs1) throws IOException JavaDoc
338     {
339         // TAG-ID 106
340
result.write(1);
341         result.write(6);
342         
343
344         // TAG-TYPE SHORT
345
result.write(0);
346         result.write(3);
347         
348
349         // TAG-LENGTH = 1
350
result.write(0);
351         result.write(0);
352         result.write(0);
353         result.write(1);
354         
355
356         // TAG-VALUE
357
result.write(0);
358         if (blackIs1)
359         {
360             result.write(1);
361         }
362         else
363         {
364             result.write(0);
365         }
366         result.write(0);// SHORT=0
367
result.write(0);// SHORT=0
368

369     }
370
371     private void writeTagStripOffset(OutputStream JavaDoc result, int value) throws IOException JavaDoc
372     {
373         // TAG-ID 111
374
result.write(1);
375         result.write(17);
376         
377         // TAG-TYPE LONG=4
378
result.write(0);
379         result.write(4);
380         
381
382         // TAG-LENGTH=1
383
result.write(0);
384         result.write(0);
385         result.write(0);
386         result.write(1);
387         
388
389         // TAG-VALUE = 8 //VOR TAG-DICTIONARY
390
int i1 = value/16777216;//=value/(256*256*256)
391
int i2 = (value-i1*16777216)/65536;
392         int i3 = (value-i1*16777216-i2*65536)/256;
393         int i4 = value % 256;
394         result.write(i1);
395         result.write(i2);
396         result.write(i3);
397         result.write(i4);
398     
399     }
400
401     private void writeTagSamplesPerPixel(OutputStream JavaDoc result, int value) throws IOException JavaDoc
402     {
403         // TAG-ID 115
404
result.write(1);
405         result.write(21);
406         
407
408         // TAG-TYPE SHORT=3
409
result.write(0);
410         result.write(3);
411         
412
413         // TAG-LENGTH=1
414
result.write(0);
415         result.write(0);
416         result.write(0);
417         result.write(1);
418         
419
420         // TAG-VALUE
421
result.write(value / 256);
422         result.write(value % 256);
423         result.write(0);// SHORT=0
424
result.write(0);// SHORT=0
425

426     }
427
428     private void writeTagRowsPerStrip(OutputStream JavaDoc result, int value) throws IOException JavaDoc
429     {
430         // TAG-ID 116
431
result.write(1);
432         result.write(22);
433         
434
435         // TAG-TYPE SHORT=3
436
result.write(0);
437         result.write(3);
438     
439
440         // TAG-LENGTH=1
441
result.write(0);
442         result.write(0);
443         result.write(0);
444         result.write(1);
445     
446
447         // TAG-VALUE
448
result.write(value / 256);
449         result.write(value % 256);
450         result.write(0);// SHORT=0
451
result.write(0);// SHORT=0
452

453     }
454
455     private void writeTagStripByteCount(OutputStream JavaDoc result, int value) throws IOException JavaDoc
456     {
457         //@todo value auswerten
458
// TAG-ID 117
459
result.write(1);
460         result.write(23);
461     
462         // TAG-TYPE LONG=4
463
result.write(0);
464         result.write(4);
465     
466
467         // TAG-LENGTH = 1
468
result.write(0);
469         result.write(0);
470         result.write(0);
471         result.write(1);
472         
473         // TAG-VALUE
474
int i1 = value/16777216;//=value/(256*256*256)
475
int i2 = (value-i1*16777216)/65536;
476         int i3 = (value-i1*16777216-i2*65536)/256;
477         int i4 = value % 256;
478         result.write(i1);
479         result.write(i2);
480         result.write(i3);
481         result.write(i4);
482         
483     }
484
485     private void writeTagXRes(OutputStream JavaDoc result, int value1, int value2) throws IOException JavaDoc
486     {
487         // TAG-ID 11A
488
result.write(1);
489         result.write(26);
490         
491         // TAG-TYPE RATIONAL=5
492
result.write(0);
493         result.write(5);
494         
495         // TAG-LENGTH=1
496
result.write(0);
497         result.write(0);
498         result.write(0);
499         result.write(1);
500         
501
502         // TAG-VALUE=OFFSET TO RATIONAL
503
int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
504         int i1 = valueOffset/16777216;//=value/(256*256*256)
505
int i2 = (valueOffset-i1*16777216)/65536;
506         int i3 = (valueOffset-i1*16777216-i2*65536)/256;
507         int i4 = valueOffset % 256;
508         result.write(i1);
509         result.write(i2);
510         result.write(i3);
511         result.write(i4);
512         
513         i1 = value1 /16777216;
514         i2 = (value1-i1*16777216)/65536;
515         i3 = (value1-i1*16777216 - i2*65536)/256;
516         i4 = value1 % 256;
517         tailer.write(i1);
518         tailer.write(i2);
519         tailer.write(i3);
520         tailer.write(i4);
521         
522         i1 = value2 /16777216;
523         i2 = (value2-i1*16777216)/65536;
524         i3 = (value2-i1*16777216 - i2*65536)/256;
525         i4 = value2 % 256;
526         tailer.write(i1);
527         tailer.write(i2);
528         tailer.write(i3);
529         tailer.write(i4);
530         
531         tailingBytesCount += 8;
532     }
533
534     private void writeTagYRes(OutputStream JavaDoc result, int value1, int value2) throws IOException JavaDoc
535     {
536         // TAG-ID 11B
537
result.write(1);
538         result.write(27);
539         
540
541         // TAG-TYPE RATIONAL=5
542
result.write(0);
543         result.write(5);
544         
545         // TAG-LENGTH=1
546
result.write(0);
547         result.write(0);
548         result.write(0);
549         result.write(1);
550         
551
552         // TAG-VALUE=OFFSET TO RATIONAL
553
int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
554         int i1 = valueOffset/16777216;//=value/(256*256*256)
555
int i2 = (valueOffset-i1*16777216)/65536;
556         int i3 = (valueOffset-i1*16777216-i2*65536)/256;
557         int i4 = valueOffset % 256;
558         result.write(i1);
559         result.write(i2);
560         result.write(i3);
561         result.write(i4);
562         
563         i1 = value1 /16777216;
564         i2 = (value1-i1*16777216)/65536;
565         i3 = (value1-i1*16777216 - i2*65536)/256;
566         i4 = value1 % 256;
567         tailer.write(i1);
568         tailer.write(i2);
569         tailer.write(i3);
570         tailer.write(i4);
571         
572         i1 = value2 /16777216;
573         i2 = (value2-i1*16777216)/65536;
574         i3 = (value2-i1*16777216 - i2*65536)/256;
575         i4 = value2 % 256;
576         tailer.write(i1);
577         tailer.write(i2);
578         tailer.write(i3);
579         tailer.write(i4);
580         
581         tailingBytesCount += 8;
582     }
583
584     private void writeTagResolutionUnit(OutputStream JavaDoc result, int value) throws IOException JavaDoc
585     {
586         // TAG-ID 128
587
result.write(1);
588         result.write(40);
589         
590         // TAG-TYPE SHORT=3
591
result.write(0);
592         result.write(3);
593         
594         // TAG-LENGTH = 1
595
result.write(0);
596         result.write(0);
597         result.write(0);
598         result.write(1);
599         
600         // TAG-VALUE
601
result.write(value/256);
602         result.write(value%256);
603         result.write(0);// SHORT=0
604
result.write(0);// SHORT=0
605

606     }
607
608     private void writeTagOrientation(OutputStream JavaDoc result, int value) throws IOException JavaDoc
609     {
610         // TAG-ID 112
611
result.write(1);
612         result.write(18);
613         
614         // TAG-TYPE SHORT = 3
615
result.write(0);
616         result.write(3);
617         
618
619         // TAG-LENGTH=1
620
result.write(0);
621         result.write(0);
622         result.write(0);
623         result.write(1);
624         
625         // TAG-VALUE
626
result.write(value / 256);
627         result.write(value % 256);
628         result.write(0);// SHORT=0
629
result.write(0);// SHORT=0
630

631     }
632
633     private void writeTagTailer(OutputStream JavaDoc result) throws IOException JavaDoc
634     {
635         // END OF TAG-DICTIONARY
636
result.write(0);
637         result.write(0);
638         result.write(0);
639         result.write(0);
640         
641         // TAILER WITH VALUES OF RATIONALFIELD's
642
result.write(tailer.toByteArray());
643     }
644
645     private void writeTagSoftware(OutputStream JavaDoc result, byte[] text) throws IOException JavaDoc
646     {
647         // TAG-ID 131
648
result.write(1);
649         result.write(49);
650         
651         // TAG-TYPE ASCII=2
652
result.write(0);
653         result.write(2);
654         
655
656         // TAG-LENGTH=id.length+1
657
result.write(0);
658         result.write(0);
659         result.write((text.length + 1) / 256);
660         result.write((text.length + 1) % 256);
661         
662         // TAG-VALUE
663
int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
664         int i1 = valueOffset/16777216;//=value/(256*256*256)
665
int i2 = (valueOffset-i1*16777216)/65536;
666         int i3 = (valueOffset-i1*16777216-i2*65536)/256;
667         int i4 = valueOffset % 256;
668         result.write(i1);
669         result.write(i2);
670         result.write(i3);
671         result.write(i4);
672         
673
674         tailer.write(text);
675         tailer.write(0);
676         tailingBytesCount += text.length + 1;
677     }
678
679     private void writeTagDateTime(OutputStream JavaDoc result, Date JavaDoc date) throws IOException JavaDoc
680     {
681         // TAG-ID 132
682
result.write(1);
683         result.write(50);
684         
685
686         // TAG-TYPE ASCII=2
687
result.write(0);
688         result.write(2);
689         
690
691         // TAG-LENGTH=20
692
result.write(0);
693         result.write(0);
694         result.write(0);
695         result.write(20);
696     
697
698         // TAG-VALUE
699
int valueOffset = offset + 6 + 12 * TAG_COUNT + tailer.size();
700         int i1 = valueOffset/16777216;//=value/(256*256*256)
701
int i2 = (valueOffset-i1*16777216)/65536;
702         int i3 = (valueOffset-i1*16777216-i2*65536)/256;
703         int i4 = valueOffset % 256;
704         result.write(i1);
705         result.write(i2);
706         result.write(i3);
707         result.write(i4);
708         
709         SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc("yyyy:MM:dd HH:mm:ss");
710         String JavaDoc datetime = sdf.format(date);
711         tailer.write(datetime.getBytes());
712         tailer.write(0);
713
714         tailingBytesCount += 20;
715     }
716
717     /**
718      * This will encode some data.
719      *
720      * @param rawData
721      * The raw data to encode.
722      * @param result
723      * The place to write to encoded results to.
724      * @param options
725      * The options to use to encode the data.
726      *
727      * @throws IOException
728      * If there is an error compressing the stream.
729      */

730     public void encode(InputStream JavaDoc rawData, OutputStream JavaDoc result, COSDictionary options) throws IOException JavaDoc
731     {
732         System.err.println("Warning: CCITTFaxDecode.encode is not implemented yet, skipping this stream.");
733     }
734 }
Popular Tags