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