aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/util/pngj/ImageInfo.java
blob: 26562ef3e89b2457ff3c11a502c77dd7b23ef722 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package jogamp.opengl.util.pngj;

/**
 * Simple immutable wrapper for basic image info.
 * <p>
 * Some parameters are redundant, but the constructor receives an 'orthogonal' subset.
 * <p>
 * ref: http://www.w3.org/TR/PNG/#11IHDR
 */
public class ImageInfo {

	// very big value ; actually we are ok with 2**22=4M, perhaps even more
	private static final int MAX_COLS_ROWS_VAL = 1000000;

	/**
	 * Cols= Image width, in pixels.
	 */
	public final int cols;

	/**
	 * Rows= Image height, in pixels
	 */
	public final int rows;

	/**
	 * Bits per sample (per channel) in the buffer (1-2-4-8-16). This is 8-16 for RGB/ARGB images, 1-2-4-8 for
	 * grayscale. For indexed images, number of bits per palette index (1-2-4-8)
	 */
	public final int bitDepth;

	/**
	 * Number of channels, as used internally: 3 for RGB, 4 for RGBA, 2 for GA (gray with alpha), 1 for grayscale or
	 * indexed.
	 */
	public final int channels;

	/**
	 * Flag: true if has alpha channel (RGBA/GA)
	 */
	public final boolean alpha;

	/**
	 * Flag: true if is grayscale (G/GA)
	 */
	public final boolean greyscale;

	/**
	 * Flag: true if image is indexed, i.e., it has a palette
	 */
	public final boolean indexed;

	/**
	 * Flag: true if image internally uses less than one byte per sample (bit depth 1-2-4)
	 */
	public final boolean packed;

	/**
	 * Bits used for each pixel in the buffer: channel * bitDepth
	 */
	public final int bitspPixel;

	/**
	 * rounded up value: this is only used internally for filter
	 */
	public final int bytesPixel;

	/**
	 * ceil(bitspp*cols/8)
	 */
	public final int bytesPerRow;

	/**
	 * Equals cols * channels
	 */
	public final int samplesPerRow;

	/**
	 * Amount of "packed samples" : when several samples are stored in a single byte (bitdepth 1,2 4) they are counted
	 * as one "packed sample". This is less that samplesPerRow only when bitdepth is 1-2-4 (flag packed = true)
	 * <p>
	 * This equals the number of elements in the scanline array if working with packedMode=true
	 * <p>
	 * For internal use, client code should rarely access this.
	 */
	public final int samplesPerRowPacked;

	/**
	 * Short constructor: assumes truecolor (RGB/RGBA)
	 */
	public ImageInfo(int cols, int rows, int bitdepth, boolean alpha) {
		this(cols, rows, bitdepth, alpha, false, false);
	}

	/**
	 * Full constructor
	 * 
	 * @param cols
	 *            Width in pixels
	 * @param rows
	 *            Height in pixels
	 * @param bitdepth
	 *            Bits per sample, in the buffer : 8-16 for RGB true color and greyscale
	 * @param alpha
	 *            Flag: has an alpha channel (RGBA or GA)
	 * @param grayscale
	 *            Flag: is gray scale (any bitdepth, with or without alpha)
	 * @param indexed
	 *            Flag: has palette
	 */
	public ImageInfo(int cols, int rows, int bitdepth, boolean alpha, boolean grayscale, boolean indexed) {
		this.cols = cols;
		this.rows = rows;
		this.alpha = alpha;
		this.indexed = indexed;
		this.greyscale = grayscale;
		if (greyscale && indexed)
			throw new PngjException("palette and greyscale are mutually exclusive");
		this.channels = (grayscale || indexed) ? (alpha ? 2 : 1) : (alpha ? 4 : 3);
		// http://www.w3.org/TR/PNG/#11IHDR
		this.bitDepth = bitdepth;
		this.packed = bitdepth < 8;
		this.bitspPixel = (channels * this.bitDepth);
		this.bytesPixel = (bitspPixel + 7) / 8;
		this.bytesPerRow = (bitspPixel * cols + 7) / 8;
		this.samplesPerRow = channels * this.cols;
		this.samplesPerRowPacked = packed ? bytesPerRow : samplesPerRow;
		// several checks
		switch (this.bitDepth) {
		case 1:
		case 2:
		case 4:
			if (!(this.indexed || this.greyscale))
				throw new PngjException("only indexed or grayscale can have bitdepth=" + this.bitDepth);
			break;
		case 8:
			break;
		case 16:
			if (this.indexed)
				throw new PngjException("indexed can't have bitdepth=" + this.bitDepth);
			break;
		default:
			throw new PngjException("invalid bitdepth=" + this.bitDepth);
		}
		if (cols < 1 || cols > MAX_COLS_ROWS_VAL)
			throw new PngjException("invalid cols=" + cols + " ???");
		if (rows < 1 || rows > MAX_COLS_ROWS_VAL)
			throw new PngjException("invalid rows=" + rows + " ???");
	}

	@Override
	public String toString() {
		return "ImageInfo [cols=" + cols + ", rows=" + rows + ", bitDepth=" + bitDepth + ", channels=" + channels
				+ ", bitspPixel=" + bitspPixel + ", bytesPixel=" + bytesPixel + ", bytesPerRow=" + bytesPerRow
				+ ", samplesPerRow=" + samplesPerRow + ", samplesPerRowP=" + samplesPerRowPacked + ", alpha=" + alpha
				+ ", greyscale=" + greyscale + ", indexed=" + indexed + ", packed=" + packed + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (alpha ? 1231 : 1237);
		result = prime * result + bitDepth;
		result = prime * result + channels;
		result = prime * result + cols;
		result = prime * result + (greyscale ? 1231 : 1237);
		result = prime * result + (indexed ? 1231 : 1237);
		result = prime * result + rows;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ImageInfo other = (ImageInfo) obj;
		if (alpha != other.alpha)
			return false;
		if (bitDepth != other.bitDepth)
			return false;
		if (channels != other.channels)
			return false;
		if (cols != other.cols)
			return false;
		if (greyscale != other.greyscale)
			return false;
		if (indexed != other.indexed)
			return false;
		if (rows != other.rows)
			return false;
		return true;
	}

}