~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/awt/image/ByteComponentRaster.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
 
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
4
 *
 
5
 * This code is free software; you can redistribute it and/or modify it
 
6
 * under the terms of the GNU General Public License version 2 only, as
 
7
 * published by the Free Software Foundation.  Oracle designates this
 
8
 * particular file as subject to the "Classpath" exception as provided
 
9
 * by Oracle in the LICENSE file that accompanied this code.
 
10
 *
 
11
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
14
 * version 2 for more details (a copy is included in the LICENSE file that
 
15
 * accompanied this code).
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License version
 
18
 * 2 along with this work; if not, write to the Free Software Foundation,
 
19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 *
 
21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
22
 * or visit www.oracle.com if you need additional information or have any
 
23
 * questions.
 
24
 */
 
25
 
 
26
package sun.awt.image;
 
27
import java.awt.image.Raster;
 
28
import java.awt.image.WritableRaster;
 
29
import java.awt.image.RasterFormatException;
 
30
import java.awt.image.SampleModel;
 
31
import java.awt.image.ComponentSampleModel;
 
32
import java.awt.image.SinglePixelPackedSampleModel;
 
33
import java.awt.image.DataBuffer;
 
34
import java.awt.image.DataBufferByte;
 
35
import java.awt.Rectangle;
 
36
import java.awt.Point;
 
37
 
 
38
/**
 
39
 * This class defines a Raster with pixels consisting of one or more 8-bit
 
40
 * data elements stored in close proximity to each other in a single byte
 
41
 * array.
 
42
 * The bit precision per data element is that
 
43
 * of the data type (that is, the bit precision for this Raster is 8).
 
44
 * There is only one pixel stride and one scanline stride for all
 
45
 * bands.  This type of Raster can be used with a
 
46
 * ComponentColorModel if there are multiple bands, or an
 
47
 * IndexColorModel if there is only one band.
 
48
 * <p>
 
49
 * For example, 3-3-2 RGB image data can be represented by a
 
50
 * ByteComponentRaster using a SinglePixelPackedSampleModel and
 
51
 * a ComponentColorModel.
 
52
 *
 
53
 */
 
