1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.imaging.formats.pnm;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22
23 import org.apache.commons.imaging.ImageFormat;
24 import org.apache.commons.imaging.ImageFormats;
25 import org.apache.commons.imaging.ImageInfo;
26 import org.apache.commons.imaging.ImagingException;
27
28 final class PamFileInfo extends AbstractFileInfo {
29 private final class ColorTupleReader extends TupleReader {
30 @Override
31 public ImageInfo.ColorType getColorType() {
32 return ImageInfo.ColorType.RGB;
33 }
34
35 @Override
36 public int getRgb(final InputStream is) throws IOException {
37 int red = readSample(is, bytesPerSample);
38 int green = readSample(is, bytesPerSample);
39 int blue = readSample(is, bytesPerSample);
40
41 red = scaleSample(red, scale, maxval);
42 green = scaleSample(green, scale, maxval);
43 blue = scaleSample(blue, scale, maxval);
44
45 int alpha = 0xff;
46 if (hasAlpha) {
47 alpha = readSample(is, bytesPerSample);
48 alpha = scaleSample(alpha, scale, maxval);
49 }
50
51 return (0xff & alpha) << 24 | (0xff & red) << 16 | (0xff & green) << 8 | (0xff & blue) << 0;
52 }
53 }
54
55 private final class GrayscaleTupleReader extends TupleReader {
56 private final ImageInfo.ColorType colorType;
57
58 GrayscaleTupleReader(final ImageInfo.ColorType colorType) {
59 this.colorType = colorType;
60 }
61
62 @Override
63 public ImageInfo.ColorType getColorType() {
64 return colorType;
65 }
66
67 @Override
68 public int getRgb(final InputStream is) throws IOException {
69 int sample = readSample(is, bytesPerSample);
70 sample = scaleSample(sample, scale, maxval);
71
72 int alpha = 0xff;
73 if (hasAlpha) {
74 alpha = readSample(is, bytesPerSample);
75 alpha = scaleSample(alpha, scale, maxval);
76 }
77
78 return (0xff & alpha) << 24 | (0xff & sample) << 16 | (0xff & sample) << 8 | (0xff & sample) << 0;
79 }
80 }
81
82 private abstract static class TupleReader {
83 public abstract ImageInfo.ColorType getColorType();
84
85 public abstract int getRgb(InputStream is) throws IOException;
86 }
87
88 private final int depth;
89 private final int maxval;
90 private final float scale;
91
92 private final int bytesPerSample;
93
94 private final boolean hasAlpha;
95
96 private final TupleReader tupleReader;
97
98 PamFileInfo(final int width, final int height, final int depth, final int maxval, final String tupleType) throws ImagingException {
99 super(width, height, true);
100 this.depth = depth;
101 this.maxval = maxval;
102 if (maxval <= 0) {
103 throw new ImagingException("PAM maxVal " + maxval + " is out of range [1;65535]");
104 }
105 if (maxval <= 255) {
106 scale = 255f;
107 bytesPerSample = 1;
108 } else if (maxval <= 65535) {
109 scale = 65535f;
110 bytesPerSample = 2;
111 } else {
112 throw new ImagingException("PAM maxVal " + maxval + " is out of range [1;65535]");
113 }
114
115 hasAlpha = tupleType.endsWith("_ALPHA");
116 switch (tupleType) {
117 case "BLACKANDWHITE":
118 case "BLACKANDWHITE_ALPHA":
119 tupleReader = new GrayscaleTupleReader(ImageInfo.ColorType.BW);
120 break;
121 case "GRAYSCALE":
122 case "GRAYSCALE_ALPHA":
123 tupleReader = new GrayscaleTupleReader(ImageInfo.ColorType.GRAYSCALE);
124 break;
125 case "RGB":
126 case "RGB_ALPHA":
127 tupleReader = new ColorTupleReader();
128 break;
129 default:
130 throw new ImagingException("Unknown PAM tupletype '" + tupleType + "'");
131 }
132 }
133
134 @Override
135 public int getBitDepth() {
136 return maxval;
137 }
138
139 @Override
140 public ImageInfo.ColorType getColorType() {
141 return tupleReader.getColorType();
142 }
143
144 @Override
145 public ImageFormat getImageType() {
146 return ImageFormats.PAM;
147 }
148
149 @Override
150 public String getImageTypeDescription() {
151 return "PAM: portable arbitrary map file format";
152 }
153
154 @Override
155 public String getMimeType() {
156 return "image/x-portable-arbitrary-map";
157 }
158
159 @Override
160 public int getNumComponents() {
161 return depth;
162 }
163
164 @Override
165 public int getRgb(final InputStream is) throws IOException {
166 return tupleReader.getRgb(is);
167 }
168
169 @Override
170 public int getRgb(final WhiteSpaceReader wsr) throws IOException {
171 throw new UnsupportedOperationException("PAM files are only ever binary");
172 }
173
174 @Override
175 public boolean hasAlpha() {
176 return hasAlpha;
177 }
178 }