1 /* 2 * Copyright (c) 2007, 2010, 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 /********************************************************************** 27 ********************************************************************** 28 ********************************************************************** 29 *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** 30 *** As an unpublished work pursuant to Title 17 of the United *** 31 *** States Code. All rights reserved. *** 32 ********************************************************************** 33 ********************************************************************** 34 **********************************************************************/ 35 36 package sun.java2d.cmm.lcms; 37 38 import java.awt.color.ICC_Profile; 39 import java.awt.color.ProfileDataException; 40 import java.awt.color.CMMException; 41 import java.awt.color.ColorSpace; 42 import java.awt.image.BufferedImage; 43 import java.awt.image.Raster; 44 import java.awt.image.WritableRaster; 45 import java.awt.image.ColorModel; 46 import java.awt.image.DirectColorModel; 47 import java.awt.image.ComponentColorModel; 48 import java.awt.image.SampleModel; 49 import java.awt.image.DataBuffer; 50 import java.awt.image.SinglePixelPackedSampleModel; 51 import java.awt.image.ComponentSampleModel; 52 import sun.java2d.cmm.*; 53 import sun.java2d.cmm.lcms.*; 54 55 56 public class LCMSTransform implements ColorTransform { 57 long ID; 58 private int inFormatter = 0; 59 private boolean isInIntPacked = false; 60 private int outFormatter = 0; 61 private boolean isOutIntPacked = false; 62 63 ICC_Profile[] profiles; 64 long [] profileIDs; 65 int renderType; 66 int transformType; 67 68 private int numInComponents = -1; 69 private int numOutComponents = -1; 70 71 private Object disposerReferent = new Object(); 72 73 /* the class initializer */ 74 static { 75 if (ProfileDeferralMgr.deferring) { 76 ProfileDeferralMgr.activateProfiles(); 77 } 78 } 79 80 public LCMSTransform(ICC_Profile profile, int renderType, 81 int transformType) 82 { 83 /* Actually, it is not a complete transform but just part of it */ 84 profiles = new ICC_Profile[1]; 85 profiles[0] = profile; 86 profileIDs = new long[1]; 87 profileIDs[0] = LCMS.getProfileID(profile); 88 this.renderType = (renderType == ColorTransform.Any)? 89 ICC_Profile.icPerceptual : renderType; 90 this.transformType = transformType; 91 92 /* Note that ICC_Profile.getNumComponents() is quite expensive 93 * (it may results in a reading of the profile header). 94 * So, here we cache the number of components of input and 95 * output profiles for further usage. 96 */ 97 numInComponents = profiles[0].getNumComponents(); 98 numOutComponents = profiles[profiles.length - 1].getNumComponents(); 99 } 100 101 public LCMSTransform (ColorTransform[] transforms) { 102 int size = 0; 103 for (int i=0; i < transforms.length; i++) { 104 size+=((LCMSTransform)transforms[i]).profiles.length; 105 } 106 profiles = new ICC_Profile[size]; 107 profileIDs = new long[size]; 108 int j = 0; 109 for (int i=0; i < transforms.length; i++) { 110 LCMSTransform curTrans = (LCMSTransform)transforms[i]; 111 System.arraycopy(curTrans.profiles, 0, profiles, j, 112 curTrans.profiles.length); 113 System.arraycopy(curTrans.profileIDs, 0, profileIDs, j, 114 curTrans.profileIDs.length); 115 j += curTrans.profiles.length; 116 } 117 renderType = ((LCMSTransform)transforms[0]).renderType; 118 119 /* Note that ICC_Profile.getNumComponents() is quite expensive 120 * (it may results in a reading of the profile header). 121 * So, here we cache the number of components of input and 122 * output profiles for further usage. 123 */ 124 numInComponents = profiles[0].getNumComponents(); 125 numOutComponents = profiles[profiles.length - 1].getNumComponents(); 126 } 127 128 public int getNumInComponents() { 129 return numInComponents; 130 } 131 132 public int getNumOutComponents() { 133 return numOutComponents; 134 } 135 136 private synchronized void doTransform(LCMSImageLayout in, 137 LCMSImageLayout out) { 138 // update native transfrom if needed 139 if (ID == 0L || 140 inFormatter != in.pixelType || isInIntPacked != in.isIntPacked || 141 outFormatter != out.pixelType || isOutIntPacked != out.isIntPacked) 142 { 143 144 if (ID != 0L) { 145 // Disposer will destroy forgotten transform 146 disposerReferent = new Object(); 147 } 148 inFormatter = in.pixelType; 149 isInIntPacked = in.isIntPacked; 150 151 outFormatter = out.pixelType; 152 isOutIntPacked = out.isIntPacked; 153 154 ID = LCMS.createNativeTransform(profileIDs, renderType, 155 inFormatter, isInIntPacked, 156 outFormatter, isOutIntPacked, 157 disposerReferent); 158 } 159 160 LCMS.colorConvert(this, in, out); 161 } 162 163 public void colorConvert(BufferedImage src, BufferedImage dst) { 164 LCMSImageLayout srcIL, dstIL; 165 166 if (!dst.getColorModel().hasAlpha()) { 167 dstIL = LCMSImageLayout.createImageLayout(dst); 168 169 if (dstIL != null) { 170 srcIL = LCMSImageLayout.createImageLayout(src); 171 if (srcIL != null) { 172 doTransform(srcIL, dstIL); 173 return; 174 } 175 } 176 } 177 178 Raster srcRas = src.getRaster(); 179 WritableRaster dstRas = dst.getRaster(); 180 ColorModel srcCM = src.getColorModel(); 181 ColorModel dstCM = dst.getColorModel(); 182 int w = src.getWidth(); 183 int h = src.getHeight(); 184 int srcNumComp = srcCM.getNumColorComponents(); 185 int dstNumComp = dstCM.getNumColorComponents(); 186 int precision = 8; 187 float maxNum = 255.0f; 188 for (int i = 0; i < srcNumComp; i++) { 189 if (srcCM.getComponentSize(i) > 8) { 190 precision = 16; 191 maxNum = 65535.0f; 192 } 193 } 194 for (int i = 0; i < dstNumComp; i++) { 195 if (dstCM.getComponentSize(i) > 8) { 196 precision = 16; 197 maxNum = 65535.0f; 198 } 199 } 200 float[] srcMinVal = new float[srcNumComp]; 201 float[] srcInvDiffMinMax = new float[srcNumComp]; 202 ColorSpace cs = srcCM.getColorSpace(); 203 for (int i = 0; i < srcNumComp; i++) { 204 srcMinVal[i] = cs.getMinValue(i); 205 srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]); 206 } 207 cs = dstCM.getColorSpace(); 208 float[] dstMinVal = new float[dstNumComp]; 209 float[] dstDiffMinMax = new float[dstNumComp]; 210 for (int i = 0; i < dstNumComp; i++) { 211 dstMinVal[i] = cs.getMinValue(i); 212 dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum; 213 } 214 boolean dstHasAlpha = dstCM.hasAlpha(); 215 boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha; 216 float[] dstColor; 217 if (dstHasAlpha) { 218 dstColor = new float[dstNumComp + 1]; 219 } else { 220 dstColor = new float[dstNumComp]; 221 } 222 if (precision == 8) { 223 byte[] srcLine = new byte[w * srcNumComp]; 224 byte[] dstLine = new byte[w * dstNumComp]; 225 Object pixel; 226 float[] color; 227 float[] alpha = null; 228 if (needSrcAlpha) { 229 alpha = new float[w]; 230 } 231 int idx; 232 // TODO check for src npixels = dst npixels 233 srcIL = new LCMSImageLayout( 234 srcLine, srcLine.length/getNumInComponents(), 235 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 236 LCMSImageLayout.BYTES_SH(1), getNumInComponents()); 237 dstIL = new LCMSImageLayout( 238 dstLine, dstLine.length/getNumOutComponents(), 239 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 240 LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); 241 // process each scanline 242 for (int y = 0; y < h; y++) { 243 // convert src scanline 244 pixel = null; 245 color = null; 246 idx = 0; 247 for (int x = 0; x < w; x++) { 248 pixel = srcRas.getDataElements(x, y, pixel); 249 color = srcCM.getNormalizedComponents(pixel, color, 0); 250 for (int i = 0; i < srcNumComp; i++) { 251 srcLine[idx++] = (byte) 252 ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + 253 0.5f); 254 } 255 if (needSrcAlpha) { 256 alpha[x] = color[srcNumComp]; 257 } 258 } 259 // color convert srcLine to dstLine 260 doTransform(srcIL, dstIL); 261 262 // convert dst scanline 263 pixel = null; 264 idx = 0; 265 for (int x = 0; x < w; x++) { 266 for (int i = 0; i < dstNumComp; i++) { 267 dstColor[i] = ((float) (dstLine[idx++] & 0xff)) * 268 dstDiffMinMax[i] + dstMinVal[i]; 269 } 270 if (needSrcAlpha) { 271 dstColor[dstNumComp] = alpha[x]; 272 } else if (dstHasAlpha) { 273 dstColor[dstNumComp] = 1.0f; 274 } 275 pixel = dstCM.getDataElements(dstColor, 0, pixel); 276 dstRas.setDataElements(x, y, pixel); 277 } 278 } 279 } else { 280 short[] srcLine = new short[w * srcNumComp]; 281 short[] dstLine = new short[w * dstNumComp]; 282 Object pixel; 283 float[] color; 284 float[] alpha = null; 285 if (needSrcAlpha) { 286 alpha = new float[w]; 287 } 288 int idx; 289 srcIL = new LCMSImageLayout( 290 srcLine, srcLine.length/getNumInComponents(), 291 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 292 LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); 293 294 dstIL = new LCMSImageLayout( 295 dstLine, dstLine.length/getNumOutComponents(), 296 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 297 LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); 298 299 // process each scanline 300 for (int y = 0; y < h; y++) { 301 // convert src scanline 302 pixel = null; 303 color = null; 304 idx = 0; 305 for (int x = 0; x < w; x++) { 306 pixel = srcRas.getDataElements(x, y, pixel); 307 color = srcCM.getNormalizedComponents(pixel, color, 0); 308 for (int i = 0; i < srcNumComp; i++) { 309 srcLine[idx++] = (short) 310 ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] + 311 0.5f); 312 } 313 if (needSrcAlpha) { 314 alpha[x] = color[srcNumComp]; 315 } 316 } 317 // color convert srcLine to dstLine 318 doTransform(srcIL, dstIL); 319 320 // convert dst scanline 321 pixel = null; 322 idx = 0; 323 for (int x = 0; x < w; x++) { 324 for (int i = 0; i < dstNumComp; i++) { 325 dstColor[i] = ((float) (dstLine[idx++] & 0xffff)) * 326 dstDiffMinMax[i] + dstMinVal[i]; 327 } 328 if (needSrcAlpha) { 329 dstColor[dstNumComp] = alpha[x]; 330 } else if (dstHasAlpha) { 331 dstColor[dstNumComp] = 1.0f; 332 } 333 pixel = dstCM.getDataElements(dstColor, 0, pixel); 334 dstRas.setDataElements(x, y, pixel); 335 } 336 } 337 } 338 } 339 340 public void colorConvert(Raster src, WritableRaster dst, 341 float[] srcMinVal, float[]srcMaxVal, 342 float[] dstMinVal, float[]dstMaxVal) { 343 LCMSImageLayout srcIL, dstIL; 344 345 // Can't pass src and dst directly to CMM, so process per scanline 346 SampleModel srcSM = src.getSampleModel(); 347 SampleModel dstSM = dst.getSampleModel(); 348 int srcTransferType = src.getTransferType(); 349 int dstTransferType = dst.getTransferType(); 350 boolean srcIsFloat, dstIsFloat; 351 if ((srcTransferType == DataBuffer.TYPE_FLOAT) || 352 (srcTransferType == DataBuffer.TYPE_DOUBLE)) { 353 srcIsFloat = true; 354 } else { 355 srcIsFloat = false; 356 } 357 if ((dstTransferType == DataBuffer.TYPE_FLOAT) || 358 (dstTransferType == DataBuffer.TYPE_DOUBLE)) { 359 dstIsFloat = true; 360 } else { 361 dstIsFloat = false; 362 } 363 int w = src.getWidth(); 364 int h = src.getHeight(); 365 int srcNumBands = src.getNumBands(); 366 int dstNumBands = dst.getNumBands(); 367 float[] srcScaleFactor = new float[srcNumBands]; 368 float[] dstScaleFactor = new float[dstNumBands]; 369 float[] srcUseMinVal = new float[srcNumBands]; 370 float[] dstUseMinVal = new float[dstNumBands]; 371 for (int i = 0; i < srcNumBands; i++) { 372 if (srcIsFloat) { 373 srcScaleFactor[i] = 65535.0f / (srcMaxVal[i] - srcMinVal[i]); 374 srcUseMinVal[i] = srcMinVal[i]; 375 } else { 376 if (srcTransferType == DataBuffer.TYPE_SHORT) { 377 srcScaleFactor[i] = 65535.0f / 32767.0f; 378 } else { 379 srcScaleFactor[i] = 65535.0f / 380 ((float) ((1 << srcSM.getSampleSize(i)) - 1)); 381 } 382 srcUseMinVal[i] = 0.0f; 383 } 384 } 385 for (int i = 0; i < dstNumBands; i++) { 386 if (dstIsFloat) { 387 dstScaleFactor[i] = (dstMaxVal[i] - dstMinVal[i]) / 65535.0f; 388 dstUseMinVal[i] = dstMinVal[i]; 389 } else { 390 if (dstTransferType == DataBuffer.TYPE_SHORT) { 391 dstScaleFactor[i] = 32767.0f / 65535.0f; 392 } else { 393 dstScaleFactor[i] = 394 ((float) ((1 << dstSM.getSampleSize(i)) - 1)) / 395 65535.0f; 396 } 397 dstUseMinVal[i] = 0.0f; 398 } 399 } 400 int ys = src.getMinY(); 401 int yd = dst.getMinY(); 402 int xs, xd; 403 float sample; 404 short[] srcLine = new short[w * srcNumBands]; 405 short[] dstLine = new short[w * dstNumBands]; 406 int idx; 407 srcIL = new LCMSImageLayout( 408 srcLine, srcLine.length/getNumInComponents(), 409 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 410 LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); 411 412 dstIL = new LCMSImageLayout( 413 dstLine, dstLine.length/getNumOutComponents(), 414 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 415 LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); 416 417 // process each scanline 418 for (int y = 0; y < h; y++, ys++, yd++) { 419 // get src scanline 420 xs = src.getMinX(); 421 idx = 0; 422 for (int x = 0; x < w; x++, xs++) { 423 for (int i = 0; i < srcNumBands; i++) { 424 sample = src.getSampleFloat(xs, ys, i); 425 srcLine[idx++] = (short) 426 ((sample - srcUseMinVal[i]) * srcScaleFactor[i] + 0.5f); 427 } 428 } 429 430 // color convert srcLine to dstLine 431 doTransform(srcIL, dstIL); 432 433 // store dst scanline 434 xd = dst.getMinX(); 435 idx = 0; 436 for (int x = 0; x < w; x++, xd++) { 437 for (int i = 0; i < dstNumBands; i++) { 438 sample = ((dstLine[idx++] & 0xffff) * dstScaleFactor[i]) + 439 dstUseMinVal[i]; 440 dst.setSample(xd, yd, i, sample); 441 } 442 } 443 } 444 } 445 446 public void colorConvert(Raster src, WritableRaster dst) { 447 448 LCMSImageLayout srcIL, dstIL; 449 dstIL = LCMSImageLayout.createImageLayout(dst); 450 if (dstIL != null) { 451 srcIL = LCMSImageLayout.createImageLayout(src); 452 if (srcIL != null) { 453 doTransform(srcIL, dstIL); 454 return; 455 } 456 } 457 // Can't pass src and dst directly to CMM, so process per scanline 458 SampleModel srcSM = src.getSampleModel(); 459 SampleModel dstSM = dst.getSampleModel(); 460 int srcTransferType = src.getTransferType(); 461 int dstTransferType = dst.getTransferType(); 462 int w = src.getWidth(); 463 int h = src.getHeight(); 464 int srcNumBands = src.getNumBands(); 465 int dstNumBands = dst.getNumBands(); 466 int precision = 8; 467 float maxNum = 255.0f; 468 for (int i = 0; i < srcNumBands; i++) { 469 if (srcSM.getSampleSize(i) > 8) { 470 precision = 16; 471 maxNum = 65535.0f; 472 } 473 } 474 for (int i = 0; i < dstNumBands; i++) { 475 if (dstSM.getSampleSize(i) > 8) { 476 precision = 16; 477 maxNum = 65535.0f; 478 } 479 } 480 float[] srcScaleFactor = new float[srcNumBands]; 481 float[] dstScaleFactor = new float[dstNumBands]; 482 for (int i = 0; i < srcNumBands; i++) { 483 if (srcTransferType == DataBuffer.TYPE_SHORT) { 484 srcScaleFactor[i] = maxNum / 32767.0f; 485 } else { 486 srcScaleFactor[i] = maxNum / 487 ((float) ((1 << srcSM.getSampleSize(i)) - 1)); 488 } 489 } 490 for (int i = 0; i < dstNumBands; i++) { 491 if (dstTransferType == DataBuffer.TYPE_SHORT) { 492 dstScaleFactor[i] = 32767.0f / maxNum; 493 } else { 494 dstScaleFactor[i] = 495 ((float) ((1 << dstSM.getSampleSize(i)) - 1)) / maxNum; 496 } 497 } 498 int ys = src.getMinY(); 499 int yd = dst.getMinY(); 500 int xs, xd; 501 int sample; 502 if (precision == 8) { 503 byte[] srcLine = new byte[w * srcNumBands]; 504 byte[] dstLine = new byte[w * dstNumBands]; 505 int idx; 506 // TODO check for src npixels = dst npixels 507 srcIL = new LCMSImageLayout( 508 srcLine, srcLine.length/getNumInComponents(), 509 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 510 LCMSImageLayout.BYTES_SH(1), getNumInComponents()); 511 dstIL = new LCMSImageLayout( 512 dstLine, dstLine.length/getNumOutComponents(), 513 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 514 LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); 515 516 // process each scanline 517 for (int y = 0; y < h; y++, ys++, yd++) { 518 // get src scanline 519 xs = src.getMinX(); 520 idx = 0; 521 for (int x = 0; x < w; x++, xs++) { 522 for (int i = 0; i < srcNumBands; i++) { 523 sample = src.getSample(xs, ys, i); 524 srcLine[idx++] = (byte) 525 ((sample * srcScaleFactor[i]) + 0.5f); 526 } 527 } 528 529 // color convert srcLine to dstLine 530 doTransform(srcIL, dstIL); 531 532 // store dst scanline 533 xd = dst.getMinX(); 534 idx = 0; 535 for (int x = 0; x < w; x++, xd++) { 536 for (int i = 0; i < dstNumBands; i++) { 537 sample = (int) (((dstLine[idx++] & 0xff) * 538 dstScaleFactor[i]) + 0.5f); 539 dst.setSample(xd, yd, i, sample); 540 } 541 } 542 } 543 } else { 544 short[] srcLine = new short[w * srcNumBands]; 545 short[] dstLine = new short[w * dstNumBands]; 546 int idx; 547 srcIL = new LCMSImageLayout( 548 srcLine, srcLine.length/getNumInComponents(), 549 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 550 LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); 551 552 dstIL = new LCMSImageLayout( 553 dstLine, dstLine.length/getNumOutComponents(), 554 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 555 LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); 556 557 // process each scanline 558 for (int y = 0; y < h; y++, ys++, yd++) { 559 // get src scanline 560 xs = src.getMinX(); 561 idx = 0; 562 for (int x = 0; x < w; x++, xs++) { 563 for (int i = 0; i < srcNumBands; i++) { 564 sample = src.getSample(xs, ys, i); 565 srcLine[idx++] = (short) 566 ((sample * srcScaleFactor[i]) + 0.5f); 567 } 568 } 569 570 // color convert srcLine to dstLine 571 doTransform(srcIL, dstIL); 572 573 // store dst scanline 574 xd = dst.getMinX(); 575 idx = 0; 576 for (int x = 0; x < w; x++, xd++) { 577 for (int i = 0; i < dstNumBands; i++) { 578 sample = (int) (((dstLine[idx++] & 0xffff) * 579 dstScaleFactor[i]) + 0.5f); 580 dst.setSample(xd, yd, i, sample); 581 } 582 } 583 } 584 } 585 } 586 587 /* convert an array of colors in short format */ 588 /* each color is a contiguous set of array elements */ 589 /* the number of colors is (size of the array) / (number of input/output 590 components */ 591 public short[] colorConvert(short[] src, short[] dst) { 592 593 if (dst == null) { 594 dst = new short [(src.length/getNumInComponents())*getNumOutComponents()]; 595 } 596 597 LCMSImageLayout srcIL = new LCMSImageLayout( 598 src, src.length/getNumInComponents(), 599 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 600 LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2); 601 602 LCMSImageLayout dstIL = new LCMSImageLayout( 603 dst, dst.length/getNumOutComponents(), 604 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 605 LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2); 606 607 doTransform(srcIL, dstIL); 608 609 return dst; 610 } 611 612 public byte[] colorConvert(byte[] src, byte[] dst) { 613 if (dst == null) { 614 dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()]; 615 } 616 617 LCMSImageLayout srcIL = new LCMSImageLayout( 618 src, src.length/getNumInComponents(), 619 LCMSImageLayout.CHANNELS_SH(getNumInComponents()) | 620 LCMSImageLayout.BYTES_SH(1), getNumInComponents()); 621 622 LCMSImageLayout dstIL = new LCMSImageLayout( 623 dst, dst.length/getNumOutComponents(), 624 LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) | 625 LCMSImageLayout.BYTES_SH(1), getNumOutComponents()); 626 627 doTransform(srcIL, dstIL); 628 629 return dst; 630 } 631 }