54
public class ByteComponentRaster extends SunWritableRaster {
 
55
 
 
56
    /** private band offset for use by native code */
 
57
    protected int bandOffset;
 
58
 
 
59
    /** Data offsets for each band of image data. */
 
60
    protected int[]         dataOffsets;
 
61
 
 
62
    /** Scanline stride of the image data contained in this Raster. */
 
63
    protected int           scanlineStride;
 
64
 
 
65
    /** Pixel stride of the image data contained in this Raster. */
 
66
    protected int           pixelStride;
 
67
 
 
68
    /** The image data array. */
 
69
    protected byte[]        data;
 
70
 
 
71
    int type;
 
72
 
 
73
    /** A cached copy of minX + width for use in bounds checks. */
 
74
    private int maxX;
 
75
 
 
76
    /** A cached copy of minY + height for use in bounds checks. */
 
77
    private int maxY;
 
78
 
 
79
    /**
 
80
     * Constructs a ByteComponentRaster with the given SampleModel.
 
81
     * The Raster's upper left corner is origin and it is the same
 
82
     * size as the SampleModel.  A DataBuffer large enough to describe the
 
83
     * Raster is automatically created.  SampleModel must be of type
 
84
     * SinglePixelPackedSampleModel or ComponentSampleModel.
 
85
     * @param sampleModel     The SampleModel that specifies the layout.
 
86
     * @param origin          The Point that specified the origin.
 
87
     */
 
88
    public ByteComponentRaster(SampleModel sampleModel, Point origin) {
 
89
        this(sampleModel,
 
90
             sampleModel.createDataBuffer(),
 
91
             new Rectangle(origin.x,
 
92
                           origin.y,
 
93
                           sampleModel.getWidth(),
 
94
                           sampleModel.getHeight()),
 
95
             origin,
 
96
             null);
 
97
    }
 
98
 
 
99
    /**
 
100
     * Constructs a ByteComponentRaster with the given SampleModel
 
101
     * and DataBuffer.  The Raster's upper left corner is origin and
 
102
     * it is the same size as the SampleModel.  The DataBuffer is not
 
103
     * initialized and must be a DataBufferByte compatible with SampleModel.
 
104
     * SampleModel must be of type SinglePixelPackedSampleModel
 
105
     * or ComponentSampleModel.
 
106
     * @param sampleModel     The SampleModel that specifies the layout.
 
107
     * @param dataBuffer      The DataBufferShort that contains the image data.
 
108
     * @param origin          The Point that specifies the origin.
 
109
     */
 
110
    public ByteComponentRaster(SampleModel sampleModel,
 
111
                                  DataBuffer dataBuffer,
 
112
                                  Point origin) {
 
113
        this(sampleModel,
 
114
             dataBuffer,
 
115
             new Rectangle(origin.x,
 
116
                           origin.y,
 
117
                           sampleModel.getWidth(),
 
118
                           sampleModel.getHeight()),
 
119
             origin,
 
120
             null);
 
121
    }
 
122
 
 
123
    /**
 
124
     * Constructs a ByteComponentRaster with the given SampleModel,
 
125
     * DataBuffer, and parent.  DataBuffer must be a DataBufferByte and
 
126
     * SampleModel must be of type SinglePixelPackedSampleModel
 
127
     * or ComponentSampleModel.
 
128
     * When translated into the base Raster's
 
129
     * coordinate system, aRegion must be contained by the base Raster.
 
130
     * Origin is the coordinate in the new Raster's coordinate system of
 
131
     * the origin of the base Raster.  (The base Raster is the Raster's
 
132
     * ancestor which has no parent.)
 
133
     *
 
134
     * Note that this constructor should generally be called by other
 
135
     * constructors or create methods, it should not be used directly.
 
136
     * @param sampleModel     The SampleModel that specifies the layout.
 
137
     * @param dataBuffer      The DataBufferShort that contains the image data.
 
138
     * @param aRegion         The Rectangle that specifies the image area.
 
139
     * @param origin          The Point that specifies the origin.
 
140
     * @param parent          The parent (if any) of this raster.
 
141
     */
 
142
    public ByteComponentRaster(SampleModel sampleModel,
 
143
                                  DataBuffer dataBuffer,
 
144
                                  Rectangle aRegion,
 
145
                                  Point origin,
 
146
                                  ByteComponentRaster parent) {
 
147
        super(sampleModel, dataBuffer, aRegion, origin, parent);
 
148
        this.maxX = minX + width;
 
149
        this.maxY = minY + height;
 
150
 
 
151
        if (!(dataBuffer instanceof DataBufferByte)) {
 
152
            throw new RasterFormatException("ByteComponentRasters must have " +
 
153
                                            "byte DataBuffers");
 
154
        }
 
155
 
 
156
        DataBufferByte dbb = (DataBufferByte)dataBuffer;
 
157
        this.data = stealData(dbb, 0);
 
158
        if (dbb.getNumBanks() != 1) {
 
159
            throw new
 
160
                RasterFormatException("DataBuffer for ByteComponentRasters"+
 
161
                                      " must only have 1 bank.");
 
162
        }
 
163
        int dbOffset = dbb.getOffset();
 
164
 
 
165
        if (sampleModel instanceof ComponentSampleModel) {
 
166
            ComponentSampleModel ism = (ComponentSampleModel)sampleModel;
 
167
            this.type = IntegerComponentRaster.TYPE_BYTE_SAMPLES;
 
168
            this.scanlineStride = ism.getScanlineStride();
 
169
            this.pixelStride = ism.getPixelStride();
 
170
            this.dataOffsets = ism.getBandOffsets();
 
171
            int xOffset = aRegion.x - origin.x;
 
172
            int yOffset = aRegion.y - origin.y;
 
173
            for (int i = 0; i < getNumDataElements(); i++) {
 
174
                dataOffsets[i] += dbOffset +
 
175
                    xOffset*pixelStride+yOffset*scanlineStride;
 
176
            }
 
177
        } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
 
178
            SinglePixelPackedSampleModel sppsm =
 
179
                    (SinglePixelPackedSampleModel)sampleModel;
 
180
            this.type = IntegerComponentRaster.TYPE_BYTE_PACKED_SAMPLES;
 
181
            this.scanlineStride = sppsm.getScanlineStride();
 
182
            this.pixelStride    = 1;
 
183
            this.dataOffsets = new int[1];
 
184
            this.dataOffsets[0] = dbOffset;
 
185
            int xOffset = aRegion.x - origin.x;
 
186
            int yOffset = aRegion.y - origin.y;
 
187
            dataOffsets[0] += xOffset*pixelStride+yOffset*scanlineStride;
 
188
        } else {
 
189
            throw new RasterFormatException("IntegerComponentRasters must " +
 
190
                "have ComponentSampleModel or SinglePixelPackedSampleModel");
 
191
        }
 
192
        this.bandOffset = this.dataOffsets[0];
 
193
 
 
194
        verify(false);
 
195
    }
 
196
 
 
197
    /**
 
198
     * Returns a copy of the data offsets array. For each band the data offset
 
199
     * is the index into the band's data array, of the first sample of the
 
200
     * band.
 
201
     */
 
202
    public int[] getDataOffsets() {
 
203
        return (int[]) dataOffsets.clone();
 
204
    }
 
205
 
 
206
    /**
 
207
     * Returns the data offset for the specified band.  The data offset
 
208
     * is the index into the data array
 
209
     * in which the first sample of the first scanline is stored.
 
210
     * @param band  The band whose offset is returned.
 
211
     */
 
212
    public int getDataOffset(int band) {
 
213
        return dataOffsets[band];
 
214
    }
 
