001 /* 002 * PCDYCbCrConversion 003 * 004 * Copyright (c) 2001, 2002 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.color.conversion; 009 010 import net.sourceforge.jiu.color.YCbCrIndex; 011 import net.sourceforge.jiu.data.RGBIndex; 012 013 /** 014 * Convert from YCbCr color space (as used in Kodak PCD files) to 015 * RGB. Only works for 24 bits per pixel (8 bits per channel) image 016 * data. 017 * 018 * @author Marco Schmidt 019 */ 020 public class PCDYCbCrConversion implements 021 RGBIndex, 022 YCbCrIndex 023 { 024 // color conversion coefficients (YCbCr to RGB) 025 private static final float c11 = 0.0054980f * 256; 026 private static final float c12 = 0.0000000f * 256; 027 private static final float c13 = 0.0051681f * 256; 028 private static final float c21 = 0.0054980f * 256; 029 private static final float c22 = -0.0015446f * 256; 030 private static final float c23 = -0.0026325f * 256; 031 private static final float c31 = 0.0054980f * 256; 032 private static final float c32 = 0.0079533f * 256; 033 private static final float c33 = 0.0000000f * 256; 034 035 private PCDYCbCrConversion() 036 { 037 } 038 039 private static byte floatToByte(float f) 040 { 041 if (f <= 0.0) 042 { 043 return 0; 044 } 045 if (f >= 255.0) 046 { 047 return (byte)255; 048 } 049 return (byte)((int)f); 050 } 051 052 /* 053 * Converts the color given by (y, cb, cr) to RGB color space. 054 * The three int variables y, cb and cr must be from the 055 * interval 0 to 255 (this is not checked). 056 * The rgb array will get the resulting RGB color, so it must 057 * have at least three entries. 058 * The three entries in that array will also be from 0 to 255 each. 059 * 060 public static void convertYCbCrToRgb(int y, int cb, int cr, int[] rgb) 061 { 062 int cr137 = cr - 137; 063 int cb156 = cb - 156; 064 rgb[INDEX_RED] = floatToInt(c11 * y + c12 * (cb156) + c13 * (cr137)); 065 rgb[INDEX_GREEN] = floatToInt(c21 * y + c22 * (cb156) + c23 * (cr137)); 066 rgb[INDEX_BLUE] = floatToInt(c31 * y + c32 * (cb156) + c33 * (cr137)); 067 } 068 069 public static int[] convertToRgb(byte[][] data, int width, int height) 070 throws IllegalArgumentException 071 { 072 if (width < 1 || height < 1) 073 { 074 throw new IllegalArgumentException("Error -- width and height must be larger " + 075 "than 0 (width=" + width + ", height=" + height); 076 } 077 if (data == null) 078 { 079 throw new IllegalArgumentException("Error -- data array must not be null."); 080 } 081 if (data.length < 3) 082 { 083 throw new IllegalArgumentException("Error -- data array must have at least " + 084 "three items (has " + data.length); 085 } 086 int numPixels = width * height; 087 int[] result = new int[numPixels]; 088 int[] rgb = new int[3]; 089 for (int i = 0; i < numPixels; i++) 090 { 091 int gray = data[INDEX_Y][i] & 0xff; 092 int cb = data[INDEX_CB][i] & 0xff; 093 int cr = data[INDEX_CR][i] & 0xff; 094 convertYCbCrToRgb(gray, cb, cr, rgb); 095 result[i] = 0xff000000 | rgb[0] << 16 | (rgb[1] << 8) | (rgb[2]); 096 } 097 return result; 098 }*/ 099 100 private static void checkArray(byte[] data, int offset, int num) throws IllegalArgumentException 101 { 102 if (data == null) 103 { 104 throw new IllegalArgumentException("Data array must be initialized."); 105 } 106 if (offset < 0 || offset + num > data.length) 107 { 108 throw new IllegalArgumentException("Invalid combination of " + 109 "offset, number and array length: offset=" + offset + 110 ", num=" + num + ", data.length=" + data.length); 111 } 112 } 113 114 /** 115 * Converts pixels from YCbCr to RGB color space. 116 * Input pixels are given as three byte arrays for luminance and the 117 * two chroma components. 118 * Same for output pixels, three other arrays for red, green and blue. 119 * Offset values can be specified separately for the YCbCr and the RGB 120 * arrays. 121 * @param y the array of gray source samples 122 * @param cb the array of chroma blue source samples 123 * @param cr the array of chroma red source samples 124 * @param yccOffset offset value into the arrays y, cb and cr; color 125 * conversion will be started at the yccOffset'th value of each array 126 * @param r the array of red destination samples 127 * @param g the array of green destination samples 128 * @param b the array of blue destination samples 129 * @param rgbOffset offset value into the arrays r, g and b; destination samples 130 * will be written to the three arrays starting at the rgbOffset'th value of each array 131 * @param num the number of pixels to be converted 132 * @throws IllegalArgumentException if one of the int values is negative or one 133 * of the arrays is null or too small 134 */ 135 public static void convertYccToRgb( 136 byte[] y, 137 byte[] cb, 138 byte[] cr, 139 int yccOffset, 140 byte[] r, 141 byte[] g, 142 byte[] b, 143 int rgbOffset, 144 int num) 145 throws IllegalArgumentException 146 { 147 if (num < 0) 148 { 149 throw new IllegalArgumentException("Negative number of pixels " + 150 "to be converted is invalid: " + num); 151 } 152 checkArray(y, yccOffset, num); 153 checkArray(cb, yccOffset, num); 154 checkArray(cr, yccOffset, num); 155 checkArray(r, rgbOffset, num); 156 checkArray(g, rgbOffset, num); 157 checkArray(b, rgbOffset, num); 158 while (num-- > 0) 159 { 160 int gray = y[yccOffset] & 0xff; 161 int chromaBlue = cb[yccOffset] & 0xff; 162 int chromaRed = cr[yccOffset++] & 0xff; 163 int cr137 = chromaRed - 137; 164 int cb156 = chromaBlue - 156; 165 r[rgbOffset] = floatToByte(c11 * gray + c12 * (cb156) + c13 * (cr137)); 166 g[rgbOffset] = floatToByte(c21 * gray + c22 * (cb156) + c23 * (cr137)); 167 b[rgbOffset++] = floatToByte(c31 * gray + c32 * (cb156) + c33 * (cr137)); 168 } 169 } 170 }