/* * @(#)Colors.java * * Copyright (c) 2005-2012 Werner Randelshofer, Goldau, Switzerland. * All rights reserved. * * You may not use, copy or modify this file, except in compliance with the * license agreement you entered into with Werner Randelshofer. * For details see accompanying license terms. */ package org.monte.media.image; import java.awt.*; import java.awt.image.*; import java.util.*; import static java.lang.Math.*; /** * Utility methods for ColorModels. * * @author Werner Randelshofer * @version $Id: ColorModels.java 299 2013-01-03 07:40:18Z werner $ */ public class ColorModels { /** * Prevent instance creation. */ private ColorModels() { } /** * Returns a descriptive string for the provided color model. */ public static String toString(ColorModel cm) { StringBuffer buf = new StringBuffer(); if (cm instanceof DirectColorModel) { DirectColorModel dcm = (DirectColorModel) cm; buf.append("Direct Color Model "); int[] masks = dcm.getMasks(); int totalBits = 0; MaskEntry[] entries = new MaskEntry[masks.length]; for (int i = 0; i < masks.length; i++) { switch (i) { case 0: entries[i] = new MaskEntry(masks[i], "R"); break; case 1: entries[i] = new MaskEntry(masks[i], "G"); break; case 2: entries[i] = new MaskEntry(masks[i], "B"); break; case 3: entries[i] = new MaskEntry(masks[i], "A"); break; } totalBits += entries[i].getBits(); } buf.append(totalBits); buf.append(" Bit "); Arrays.sort(entries); for (int i = 0; i < entries.length; i++) { buf.append(entries[i]); } } else if (cm instanceof IndexColorModel) { buf.append("Index Color Model "); IndexColorModel icm = (IndexColorModel) cm; int mapSize = icm.getMapSize(); buf.append(icm.getMapSize()); buf.append(" Colors"); } else { buf.append(cm.toString()); } switch (cm.getTransparency()) { case Transparency.OPAQUE: break; case Transparency.BITMASK: buf.append(" with Alpha Bitmask"); break; case Transparency.TRANSLUCENT: buf.append(" with Alpha Translucency"); break; } return buf.toString(); } private static class MaskEntry implements Comparable { private int mask; private int bits; private String name; public MaskEntry(int mask, String name) { this.mask = mask; this.name = name; for (int i = 0; i < 32; i++) { if (((mask >>> i) & 1) == 1) { bits++; } } } public int getBits() { return bits; } public String toString() { return name; } public int compareTo(Object o) { MaskEntry that = (MaskEntry) o; return that.mask - this.mask; } } /** RGB in the range [0,1] to YCC in the range Y=[0,1], Cb=[-0.5,0.5], * Cr=[-0.5,0.5] */ public static void RGBtoYCC(float[] rgb, float[] ycc) { float R = max(0f, min(1f, rgb[0])); float G = max(0f, min(1f, rgb[1])); float B = max(0f, min(1f, rgb[2])); float Y = 0.3f * R + 0.6f * G + 0.1f * B; float V = R - Y; float U = B - Y; float Cb = (U / 2f) /*+ 0.5f*/; float Cr = (V / 1.6f) /*+ 0.5f*/; ycc[0] = Y; ycc[1] = Cb; ycc[2] = Cr; } /** YCC in the range Y=[0,1], Cb=[-0.5,0.5], Cr=[-0.5,0.5] * to RGB in the range [0,1] */ public static void YCCtoRGB(float[] ycc, float[] rgb) { float Y = max(0f, min(1f, ycc[0])); float Cb = max(-0.5f, min(0.5f, ycc[1])); float Cr = max(-0.5f, min(0.5f, ycc[2])); float U = (Cb /*- 0.5f*/) * 2f; float V = (Cr /*- 0.5f*/) * 1.6f; float R = V + Y; float B = U + Y; float G = (Y - 0.3f * R - 0.1f * B) / 0.6f; rgb[0] = max(0f, min(1f, R)); rgb[1] = max(0f, min(1f, G)); rgb[2] = max(0f, min(1f, B)); } /** RGB 8-bit per channel to YCC 16-bit per channel. */ public static void RGBtoYCC(int[] rgb, int[] ycc) { int R = rgb[0]; int G = rgb[1]; int B = rgb[2]; int Y = 77 * R + 153 * G + 26 * B; int V = R * 256 - Y; int U = B * 256 - Y; int Cb = (U / 2) + 128 * 256; int Cr = (V * 5 / 8) + 128 * 256; ycc[0] = Y; ycc[1] = Cb; ycc[2] = Cr; } /** RGB 8-bit per channel to YCC 16-bit per channel. */ public static void RGBtoYCC(int rgb, int[] ycc) { int R = (rgb & 0xff0000) >>> 16; int G = (rgb & 0xff00) >>> 8; int B = rgb & 0xff; int Y = 77 * R + 153 * G + 26 * B; int V = R * 256 - Y; int U = B * 256 - Y; int Cb = (U / 2) + 128 * 256; int Cr = (V * 5 / 8) + 128 * 256; ycc[0] = Y; ycc[1] = Cb; ycc[2] = Cr; } /** RGB in the range [0,1] to YUV in the range Y=[0,1], U=[-0.5,0.5], * V=[-0.5,0.5] */ public static void RGBtoYUV(float[] rgb, float[] yuv) { float R = max(0f, min(1f, rgb[0])); float G = max(0f, min(1f, rgb[1])); float B = max(0f, min(1f, rgb[2])); float Y = 0.3f * R + 0.6f * G + 0.1f * B; yuv[0] = 0.299f * R + 0.587f * G + 0.114f * B; yuv[1] = -0.14713f * R - 0.28886f * G + 0.436f * B; yuv[2] = 0.615f * R - 0.51499f * G - 0.10001f * B; } /** YUV in the range Y=[0,1], U=[-0.5,0.5], V=[-0.5,0.5] * to RGB in the range [0,1] */ public static void YUVtoRGB(float[] yuv, float[] rgb) { float Y = max(0f, min(1f, yuv[0])); float U = max(-0.5f, min(0.5f, yuv[1])); float V = max(-0.5f, min(0.5f, yuv[2])); float R = 1 * Y + 0 * U + 1.13983f * V; float G = 1 * Y - 0.39465f * U - 0.58060f * V; float B = 1 * Y + 2.03211f * U + 0 * V; rgb[0]=min(1,max(0,R)); rgb[1]=min(1,max(0,G)); rgb[2]=min(1,max(0,B)); } /** YCC 16-bit per channel to RGB 8-bit per channel. */ public static void YCCtoRGB(int[] ycc, int[] rgb) { int Y = ycc[0]; int Cb = ycc[1]; int Cr = ycc[2]; int U = (Cb - 128 * 256) * 2; int V = (Cr - 128 * 256) * 8 / 5; int R = min(255, max(0, (V + Y) / 256)); int B = min(255, max(0, (U + Y) / 256)); int G = min(255, max(0, (Y - 77 * R - 26 * B) / 153)); rgb[0] = R; rgb[1] = G; rgb[2] = B; } /** YCC 16-bit per channel to RGB 8-bit per channel. */ public static int YCCtoRGB(int[] ycc) { int Y = ycc[0]; int Cb = ycc[1]; int Cr = ycc[2]; int U = (Cb - 128 * 256) * 2; int V = (Cr - 128 * 256) * 8 / 5; int R = min(255, max(0, (V + Y) / 256)); int B = min(255, max(0, (U + Y) / 256)); int G = min(255, max(0, (Y - 77 * R - 26 * B) / 153)); return R << 16 | G << 8 | B; } /** RGB in the range [0,1] to YIQ in the range Y in [0,1], * I in [-0.5957,0.5957], Q in [-0.5226,0.5226]. * <p> * http://en.wikipedia.org/wiki/YIQ */ public static void RGBtoYIQ(float[] rgb, float[] yiq) { float R = max(0f, min(1f, rgb[0])); float G = max(0f, min(1f, rgb[1])); float B = max(0f, min(1f, rgb[2])); float Y = 0.299f * R + 0.587f * G + 0.114f * B; float I = 0.595716f * R + -0.274453f * G + -0.321263f * B; float Q = 0.211456f * R + -0.522591f * G + 0.311135f * B; yiq[0] = Y; yiq[1] = I; yiq[2] = Q; } /** YIQ in the range Y in [0,1], I in [-0.5957,0.5957], Q in [-0.5226,0.5226] * to RGB in the range [0,1] * <p> * http://en.wikipedia.org/wiki/YIQ */ public static void YIQtoRGB(float[] yiq, float[] rgb) { float Y = max(0f, min(1f, yiq[0])); float I = max(-0.5957f, min(0.5957f, yiq[1])); float Q = max(-0.5226f, min(0.5226f, yiq[2])); float R = Y + 0.9563f * I + 0.6210f * Q; float G = Y + -0.2721f * I + -0.6474f * Q; float B = Y + -1.1070f * I + 1.7046f * Q; rgb[0] = max(0f, min(1f, R)); rgb[1] = max(0f, min(1f, G)); rgb[2] = max(0f, min(1f, B)); } }