215
 
 
216
    /**
 
217
     * Returns the scanline stride -- the number of data array elements between
 
218
     * a given sample and the sample in the same column of the next row in the
 
219
     * same band.
 
220
     */
 
221
    public int getScanlineStride() {
 
222
        return scanlineStride;
 
223
    }
 
224
 
 
225
    /**
 
226
     * Returns pixel stride -- the number of data array elements between two
 
227
     * samples for the same band on the same scanline.
 
228
     */
 
229
    public int getPixelStride() {
 
230
        return pixelStride;
 
231
    }
 
232
 
 
233
    /**
 
234
     * Returns a reference to the data array.
 
235
     */
 
236
    public byte[] getDataStorage() {
 
237
        return data;
 
238
    }
 
239
 
 
240
    /**
 
241
     * Returns the data elements for all bands at the specified
 
242
     * location.
 
243
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
244
     * if the pixel coordinate is out of bounds.
 
245
     * A ClassCastException will be thrown if the input object is non null
 
246
     * and references anything other than an array of transferType.
 
247
     * @param x        The X coordinate of the pixel location.
 
248
     * @param y        The Y coordinate of the pixel location.
 
249
     * @param outData  An object reference to an array of type defined by
 
250
     *                 getTransferType() and length getNumDataElements().
 
251
     *                 If null an array of appropriate type and size will be
 
252
     *                 allocated.
 
253
     * @return         An object reference to an array of type defined by
 
254
     *                 getTransferType() with the request pixel data.
 
255
     */
 
256
    public Object getDataElements(int x, int y, Object obj) {
 
257
        if ((x < this.minX) || (y < this.minY) ||
 
258
            (x >= this.maxX) || (y >= this.maxY)) {
 
259
            throw new ArrayIndexOutOfBoundsException
 
260
                ("Coordinate out of bounds!");
 
261
        }
 
262
        byte outData[];
 
263
        if (obj == null) {
 
264
            outData = new byte[numDataElements];
 
265
        } else {
 
266
            outData = (byte[])obj;
 
267
        }
 
268
        int off = (y-minY)*scanlineStride +
 
269
                  (x-minX)*pixelStride;
 
270
 
 
271
        for (int band = 0; band < numDataElements; band++) {
 
272
            outData[band] = data[dataOffsets[band] + off];
 
273
        }
 
274
 
 
275
        return outData;
 
276
    }
 
277
 
 
278
    /**
 
279
     * Returns an array of data elements from the specified rectangular
 
280
     * region.
 
281
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
282
     * if the pixel coordinates are out of bounds.
 
283
     * A ClassCastException will be thrown if the input object is non null
 
284
     * and references anything other than an array of transferType.
 
285
     * <pre>
 
286
     *       byte[] bandData = (byte[])raster.getDataElements(x, y, w, h, null);
 
287
     *       int numDataElements = raster.getNumDataElements();
 
288
     *       byte[] pixel = new byte[numDataElements];
 
289
     *       // To find a data element at location (x2, y2)
 
290
     *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
 
291
     *                        pixel, 0, numDataElements);
 
292
     * </pre>
 
293
     * @param x        The X coordinate of the upper left pixel location.
 
294
     * @param y        The Y coordinate of the upper left pixel location.
 
295
     * @param width    Width of the pixel rectangle.
 
296
     * @param height   Height of the pixel rectangle.
 
297
     * @param outData  An object reference to an array of type defined by
 
298
     *                 getTransferType() and length w*h*getNumDataElements().
 
299
     *                 If null an array of appropriate type and size will be
 
300
     *                 allocated.
 
301
     * @return         An object reference to an array of type defined by
 
302
     *                 getTransferType() with the request pixel data.
 
303
     */
 
304
    public Object getDataElements(int x, int y, int w, int h, Object obj) {
 
305
        if ((x < this.minX) || (y < this.minY) ||
 
306
            (x + w > this.maxX) || (y + h > this.maxY)) {
 
307
            throw new ArrayIndexOutOfBoundsException
 
308
                ("Coordinate out of bounds!");
 
309
        }
 
310
        byte outData[];
 
311
        if (obj == null) {
 
312
            outData = new byte[w*h*numDataElements];
 
313
        } else {
 
314
            outData = (byte[])obj;
 
315
        }
 
316
 
 
317
        int yoff = (y-minY)*scanlineStride +
 
318
                   (x-minX)*pixelStride;
 
319
        int xoff;
 
320
        int off = 0;
 
321
        int xstart;
 
322
        int ystart;
 
323
 
 
324
        for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
325
            xoff = yoff;
 
326
            for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
327
                for (int c = 0; c < numDataElements; c++) {
 
328
                    outData[off++] = data[dataOffsets[c] + xoff];
 
329
                }
 
330
            }
 
331
        }
 
332
 
 
333
        return outData;
 
334
    }
 
