1
2 package org.freehep.graphicsio.ps;
3
4 import java.awt.Image;
5 import java.awt.image.ImageProducer;
6 import java.io.DataOutputStream;
7 import java.io.IOException;
8 import java.io.OutputStream;
9
10 import org.freehep.graphicsio.ImageEncoder;
11
12
13
14
15
16
17 public class EPSIEncoder extends ImageEncoder {
18
19
20 final static int maxBitsPerByte = 8;
21
22
23 final static int maxBytesPerScan = 128;
24
25
26 private int grayscaleBits;
27
28
29 private boolean portrait;
30
31
32 int width, height;
33
34
35 byte[][] grayPixels;
36
37
38 Scanline scanline;
39
40
41 private static char[] hexDigit = { '0', '1', '2', '3', '4', '5', '6', '7',
42 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
43
44
45 final private static byte[] lowBitMask = { (byte) 0, (byte) 1, (byte) 3,
46 (byte) 7, (byte) 15, (byte) 31, (byte) 63, (byte) 127, (byte) 255 };
47
48
49
50
51
52
53
54
55
56 public EPSIEncoder(Image img, OutputStream out, int grayscaleBits,
57 boolean portrait) throws IOException {
58
59 super(img, new DataOutputStream(out));
60 this.grayscaleBits = grayscaleBits;
61 this.portrait = portrait;
62 }
63
64
65
66
67
68
69
70
71
72 public EPSIEncoder(ImageProducer prod, OutputStream out, int grayscaleBits,
73 boolean portrait) throws IOException {
74
75 super(prod, new DataOutputStream(out));
76 this.grayscaleBits = grayscaleBits;
77 this.portrait = portrait;
78 }
79
80 protected void encodeStart(int width, int height) throws IOException {
81
82 this.width = width;
83 this.height = height;
84 grayPixels = new byte[height][width];
85
86
87 int w, h;
88 if (portrait) {
89 w = width;
90 h = height;
91 } else {
92 w = height;
93 h = width;
94 }
95
96
97 int bitsPerScan = w * grayscaleBits;
98 int bytesPerScan = (bitsPerScan / maxBitsPerByte)
99 + ((bitsPerScan % maxBitsPerByte == 0) ? 0 : 1);
100 int linesPerScan = (bytesPerScan / maxBytesPerScan)
101 + ((bytesPerScan % maxBytesPerScan == 0) ? 0 : 1);
102 int lines = linesPerScan * h;
103
104
105 scanline = new Scanline(bytesPerScan, grayscaleBits);
106
107
108 putString("%%BeginPreview " + width + " " + height + " "
109 + grayscaleBits + " " + lines + "\n");
110 }
111
112 protected void encodePixels(int x, int y, int w, int h, int[] rgbPixels,
113 int off, int scansize) throws IOException {
114
115
116 for (int row = 0; row < h; ++row) {
117 for (int column = 0; column < w; column++) {
118 grayPixels[y + row][column] = toGrayscale(rgbPixels[row
119 * scansize + off + column]);
120 }
121 }
122 }
123
124
125 private byte toGrayscale(int argb) {
126 int mask = 0xFF;
127 double blue = ((double) ((argb >> 0) & mask)) / 255.;
128 double green = ((double) ((argb >> 8) & mask)) / 255.;
129 double red = ((double) ((argb >> 16) & mask)) / 255.;
130
131 return (byte) (255. * Math.max(0.,
132 (1. - (0.3 * red + 0.59 * green + 0.11 * blue))));
133 }
134
135 protected void encodeDone() throws IOException {
136
137 if (portrait) {
138 for (int row = height - 1; row >= 0; row--) {
139 scanline.reset();
140 for (int col = 0; col < width; col++) {
141 byte gray = grayPixels[row][col];
142 scanline.add(gray);
143 }
144 scanline.put();
145 }
146 } else {
147 for (int col = width - 1; col >= 0; col--) {
148 scanline.reset();
149 for (int row = height - 1; row >= 0; row--) {
150 byte gray = grayPixels[row][col];
151 scanline.add(gray);
152 }
153 scanline.put();
154 }
155 }
156
157
158 putString("%%EndPreview\n");
159 }
160
161
162 void putString(String s) throws IOException {
163
164 out.write(s.getBytes());
165 }
166
167
168 void putChar(char c) throws IOException {
169
170 out.write(c);
171 }
172
173
174 void putByte(byte b) throws IOException {
175
176 int highNibble = (b >> 4) & 0xF;
177 int lowNibble = b & 0xF;
178
179 out.write(hexDigit[highNibble]);
180 out.write(hexDigit[lowNibble]);
181 }
182
183
184
185 private class Scanline {
186
187 private byte[] line;
188
189 private int nbits;
190
191 private int currentByte;
192
193 private int currentOffset;
194
195 public Scanline(int size, int nbits) {
196 line = new byte[size];
197 this.nbits = nbits;
198 reset();
199 }
200
201
202
203 public void reset() {
204 currentByte = 0;
205 currentOffset = 0;
206 for (int i = 0; i < line.length; i++) {
207 line[i] = 0;
208 }
209 }
210
211 public void add(byte b) {
212
213
214 b >>= (maxBitsPerByte - nbits);
215 b &= lowBitMask[nbits];
216
217
218 line[currentByte] |= b;
219
220
221 if (maxBitsPerByte - nbits - currentOffset == 0) {
222
223
224 currentOffset = 0;
225 currentByte++;
226 } else {
227
228
229
230 currentOffset += nbits;
231 line[currentByte] <<= nbits;
232 }
233 }
234
235 public void put() throws IOException {
236
237
238
239
240 while (maxBitsPerByte - nbits - currentOffset > 0) {
241 line[line.length - 1] <<= nbits;
242 currentOffset += nbits;
243 }
244
245 for (int i = 0; i < line.length; i++) {
246 if (i % maxBytesPerScan == 0) {
247 if (i != 0)
248 putChar('\n');
249 putChar('%');
250 }
251 putByte(line[i]);
252 }
253 putChar('\n');
254 }
255 }
256
257 }