File: MemoryByteChannelImage.java

package info (click to toggle)
java-imaging-utilities 0.14.2%2B3-4
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 2,304 kB
  • ctags: 3,737
  • sloc: java: 31,190; sh: 238; xml: 30; makefile: 19
file content (364 lines) | stat: -rw-r--r-- 9,302 bytes parent folder | download | duplicates (2)
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*
 * MemoryByteChannelImage
 *
 * Copyright (c) 2002, 2003 Marco Schmidt.
 * All rights reserved.
 */

package net.sourceforge.jiu.data;

/**
 * An implementation of {@link ByteChannelImage} that stores image channels as
 * <code>byte[]</code> arrays in memory.
 * An image can have an arbitrary number of channels.
 * <p>
 * This class is abstract because it is merely a data container.
 * It takes a subclass like {@link MemoryGray8Image} to give meaning to the values.
 *
 * @author Marco Schmidt
 */
public abstract class MemoryByteChannelImage implements ByteChannelImage
{
	private final byte[][] data;
	private final byte[] firstChannel; // == data[0]
	private final int numChannels; // == data.length
	private final int width;
	private final int height;
	private final int numPixels; // == width * height

	/**
	 * Create an image of byte channels.
	 * Image data will be completely in memory, so memory requirements are 
	 * <code>width * height * numChannels</code> bytes.
	 * Note that the data will not be initialized, so you should not assume
	 * anything about its content.
	 *
	 * @param numChannels the number of channels in this image, must be
	 *  non-zero and positive
	 * @param width the horizontal resolution, must be non-zero and positive
	 * @param height the vertical resolution, must be non-zero and positive
	 * @throws IllegalArgumentException if any of the parameters are invalid
	 *  or if width times height exceeds two GB
	 * @throws OutOfMemoryException if there is not enough free memory for
	 *  the specified resolution
	 */
	public MemoryByteChannelImage(int numChannels, int width, int height)
	{
		if (width < 1)
		{
			throw new IllegalArgumentException("Width must be larger than " +
				"0: " + width);
		}
		if (height < 1)
		{
			throw new IllegalArgumentException("Height must be larger than" +
				" 0: " + height);
		}
		if (numChannels < 1)
		{
			throw new IllegalArgumentException("Number of channels must be " +
				"larger than 0: " + numChannels);
		}
		this.width = width;
		this.height = height;
		this.numChannels = numChannels;
		numPixels = width * height;
		data = new byte[numChannels][];
		for (int i = 0; i < numChannels; i++)
		{
			data[i] = new byte[numPixels];
		}
		firstChannel = data[0];
	}

	/**
	 * Throws an exception if the arguments do not form a valid horizontal 
	 * sequence of samples.
	 * To be valid, all of the following requirements must be met:
	 */
	protected void checkPositionAndNumber(int channel, int x, int y, int w, int h)
	{
		if (channel < 0 || channel >= numChannels)
		{
			throw new IllegalArgumentException("Illegal channel index value: " + channel +
				". Must be from 0 to " + (numChannels - 1) + ".");
		}
		if (x < 0 || x >= getWidth())
		{
			throw new IllegalArgumentException("The value for x is invalid: " + x + ".");
		}
		if (w < 1)
		{
			throw new IllegalArgumentException("The value for w is invalid: " + w + ".");
		}
		if (x + w > getWidth())
		{
			throw new IllegalArgumentException("The values x + w exceed the " +
				"width of this image; x=" + x + ", w=" + w + ", width=" + 
				getWidth());
		}
		if (h < 1)
		{
			throw new IllegalArgumentException("The value for h is invalid: " + h + ".");
		}
		if (y < 0 || y >= getHeight())
		{
			throw new IllegalArgumentException("The value for y is invalid: " + y + ".");
		}
		if (y + h > getHeight())
		{
			throw new IllegalArgumentException("The values y + h exceed the " +
				"height of this image; y=" + y + ", h=" + h + ", height=" + 
				getHeight());
		}
	}

	public void clear(byte newValue)
	{
		clear(0, newValue);
	}

	public void clear(int channelIndex, byte newValue)
	{
		// check the validity of the channel index
		checkPositionAndNumber(channelIndex, 0, 0, 1, 1);
		// get the correct channel as byte[]
		final byte[] CHANNEL = data[channelIndex];
		// fill channel with the argument value
		final byte VALUE = (byte)newValue;
		final int LENGTH = CHANNEL.length;
		for (int i = 0; i < LENGTH; i++)
		{
			CHANNEL[i] = VALUE;
		}
	}

	public void clear(int newValue)
	{
		clear(0, (byte)newValue);
	}

	public void clear(int channelIndex, int newValue)
	{
		clear(channelIndex, (byte)newValue);
	}

	public abstract PixelImage createCompatibleImage(int width, int height);

	public PixelImage createCopy()
	{
		PixelImage copy = createCompatibleImage(getWidth(), getHeight());
		MemoryByteChannelImage result = (MemoryByteChannelImage)copy;
		for (int channelIndex = 0; channelIndex < getNumChannels(); channelIndex++)
		{
			System.arraycopy(data[channelIndex], 0, result.data[channelIndex], 0, data[channelIndex].length);
		}
		return result;
	}