335
 
 
336
    /**
 
337
     * Returns a byte array of data elements from the specified rectangular
 
338
     * region for the specified band.
 
339
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
340
     * if the pixel coordinates are out of bounds.
 
341
     * <pre>
 
342
     *       byte[] bandData = raster.getByteData(x, y, w, h, null);
 
343
     *       // To find the data element at location (x2, y2)
 
344
     *       byte bandElement = bandData[((y2-y)*w + (x2-x))];
 
345
     * </pre>
 
346
     * @param x        The X coordinate of the upper left pixel location.
 
347
     * @param y        The Y coordinate of the upper left pixel location.
 
348
     * @param width    Width of the pixel rectangle.
 
349
     * @param height   Height of the pixel rectangle.
 
350
     * @param band     The band to return.
 
351
     * @param outData  If non-null, data elements for all bands
 
352
     *                 at the specified location are returned in this array.
 
353
     * @return         Data array with data elements for all bands.
 
354
     */
 
355
    public byte[] getByteData(int x, int y, int w, int h,
 
356
                              int band, byte[] outData) {
 
357
        // Bounds check for 'band' will be performed automatically
 
358
        if ((x < this.minX) || (y < this.minY) ||
 
359
            (x + w > this.maxX) || (y + h > this.maxY)) {
 
360
            throw new ArrayIndexOutOfBoundsException
 
361
                ("Coordinate out of bounds!");
 
362
        }
 
363
        if (outData == null) {
 
364
            outData = new byte[scanlineStride*h];
 
365
        }
 
366
        int yoff = (y-minY)*scanlineStride +
 
367
                   (x-minX)*pixelStride + dataOffsets[band];
 
368
        int xoff;
 
369
        int off = 0;
 
370
        int xstart;
 
371
        int ystart;
 
372
 
 
373
        if (pixelStride == 1) {
 
374
            if (scanlineStride == w) {
 
375
                System.arraycopy(data, yoff, outData, 0, w*h);
 
376
            }
 
377
            else {
 
378
                for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
379
                    System.arraycopy(data, yoff, outData, off, w);
 
380
                    off += w;
 
381
                }
 
382
            }
 
383
        }
 
384
        else {
 
385
            for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
386
                xoff = yoff;
 
387
                for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
388
                    outData[off++] = data[xoff];
 
389
                }
 
390
            }
 
391
        }
 
392
 
 
393
        return outData;
 
394
    }
 
395
 
 
396
    /**
 
397
     * Returns a byte array of data elements from the specified rectangular
 
398
     * region.
 
399
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
400
     * if the pixel coordinates are out of bounds.
 
401
     * <pre>
 
402
     *       byte[] bandData = raster.getByteData(x, y, w, h, null);
 
403
     *       int numDataElements = raster.getnumDataElements();
 
404
     *       byte[] pixel = new byte[numDataElements];
 
405
     *       // To find a data element at location (x2, y2)
 
406
     *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
 
407
     *                        pixel, 0, numDataElements);
 
408
     * </pre>
 
409
     * @param x        The X coordinate of the upper left pixel location.
 
410
     * @param y        The Y coordinate of the upper left pixel location.
 
411
     * @param width    Width of the pixel rectangle.
 
412
     * @param height   Height of the pixel rectangle.
 
413
     * @param outData  If non-null, data elements for all bands
 
414
     *                 at the specified location are returned in this array.
 
415
     * @return         Data array with data elements for all bands.
 
416
     */
 
417
    public byte[] getByteData(int x, int y, int w, int h, byte[] outData) {
 
418
        if ((x < this.minX) || (y < this.minY) ||
 
419
            (x + w > this.maxX) || (y + h > this.maxY)) {
 
420
            throw new ArrayIndexOutOfBoundsException
 
421
                ("Coordinate out of bounds!");
 
422
        }
 
423
        if (outData == null) {
 
424
            outData = new byte[numDataElements*scanlineStride*h];
 
425
        }
 
426
        int yoff = (y-minY)*scanlineStride +
 
427
                   (x-minX)*pixelStride;
 
428
        int xoff;
 
429
        int off = 0;
 
430
        int xstart;
 
431
        int ystart;
 
432
 
 
433
        // REMIND: Should keep track if dataOffsets are in a nice order
 
434
        for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
435
            xoff = yoff;
 
436
            for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
437
                for (int c = 0; c < numDataElements; c++) {
 
438
                    outData[off++] = data[dataOffsets[c] + xoff];
 
439
                }
 
440
            }
 
441
        }
 
442
 
 
443
        return outData;
 
444
    }
 
445
 
 
446
    /**
 
447
     * Stores the data elements for all bands at the specified location.
 
448
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
449
     * if the pixel coordinate is out of bounds.
 
450
     * A ClassCastException will be thrown if the input object is non null
 
451
     * and references anything other than an array of transferType.
 
452
     * @param x        The X coordinate of the pixel location.
 
453
     * @param y        The Y coordinate of the pixel location.
 
454
     * @param inData   An object reference to an array of type defined by
 
455
     *                 getTransferType() and length getNumDataElements()
 
456
     *                 containing the pixel data to place at x,y.
 
457
     */
 
