001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Jean-Marc Orliaguet, Chalmers 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.theme.presets; 023 024import java.awt.Color; 025import java.io.ByteArrayInputStream; 026import java.io.DataInputStream; 027import java.io.IOException; 028import java.util.LinkedHashMap; 029import java.util.Map; 030 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033 034public class PhotoshopPaletteParser extends PaletteParser { 035 036 private static final Log log = LogFactory.getLog(PhotoshopPaletteParser.class); 037 038 private static final int RGB = 0; 039 040 private static final int HSB = 1; 041 042 private static final int CMYK = 2; 043 044 private static final int LAB = 7; 045 046 private static final int GRAYSCALE = 8; 047 048 private static final int WIDE_CMYK = 9; 049 050 public static boolean checkSanity(byte[] bytes) { 051 return true; 052 } 053 054 public static Map<String, String> parse(byte[] bytes) { 055 Map<String, String> entries = new LinkedHashMap<String, String>(); 056 ByteArrayInputStream is = new ByteArrayInputStream(bytes); 057 DataInputStream dis = new DataInputStream(is); 058 059 char[] words = new char[bytes.length]; 060 int size = 0; 061 while (true) { 062 try { 063 words[size] = dis.readChar(); 064 size++; 065 } catch (IOException e) { 066 break; 067 } 068 } 069 070 try { 071 is.close(); 072 dis.close(); 073 } catch (IOException e) { 074 log.error(e, e); 075 } 076 077 int offset = 1; 078 int version = words[0] & 0xffff; 079 int nc = words[1] & 0xffff; 080 081 // get version 2 if it exists 082 if (version == 1 && size > nc * 5 + 2) { 083 offset += nc * 5 + 2; 084 version = words[offset - 1] & 0xffff; 085 nc = words[offset] & 0xffff; 086 } 087 088 if (version == 1) { 089 log.debug("Found ACO v1 color file (Photoshop < 7.0)"); 090 } else if (version == 2) { 091 log.debug("Found ACO v2 color file (Photoshop >= 7.0)"); 092 } else { 093 log.error("Unknown ACO file version: " + version); 094 return entries; 095 } 096 097 log.debug("Found " + nc + " colors."); 098 099 int counter = 1; 100 for (int j = 0; j < nc; j++) { 101 String value = null; 102 int colorSpace = words[offset + 1] & 0xff; 103 int w = words[offset + 2] & 0xffff; 104 int x = words[offset + 3] & 0xffff; 105 int y = words[offset + 4] & 0xffff; 106 int z = words[offset + 5] & 0xffff; 107 108 if (colorSpace == RGB) { 109 value = rgbToHex(w / 256, x / 256, y / 256); 110 111 } else if (colorSpace == HSB) { 112 float hue = w / 65535F; // [0.0-1.0] 113 float saturation = x / 65535F; // [0.0-1.0] 114 float brightness = y / 65535F; // [0.0-1.0] 115 Color color = Color.getHSBColor(hue, saturation, brightness); 116 value = rgbToHex(color.getRed(), color.getGreen(), color.getBlue()); 117 118 } else if (colorSpace == CMYK) { 119 float cyan = 1F - w / 65535F; // [0.0-1.0] 120 float magenta = 1F - x / 65535F; // [0.0-1.0] 121 float yellow = 1F - y / 65535F; // [0.0-1.0] 122 float black = 1F - z / 65535F; // [0.0-1.0] 123 // TODO: do the conversion to RGB. An ICC profile is required. 124 log.warn("Unsupported color space: CMYK"); 125 126 } else if (colorSpace == GRAYSCALE) { 127 int gray = (int) (w * 256F / 10000F); // [0-256] 128 value = rgbToHex(gray, gray, gray); 129 130 } else if (colorSpace == LAB) { 131 float l = w / 100F; 132 float a = x / 100F; 133 float b = y / 100F; 134 // TODO: do the conversion to RGB. An ICC profile is required. 135 log.warn("Unsupported color space: CIE Lab"); 136 137 } else if (colorSpace == WIDE_CMYK) { 138 float cyan = w / 10000F; // [0.0-1.0] 139 float magenta = x / 10000F; // [0.0-1.0] 140 float yellow = y / 10000F; // [0.0-1.0] 141 float black = z / 10000F; // [0.0-1.0] 142 // TODO: do the conversion to RGB. An ICC profile is required. 143 log.warn("Unsupported color space: Wide CMYK"); 144 145 } else { 146 log.warn("Unknown color space: " + colorSpace); 147 } 148 149 String name = ""; 150 if (version == 1) { 151 name = String.format("Color %s", counter); 152 } 153 154 else if (version == 2) { 155 int len = (words[offset + 7] & 0xffff) - 1; 156 name = String.copyValueOf(words, offset + 8, len); 157 offset += len + 3; 158 159 String n = name; 160 int c = 2; 161 while (entries.containsKey(n)) { 162 n = String.format("%s %s", name, c); 163 c++; 164 } 165 name = n; 166 } 167 168 if (value != null) { 169 entries.put(name, value); 170 } 171 172 offset += 5; 173 counter++; 174 } 175 176 return entries; 177 } 178 179}