	public long getAllocatedMemory()
	{
		long result = 0;
		if (data != null)
		{
			int channelIndex = 0;
			while (channelIndex < data.length)
			{
				byte[] array = data[channelIndex++];
				if (array != null)
				{
					result += array.length;
				}
			}
		}
		return result;
	}

	public int getBitsPerPixel()
	{
		return numChannels * 8;
	}

	public byte getByteSample(int channel, int x, int y)
	{
		/* advantage of the following approach: we don't check arguments 
		   before we access the data (too costly); instead, we have the VM 
		   throw an array index out of bounds exception and then determine 
		   which of the arguments was wrong;
		   that's better than checking before access all of the time => 
		   the VM checks anyway
		   we then throw a meaningful IllegalArgumentException (in 
		   checkPositionAndNumber)
		   disadvantage: some erroneous arguments aren't noticed, example:
		   width=100, height=20, x=100, y=0
		   will not result in an error (because only 0..99 are valid for x) 
		   but in the return of sample(0/1)
		   
		    */
		try
		{
			return data[channel][y * width + x];
		}
		catch (ArrayIndexOutOfBoundsException aioobe)
		{
			checkPositionAndNumber(channel, x, y, 1, 1);
			return -1;
		}
	}

	public byte getByteSample(int x, int y)
	{
		return getByteSample(0, x, y);
	}

	public void getByteSamples(int channel, int x, int y, int w, int h, byte[] dest, int destOffset)
	{
		checkPositionAndNumber(channel, x, y, w, h);
		byte[] src = data[channel];
		try
		{
			int srcOffset = y * width + x;
			while (h-- > 0)
			{
				java.lang.System.arraycopy(src, srcOffset, dest, destOffset, w);
				srcOffset += width;
				destOffset += w;
			}
		}
		catch (ArrayIndexOutOfBoundsException aioobe)
		{
		}
	}

	public final int getHeight()
	{
		return height;
	}

	public int getMaxSample(int channel)
	{
		return 255;
	}

	public int getNumChannels()
	{
		return numChannels;
	}

	public final int getSample(int x, int y)
	{
		try
		{
			return firstChannel[y * width + x] & 0xff;
		}
		catch (ArrayIndexOutOfBoundsException aioobe)
		{
			checkPositionAndNumber(0, x, y, 1, 1);
			return -1;
		}
	}

	public final int getSample(int channel, int x, int y)
	{
		try
		{
			return data[channel][y * width + x] & 0xff;
		}
		catch (ArrayIndexOutOfBoundsException aioobe)
		{
			checkPositionAndNumber(channel, x, y, 1, 1);
			return -1;
		}
	}

	public void getSamples(int channel, int x, int y, int w, int h, int[] dest, int destOffs)
	{
		if (w < 1 || h < 1)
		{
			return;
		}
		byte[] src = data[channel];
		int srcOffs = y * width + x;
		while (h-- != 0)
		{
			int loop = w;
			int from = srcOffs;
			while (loop-- != 0)
			{
				dest[destOffs++] = src[from++] & 0xff;
			}
			srcOffs += width;
		}
	}

	public final int getWidth()
	{
		return width;
	}

	public final void putByteSample(int channel, int x, int y, byte newValue)
	{
		checkPositionAndNumber(channel, x, y, 1, 1);
		try
		{
			data[channel][y * width + x] = newValue;
		}
		catch (ArrayIndexOutOfBoundsException aioobe)
		{
			checkPositionAndNumber(channel, x, y, 1, 1);
		}
	}

	public final void putByteSample(int x, int y, byte newValue)
	{
		checkPositionAndNumber(0, x, y, 1, 1);
		try
		{
			firstChannel[y * width + x] = newValue;
		}
		catch (ArrayIndexOutOfBoundsException aioobe)
		{
			checkPositionAndNumber(0, x, y, 1, 1);
		}
	}

	public void putByteSamples(int channel, int x, int y, int w, int h, byte[] src, int srcOffset)
	{
		checkPositionAndNumber(channel, x, y, w, h);
		byte[] dest = data[channel];
		int destOffset = y * width + x;
		while (h-- > 0)
		{
			java.lang.System.arraycopy(src, srcOffset, dest, destOffset, w);
			srcOffset += w;
			destOffset += width;
		}
	}

	public void putSamples(int channel, int x, int y, int w, int h, int[] src, int srcOffs)
	{
		checkPositionAndNumber(channel, x, y, w, h);
		byte[] dest = data[channel];
		int destOffs = y * width + x;
		while (h-- != 0)
		{
			int loop = w;
			int to = destOffs;
			while (loop-- != 0)
			{
				dest[to++] = (byte)src[srcOffs++];
			}
			destOffs += width;
		}
	}

	public final void putSample(int x, int y, int newValue)
	{
		putByteSample(0, x, y, (byte)newValue);
	}

	public final void putSample(int channel, int x, int y, int newValue)
	{
		putByteSample(channel, x, y, (byte)newValue);
	}
}