Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java
38918 views
1
/*
2
* Copyright (c) 2007, 2013, 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
package sun.java2d.cmm.lcms;
26
27
import java.awt.image.BufferedImage;
28
import java.awt.image.ComponentColorModel;
29
import java.awt.image.ComponentSampleModel;
30
import java.awt.image.DataBuffer;
31
import java.awt.image.ColorModel;
32
import java.awt.image.Raster;
33
import java.awt.image.SampleModel;
34
import sun.awt.image.ByteComponentRaster;
35
import sun.awt.image.ShortComponentRaster;
36
import sun.awt.image.IntegerComponentRaster;
37
38
class LCMSImageLayout {
39
40
public static int BYTES_SH(int x) {
41
return x;
42
}
43
44
public static int EXTRA_SH(int x) {
45
return x << 7;
46
}
47
48
public static int CHANNELS_SH(int x) {
49
return x << 3;
50
}
51
public static final int SWAPFIRST = 1 << 14;
52
public static final int DOSWAP = 1 << 10;
53
public static final int PT_RGB_8 =
54
CHANNELS_SH(3) | BYTES_SH(1);
55
public static final int PT_GRAY_8 =
56
CHANNELS_SH(1) | BYTES_SH(1);
57
public static final int PT_GRAY_16 =
58
CHANNELS_SH(1) | BYTES_SH(2);
59
public static final int PT_RGBA_8 =
60
EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
61
public static final int PT_ARGB_8 =
62
EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST;
63
public static final int PT_BGR_8 =
64
DOSWAP | CHANNELS_SH(3) | BYTES_SH(1);
65
public static final int PT_ABGR_8 =
66
DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
67
public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3)
68
| BYTES_SH(1) | DOSWAP | SWAPFIRST;
69
public static final int DT_BYTE = 0;
70
public static final int DT_SHORT = 1;
71
public static final int DT_INT = 2;
72
public static final int DT_DOUBLE = 3;
73
boolean isIntPacked = false;
74
int pixelType;
75
int dataType;
76
int width;
77
int height;
78
int nextRowOffset;
79
private int nextPixelOffset;
80
int offset;
81
82
/* This flag indicates whether the image can be processed
83
* at once by doTransfrom() native call. Otherwise, the
84
* image is processed scan by scan.
85
*/
86
private boolean imageAtOnce = false;
87
Object dataArray;
88
89
private int dataArrayLength; /* in bytes */
90
91
private LCMSImageLayout(int np, int pixelType, int pixelSize)
92
throws ImageLayoutException
93
{
94
this.pixelType = pixelType;
95
width = np;
96
height = 1;
97
nextPixelOffset = pixelSize;
98
nextRowOffset = safeMult(pixelSize, np);
99
offset = 0;
100
}
101
102
private LCMSImageLayout(int width, int height, int pixelType,
103
int pixelSize)
104
throws ImageLayoutException
105
{
106
this.pixelType = pixelType;
107
this.width = width;
108
this.height = height;
109
nextPixelOffset = pixelSize;
110
nextRowOffset = safeMult(pixelSize, width);
111
offset = 0;
112
}
113
114
115
public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize)
116
throws ImageLayoutException
117
{
118
this(np, pixelType, pixelSize);
119
dataType = DT_BYTE;
120
dataArray = data;
121
dataArrayLength = data.length;
122
123
verify();
124
}
125
126
public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize)
127
throws ImageLayoutException
128
{
129
this(np, pixelType, pixelSize);
130
dataType = DT_SHORT;
131
dataArray = data;
132
dataArrayLength = 2 * data.length;
133
134
verify();
135
}
136
137
public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize)
138
throws ImageLayoutException
139
{
140
this(np, pixelType, pixelSize);
141
dataType = DT_INT;
142
dataArray = data;
143
dataArrayLength = 4 * data.length;
144
145
verify();
146
}
147
148
public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
149
throws ImageLayoutException
150
{
151
this(np, pixelType, pixelSize);
152
dataType = DT_DOUBLE;
153
dataArray = data;
154
dataArrayLength = 8 * data.length;
155
156
verify();
157
}
158
159
private LCMSImageLayout() {
160
}
161
162
/* This method creates a layout object for given image.
163
* Returns null if the image is not supported by current implementation.
164
*/
165
public static LCMSImageLayout createImageLayout(BufferedImage image) throws ImageLayoutException {
166
LCMSImageLayout l = new LCMSImageLayout();
167
168
switch (image.getType()) {
169
case BufferedImage.TYPE_INT_RGB:
170
l.pixelType = PT_ARGB_8;
171
l.isIntPacked = true;
172
break;
173
case BufferedImage.TYPE_INT_ARGB:
174
l.pixelType = PT_ARGB_8;
175
l.isIntPacked = true;
176
break;
177
case BufferedImage.TYPE_INT_BGR:
178
l.pixelType = PT_ABGR_8;
179
l.isIntPacked = true;
180
break;
181
case BufferedImage.TYPE_3BYTE_BGR:
182
l.pixelType = PT_BGR_8;
183
break;
184
case BufferedImage.TYPE_4BYTE_ABGR:
185
l.pixelType = PT_ABGR_8;
186
break;
187
case BufferedImage.TYPE_BYTE_GRAY:
188
l.pixelType = PT_GRAY_8;
189
break;
190
case BufferedImage.TYPE_USHORT_GRAY:
191
l.pixelType = PT_GRAY_16;
192
break;
193
default:
194
/* ColorConvertOp creates component images as
195
* default destination, so this kind of images
196
* has to be supported.
197
*/
198
ColorModel cm = image.getColorModel();
199
if (cm instanceof ComponentColorModel) {
200
ComponentColorModel ccm = (ComponentColorModel) cm;
201
202
// verify whether the component size is fine
203
int[] cs = ccm.getComponentSize();
204
for (int s : cs) {
205
if (s != 8) {
206
return null;
207
}
208
}
209
210
return createImageLayout(image.getRaster());
211
212
}
213
return null;
214
}
215
216
l.width = image.getWidth();
217
l.height = image.getHeight();
218
219
switch (image.getType()) {
220
case BufferedImage.TYPE_INT_RGB:
221
case BufferedImage.TYPE_INT_ARGB:
222
case BufferedImage.TYPE_INT_BGR:
223
do {
224
IntegerComponentRaster intRaster = (IntegerComponentRaster)
225
image.getRaster();
226
l.nextRowOffset = safeMult(4, intRaster.getScanlineStride());
227
l.nextPixelOffset = safeMult(4, intRaster.getPixelStride());
228
l.offset = safeMult(4, intRaster.getDataOffset(0));
229
l.dataArray = intRaster.getDataStorage();
230
l.dataArrayLength = 4 * intRaster.getDataStorage().length;
231
l.dataType = DT_INT;
232
233
if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) {
234
l.imageAtOnce = true;
235
}
236
} while (false);
237
break;
238
239
case BufferedImage.TYPE_3BYTE_BGR:
240
case BufferedImage.TYPE_4BYTE_ABGR:
241
do {
242
ByteComponentRaster byteRaster = (ByteComponentRaster)
243
image.getRaster();
244
l.nextRowOffset = byteRaster.getScanlineStride();
245
l.nextPixelOffset = byteRaster.getPixelStride();
246
247
int firstBand = image.getSampleModel().getNumBands() - 1;
248
l.offset = byteRaster.getDataOffset(firstBand);
249
l.dataArray = byteRaster.getDataStorage();
250
l.dataArrayLength = byteRaster.getDataStorage().length;
251
l.dataType = DT_BYTE;
252
if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
253
l.imageAtOnce = true;
254
}
255
} while (false);
256
break;
257
258
case BufferedImage.TYPE_BYTE_GRAY:
259
do {
260
ByteComponentRaster byteRaster = (ByteComponentRaster)
261
image.getRaster();
262
l.nextRowOffset = byteRaster.getScanlineStride();
263
l.nextPixelOffset = byteRaster.getPixelStride();
264
265
l.dataArrayLength = byteRaster.getDataStorage().length;
266
l.offset = byteRaster.getDataOffset(0);
267
l.dataArray = byteRaster.getDataStorage();
268
l.dataType = DT_BYTE;
269
270
if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
271
l.imageAtOnce = true;
272
}
273
} while (false);
274
break;
275
276
case BufferedImage.TYPE_USHORT_GRAY:
277
do {
278
ShortComponentRaster shortRaster = (ShortComponentRaster)
279
image.getRaster();
280
l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride());
281
l.nextPixelOffset = safeMult(2, shortRaster.getPixelStride());
282
283
l.offset = safeMult(2, shortRaster.getDataOffset(0));
284
l.dataArray = shortRaster.getDataStorage();
285
l.dataArrayLength = 2 * shortRaster.getDataStorage().length;
286
l.dataType = DT_SHORT;
287
288
if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) {
289
l.imageAtOnce = true;
290
}
291
} while (false);
292
break;
293
default:
294
return null;
295
}
296
l.verify();
297
return l;
298
}
299
300
private static enum BandOrder {
301
DIRECT,
302
INVERTED,
303
ARBITRARY,
304
UNKNOWN;
305
306
public static BandOrder getBandOrder(int[] bandOffsets) {
307
BandOrder order = UNKNOWN;
308
309
int numBands = bandOffsets.length;
310
311
for (int i = 0; (order != ARBITRARY) && (i < bandOffsets.length); i++) {
312
switch (order) {
313
case UNKNOWN:
314
if (bandOffsets[i] == i) {
315
order = DIRECT;
316
} else if (bandOffsets[i] == (numBands - 1 - i)) {
317
order = INVERTED;
318
} else {
319
order = ARBITRARY;
320
}
321
break;
322
case DIRECT:
323
if (bandOffsets[i] != i) {
324
order = ARBITRARY;
325
}
326
break;
327
case INVERTED:
328
if (bandOffsets[i] != (numBands - 1 - i)) {
329
order = ARBITRARY;
330
}
331
break;
332
}
333
}
334
return order;
335
}
336
}
337
338
private void verify() throws ImageLayoutException {
339
340
if (offset < 0 || offset >= dataArrayLength) {
341
throw new ImageLayoutException("Invalid image layout");
342
}
343
344
if (nextPixelOffset != getBytesPerPixel(pixelType)) {
345
throw new ImageLayoutException("Invalid image layout");
346
}
347
348
int lastScanOffset = safeMult(nextRowOffset, (height - 1));
349
350
int lastPixelOffset = safeMult(nextPixelOffset, (width -1 ));
351
352
lastPixelOffset = safeAdd(lastPixelOffset, lastScanOffset);
353
354
int off = safeAdd(offset, lastPixelOffset);
355
356
if (off < 0 || off >= dataArrayLength) {
357
throw new ImageLayoutException("Invalid image layout");
358
}
359
}
360
361
static int safeAdd(int a, int b) throws ImageLayoutException {
362
long res = a;
363
res += b;
364
if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
365
throw new ImageLayoutException("Invalid image layout");
366
}
367
return (int)res;
368
}
369
370
static int safeMult(int a, int b) throws ImageLayoutException {
371
long res = a;
372
res *= b;
373
if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
374
throw new ImageLayoutException("Invalid image layout");
375
}
376
return (int)res;
377
}
378
379
public static class ImageLayoutException extends Exception {
380
public ImageLayoutException(String message) {
381
super(message);
382
}
383
}
384
public static LCMSImageLayout createImageLayout(Raster r) {
385
LCMSImageLayout l = new LCMSImageLayout();
386
if (r instanceof ByteComponentRaster &&
387
r.getSampleModel() instanceof ComponentSampleModel) {
388
ByteComponentRaster br = (ByteComponentRaster)r;
389
390
ComponentSampleModel csm = (ComponentSampleModel)r.getSampleModel();
391
392
l.pixelType = CHANNELS_SH(br.getNumBands()) | BYTES_SH(1);
393
394
int[] bandOffsets = csm.getBandOffsets();
395
BandOrder order = BandOrder.getBandOrder(bandOffsets);
396
397
int firstBand = 0;
398
switch (order) {
399
case INVERTED:
400
l.pixelType |= DOSWAP;
401
firstBand = csm.getNumBands() - 1;
402
break;
403
case DIRECT:
404
// do nothing
405
break;
406
default:
407
// unable to create the image layout;
408
return null;
409
}
410
411
l.nextRowOffset = br.getScanlineStride();
412
l.nextPixelOffset = br.getPixelStride();
413
414
l.offset = br.getDataOffset(firstBand);
415
l.dataArray = br.getDataStorage();
416
l.dataType = DT_BYTE;
417
418
l.width = br.getWidth();
419
l.height = br.getHeight();
420
421
if (l.nextRowOffset == l.width * br.getPixelStride()) {
422
l.imageAtOnce = true;
423
}
424
return l;
425
}
426
return null;
427
}
428
429
/**
430
* Derives number of bytes per pixel from the pixel format.
431
* Following bit fields are used here:
432
* [0..2] - bytes per sample
433
* [3..6] - number of color samples per pixel
434
* [7..9] - number of non-color samples per pixel
435
*
436
* A complete description of the pixel format can be found
437
* here: lcms2.h, lines 651 - 667.
438
*
439
* @param pixelType pixel format in lcms2 notation.
440
* @return number of bytes per pixel for given pixel format.
441
*/
442
private static int getBytesPerPixel(int pixelType) {
443
int bytesPerSample = (0x7 & pixelType);
444
int colorSamplesPerPixel = 0xF & (pixelType >> 3);
445
int extraSamplesPerPixel = 0x7 & (pixelType >> 7);
446
447
return bytesPerSample * (colorSamplesPerPixel + extraSamplesPerPixel);
448
}
449
}
450
451