458
    public void setDataElements(int x, int y, Object obj) {
 
459
        if ((x < this.minX) || (y < this.minY) ||
 
460
            (x >= this.maxX) || (y >= this.maxY)) {
 
461
            throw new ArrayIndexOutOfBoundsException
 
462
                ("Coordinate out of bounds!");
 
463
        }
 
464
        byte inData[] = (byte[])obj;
 
465
        int off = (y-minY)*scanlineStride +
 
466
                  (x-minX)*pixelStride;
 
467
 
 
468
        for (int i = 0; i < numDataElements; i++) {
 
469
            data[dataOffsets[i] + off] = inData[i];
 
470
        }
 
471
 
 
472
        markDirty();
 
473
    }
 
474
 
 
475
    /**
 
476
     * Stores the Raster data at the specified location.
 
477
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
478
     * if the pixel coordinates are out of bounds.
 
479
     * @param x          The X coordinate of the pixel location.
 
480
     * @param y          The Y coordinate of the pixel location.
 
481
     * @param inRaster   Raster of data to place at x,y location.
 
482
     */
 
483
    public void setDataElements(int x, int y, Raster inRaster) {
 
484
        int dstOffX = inRaster.getMinX() + x;
 
485
        int dstOffY = inRaster.getMinY() + y;
 
486
        int width  = inRaster.getWidth();
 
487
        int height = inRaster.getHeight();
 
488
        if ((dstOffX < this.minX) || (dstOffY < this.minY) ||
 
489
            (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) {
 
490
            throw new ArrayIndexOutOfBoundsException
 
491
                ("Coordinate out of bounds!");
 
492
        }
 
493
 
 
494
        setDataElements(dstOffX, dstOffY, width, height, inRaster);
 
495
    }
 
496
 
 
497
    /**
 
498
     * Stores the Raster data at the specified location.
 
499
     * @param dstX The absolute X coordinate of the destination pixel
 
500
     * that will receive a copy of the upper-left pixel of the
 
501
     * inRaster
 
502
     * @param dstY The absolute Y coordinate of the destination pixel
 
503
     * that will receive a copy of the upper-left pixel of the
 
504
     * inRaster
 
505
     * @param width      The number of pixels to store horizontally
 
506
     * @param height     The number of pixels to store vertically
 
507
     * @param inRaster   Raster of data to place at x,y location.
 
508
     */
 
509
    private void setDataElements(int dstX, int dstY,
 
510
                                 int width, int height,
 
511
                                 Raster inRaster) {
 
512
        // Assume bounds checking has been performed previously
 
513
        if (width <= 0 || height <= 0) {
 
514
            return;
 
515
        }
 
516
 
 
517
        int srcOffX = inRaster.getMinX();
 
518
        int srcOffY = inRaster.getMinY();
 
519
        Object tdata = null;
 
520
 
 
521
        if (inRaster instanceof ByteComponentRaster) {
 
522
            ByteComponentRaster bct = (ByteComponentRaster) inRaster;
 
523
            byte[] bdata = bct.getDataStorage();
 
524
            // REMIND: Do something faster!
 
525
            if (numDataElements == 1) {
 
526
                int toff = bct.getDataOffset(0);
 
527
                int tss  = bct.getScanlineStride();
 
528
 
 
529
                int srcOffset = toff;
 
530
                int dstOffset = dataOffsets[0]+(dstY-minY)*scanlineStride+
 
531
                                               (dstX-minX);
 
532
 
 
533
 
 
534
                if (pixelStride == bct.getPixelStride()) {
 
535
                    width *= pixelStride;
 
536
                    for (int tmpY=0; tmpY < height; tmpY++) {
 
537
                        System.arraycopy(bdata, srcOffset,
 
538
                                         data, dstOffset, width);
 
539
                        srcOffset += tss;
 
540
                        dstOffset += scanlineStride;
 
541
                    }
 
542
                    markDirty();
 
543
                    return;
 
544
                }
 
545
            }
 
546
        }
 
547
 
 
548
        for (int startY=0; startY < height; startY++) {
 
549
            // Grab one scanline at a time
 
550
            tdata = inRaster.getDataElements(srcOffX, srcOffY+startY,
 
551
                                             width, 1, tdata);
 
552
            setDataElements(dstX, dstY+startY, width, 1, tdata);
 
553
        }
 
554
    }
 
555
 
 
556
    /**
 
557
     * Stores an array of data elements into the specified rectangular
 
558
     * region.
 
559
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
560
     * if the pixel coordinates are out of bounds.
 
561
     * A ClassCastException will be thrown if the input object is non null
 
562
     * and references anything other than an array of transferType.
 
563
     * The data elements in the
 
564
     * data array are assumed to be packed.  That is, a data element
 
565
     * for the nth band at location (x2, y2) would be found at:
 
566
     * <pre>
 
567
     *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
 
568
     * </pre>
 
569
     * @param x        The X coordinate of the upper left pixel location.
 
570
     * @param y        The Y coordinate of the upper left pixel location.
 
571
     * @param w        Width of the pixel rectangle.
 
572
     * @param h        Height of the pixel rectangle.
 
573
     * @param inData   An object reference to an array of type defined by
 
574
     *                 getTransferType() and length w*h*getNumDataElements()
 
575
     *                 containing the pixel data to place between x,y and
 
576
     *                 x+h, y+h.
 
577
     */
 
578
    public void setDataElements(int x, int y, int w, int h, Object obj) {
 
579
        if ((x < this.minX) || (y < this.minY) ||
 
580
            (x + w > this.maxX) || (y + h > this.maxY)) {
 
581
            throw new ArrayIndexOutOfBoundsException
 
582
                ("Coordinate out of bounds!");
 
583
        }
 
584
        byte inData[] = (byte[])obj;
 
585
        int yoff = (y-minY)*scanlineStride +
 
586
                   (x-minX)*pixelStride;
 
587
        int xoff;
 
588
        int off = 0;
 
589
        int xstart;
 
590
        int ystart;
 
591
 
 
592
        if (numDataElements == 1) {
 
593
            int srcOffset = 0;
 
594
            int dstOffset = yoff + dataOffsets[0];
 
595
            for (ystart=0; ystart < h; ystart++) {
 
596
                xoff = yoff;
 
597
                System.arraycopy(inData, srcOffset,
 
598
                                 data, dstOffset, w);
 
599
 
 
600
                srcOffset += w;
 
601
                dstOffset += scanlineStride;
 
602
            }
 
603
            markDirty();
 
604
            return;
 
605
        }
 
606
 
 
607
        for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
608
            xoff = yoff;
 
609
            for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
610
                for (int c = 0; c < numDataElements; c++) {
 
611
                    data[dataOffsets[c] + xoff] = inData[off++];
 
612
                }
 
613
            }
 
614
        }
 
615
 
 
616
        markDirty();
 
617
    }
 
618
 
 
619
    /**
 
620
     * Stores a byte array of data elements into the specified rectangular
 
621
     * region for the specified band.
 
622
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
623
     * if the pixel coordinates are out of bounds.
 
624
     * The data elements in the
 
625
     * data array are assumed to be packed.  That is, a data element
 
626
     * at location (x2, y2) would be found at:
 
627
     * <pre>
 
628
     *      inData[((y2-y)*w + (x2-x)) + n]
 
629
     * </pre>
 
630
     * @param x        The X coordinate of the upper left pixel location.
 
631
     * @param y        The Y coordinate of the upper left pixel location.
 
632
     * @param w        Width of the pixel rectangle.
 
633
     * @param h        Height of the pixel rectangle.
 
634
     * @param band     The band to set.
 
635
     * @param inData   The data elements to be stored.
 
636
     */
 
637
    public void putByteData(int x, int y, int w, int h,
 
638
                            int band, byte[] inData) {
 
639
        // Bounds check for 'band' will be performed automatically
 
640
        if ((x < this.minX) || (y < this.minY) ||
 
641
            (x + w > this.maxX) || (y + h > this.maxY)) {
 
642
            throw new ArrayIndexOutOfBoundsException
 
643
                ("Coordinate out of bounds!");
 
644
        }
 
645
        int yoff = (y-minY)*scanlineStride +
 
646
                   (x-minX)*pixelStride + dataOffsets[band];
 
647
        int xoff;
 
648
        int off = 0;
 
649
        int xstart;
 
650
        int ystart;
 
651
 
 
652
        if (pixelStride == 1) {
 
653
            if (scanlineStride == w) {
 
654
                System.arraycopy(inData, 0, data, yoff, w*h);
 
655
            }
 
656
            else {
 
657
                for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
658
                    System.arraycopy(inData, off, data, yoff, w);
 
659
                    off += w;
 
660
                }
 
661
            }
 
662
        }
 
663
        else {
 
664
            for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
665
                xoff = yoff;
 
666
                for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
667
                    data[xoff] = inData[off++];
 
668
                }
 
669
            }
 
670
        }
 
671
 
 
672
        markDirty();
 
673
    }
 
674
 
 
675
    /**
 
676
     * Stores a byte array of data elements into the specified rectangular
 
677
     * region.
 
678
     * An ArrayIndexOutOfBounds exception will be thrown at runtime
 
679
     * if the pixel coordinates are out of bounds.
 
680
     * The data elements in the
 
681
     * data array are assumed to be packed.  That is, a data element
 
682
     * for the nth band at location (x2, y2) would be found at:
 
683
     * <pre>
 
684
     *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
 
685
     * </pre>
 
686
     * @param x        The X coordinate of the upper left pixel location.
 
687
     * @param y        The Y coordinate of the upper left pixel location.
 
688
     * @param w        Width of the pixel rectangle.
 
689
     * @param h        Height of the pixel rectangle.
 
690
     * @param inData   The data elements to be stored.
 
691
     */
 
692
    public void putByteData(int x, int y, int w, int h, byte[] inData) {
 
693
        if ((x < this.minX) || (y < this.minY) ||
 
694
            (x + w > this.maxX) || (y + h > this.maxY)) {
 
695
            throw new ArrayIndexOutOfBoundsException
 
696
                ("Coordinate out of bounds!");
 
697
        }
 
698
        int yoff = (y-minY)*scanlineStride +
 
699
                   (x-minX)*pixelStride;
 
700
 
 
701
        int xoff;
 
702
        int off = 0;
 
703
        int xstart;
 
704
        int ystart;
 
705
 
 
706
        if (numDataElements == 1) {
 
707
            yoff += dataOffsets[0];
 
708
            if (pixelStride == 1) {
 
709
                if (scanlineStride == w) {
 
710
                    System.arraycopy(inData, 0, data, yoff, w*h);
 
711
                }
 
712
                else {
 
713
                    for (ystart=0; ystart < h; ystart++) {
 
714
                        System.arraycopy(inData, off, data, yoff, w);
 
715
                        off += w;
 
716
                        yoff += scanlineStride;
 
717
                    }
 
718
                }
 
719
            }
 
720
            else {
 
721
                for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
722
                    xoff = yoff;
 
723
                    for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
724
                        data[xoff] = inData[off++];
 
725
                    }
 
726
                }
 
727
            }
 
728
        }
 
729
        else {
 
730
            for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 
731
                xoff = yoff;
 
732
                for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 
733
                    for (int c = 0; c < numDataElements; c++) {
 
734
                        data[dataOffsets[c] + xoff] = inData[off++];
 
735
                    }
 
736
                }
 
737
            }
 
738
        }
 
739
 
 
740
        markDirty();
 
741
    }
 
742
 
 
743
    /**
 
744
     * Creates a subraster given a region of the raster.  The x and y
 
745
     * coordinates specify the horizontal and vertical offsets
 
746
     * from the upper-left corner of this raster to the upper-left corner
 
747
     * of the subraster.  A subset of the bands of the parent Raster may
 
748
     * be specified.  If this is null, then all the bands are present in the
 
749
     * subRaster. A translation to the subRaster may also be specified.
 
750
     * Note that the subraster will reference the same
 
751
     * DataBuffer as the parent raster, but using different offsets.
 
752
     * @param x               X offset.
 
753
     * @param y               Y offset.
 
754
     * @param width           Width (in pixels) of the subraster.
 
755
     * @param height          Height (in pixels) of the subraster.
 
756
     * @param x0              Translated X origin of the subraster.
 
757
     * @param y0              Translated Y origin of the subraster.
 
758
     * @param bandList        Array of band indices.
 
759
     * @exception RasterFormatException
 
760
     *            if the specified bounding box is outside of the parent raster.
 
761
     */
 
762
    public Raster createChild(int x, int y,
 
763
                              int width, int height,
 
764
                              int x0, int y0, int[] bandList) {
 
765
        WritableRaster newRaster = createWritableChild(x, y,
 
766
                                                       width, height,
 
767
                                                       x0, y0,
 
768
                                                       bandList);
 
769
        return (Raster) newRaster;
 
770
    }
 
771
 
 
772
    /**
 
773
     * Creates a Writable subRaster given a region of the Raster. The x and y
 
774
     * coordinates specify the horizontal and vertical offsets
 
775
     * from the upper-left corner of this Raster to the upper-left corner
 
776
     * of the subRaster.  A subset of the bands of the parent Raster may
 
777
     * be specified.  If this is null, then all the bands are present in the
 
778
     * subRaster. A translation to the subRaster may also be specified.
 
779
     * Note that the subRaster will reference the same
 
780
     * DataBuffer as the parent Raster, but using different offsets.
 
781
     * @param x               X offset.
 
782
     * @param y               Y offset.
 
783
     * @param width           Width (in pixels) of the subraster.
 
784
     * @param height          Height (in pixels) of the subraster.
 
785
     * @param x0              Translated X origin of the subraster.
 
786
     * @param y0              Translated Y origin of the subraster.
 
787
     * @param bandList        Array of band indices.
 
788
     * @exception RasterFormatException
 
789
     *            if the specified bounding box is outside of the parent Raster.
 
790
     */
 
791
    public WritableRaster createWritableChild(int x, int y,
 
792
                                              int width, int height,
 
793
                                              int x0, int y0,
 
794
                                              int[] bandList) {
 
795
        if (x < this.minX) {
 
796
            throw new RasterFormatException("x lies outside the raster");
 
797
        }
 
798
        if (y < this.minY) {
 
799
            throw new RasterFormatException("y lies outside the raster");
 
800
        }
 
801
        if ((x+width < x) || (x+width > this.minX + this.width)) {
 
802
            throw new RasterFormatException("(x + width) is outside of Raster");
 
803
        }
 
804
        if ((y+height < y) || (y+height > this.minY + this.height)) {
 
805
            throw new RasterFormatException("(y + height) is outside of Raster");
 
806
        }
 
807
 
 
808
        SampleModel sm;
 
809
 
 
810
        if (bandList != null)
 
811
            sm = sampleModel.createSubsetSampleModel(bandList);
 
812
        else
 
813
            sm = sampleModel;
 
814
 
 
815
        int deltaX = x0 - x;
 
816
        int deltaY = y0 - y;
 
817
 
 
818
        return new ByteComponentRaster(sm,
 
819
                                       dataBuffer,
 
820
                                       new Rectangle(x0, y0, width, height),
 
821
                                       new Point(sampleModelTranslateX+deltaX,
 
822
                                                 sampleModelTranslateY+deltaY),
 
823
                                       this);
 
824
    }
 
825
 
 
826
    /**
 
827
     * Creates a Raster with the same layout but using a different
 
828
     * width and height, and with new zeroed data arrays.
 
829
     */
 
830
    public WritableRaster createCompatibleWritableRaster(int w, int h) {
 
831
        if (w <= 0 || h <=0) {
 
832
            throw new RasterFormatException("negative "+
 
833
                                          ((w <= 0) ? "width" : "height"));
 
834
        }
 
835
 
 
836
        SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
 
837
 
 
838
        return new ByteComponentRaster(sm , new Point(0,0));
 
839
 
 
840
    }
 
841
 
 
842
    /**
 
843
     * Creates a Raster with the same layout and the same
 
844
     * width and height, and with new zeroed data arrays.  If
 
845
     * the Raster is a subRaster, this will call
 
846
     * createCompatibleRaster(width, height).
 
847
     */
 
848
    public WritableRaster createCompatibleWritableRaster() {
 
849
        return createCompatibleWritableRaster(width,height);
 
850
    }
 
851
 
 
852
    /**
 
853
     * Verify that the layout parameters are consistent with
 
854
     * the data.  If strictCheck
 
855
     * is false, this method will check for ArrayIndexOutOfBounds conditions.  If
 
856
     * strictCheck is true, this method will check for additional error
 
857
     * conditions such as line wraparound (width of a line greater than
 
858
     * the scanline stride).
 
859
     * @return   String   Error string, if the layout is incompatible with
 
860
     *                    the data.  Otherwise returns null.
 
861
     */
 
862
    private void verify (boolean strictCheck) {
 
863
        // Make sure data for Raster is in a legal range
 
864
        for (int i=0; i < dataOffsets.length; i++) {
 
865
            if (dataOffsets[i] < 0) {
 
866
                throw new RasterFormatException("Data offsets for band "+i+
 
867
                                                "("+dataOffsets[i]+
 
868
                                                ") must be >= 0");
 
869
            }
 
870
        }
 
871
 
 
872
        int maxSize = 0;
 
873
        int size;
 
874
 
 
875
        for (int i=0; i < numDataElements; i++) {
 
876
            size = (height-1)*scanlineStride + (width-1)*pixelStride +
 
877
                dataOffsets[i];
 
878
            if (size > maxSize) {
 
879
                maxSize = size;
 
880
            }
 
881
        }
 
882
        if (data.length < maxSize) {
 
883
            throw new RasterFormatException("Data array too small (should be "+
 
884
                                          maxSize+" )");
 
885
        }
 
886
    }
 
887
 
 
888
    public String toString() {
 
889
        return new String ("ByteComponentRaster: width = "+width+" height = "
 
890
                           + height
 
891
                           +" #numDataElements "+numDataElements
 
892
                           //  +" xOff = "+xOffset+" yOff = "+yOffset
 
893
                           +" dataOff[0] = "+dataOffsets[0]);
 
894
    }
 
895
 
 
896
//    /**
 
897
//     * For debugging...  prints a region of a one-band ByteComponentRaster
 
898
//     */
 
899
//    public void print(int x, int y, int w, int h) {
 
900
//        // REMIND:  Only works for 1 band!
 
901
//        System.out.println(this);
 
902
//        int offset = dataOffsets[0] + y*scanlineStride + x*pixelStride;
 
903
//        int off;
 
904
//        for (int yoff=0; yoff < h; yoff++, offset += scanlineStride) {
 
905
//            off = offset;
 
906
//            System.out.print("Line "+(y+yoff)+": ");
 
907
//            for (int xoff = 0; xoff < w; xoff++, off+= pixelStride) {
 
908
//                String s = Integer.toHexString(data[off]);
 
909
//                if (s.length() == 8) {
 
910
//                    s = s.substring(6,8);
 
911
//                }
 
912
//                System.out.print(s+" ");
 
913
//            }
 
914
//            System.out.println("");
 
915
//        }
 
916
//    }
 
917
 
 
918
 
 
919
}