| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.ide.ergonomics.ant; |
| |
| import java.awt.image.BufferedImage; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Arrays; |
| import javax.imageio.ImageIO; |
| import org.apache.tools.ant.types.Resource; |
| |
| /** |
| * |
| * @author Jaroslav Tulach <jtulach@netbeans.org> |
| */ |
| final class IconResource extends Resource { |
| private Resource r; |
| private BufferedImage badgeIcon; |
| |
| public IconResource(Resource r, BufferedImage badgeIcon) { |
| super(r.getName(), r.isExists(), r.getLastModified(), r.isDirectory(), r.getSize()); |
| this.r = r; |
| this.badgeIcon = badgeIcon; |
| } |
| |
| @Override |
| public InputStream getInputStream() throws IOException { |
| if (getName().endsWith(".html")) { |
| return r.getInputStream(); |
| } |
| try { |
| InputStream is = r.getInputStream(); |
| BufferedImage img = ImageIO.read(is); |
| if (img == null) { |
| return r.getInputStream(); |
| } |
| BufferedImage merge = merge(img, badgeIcon); |
| ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| ImageIO.write(merge, "png", os); |
| return new ByteArrayInputStream(os.toByteArray()); |
| } catch (IOException ex) { |
| return r.getInputStream(); |
| } |
| } |
| |
| private static BufferedImage merge(BufferedImage main, BufferedImage badge) { |
| int w = Math.max(main.getWidth(), badge.getWidth()); |
| int h = Math.max(main.getHeight(), badge.getHeight()); |
| BufferedImage result = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); |
| for (int x = 0; x < w; x++) { |
| for (int y = 0; y < h; y++) { |
| int badgeColor = x < badge.getWidth() && y < badge.getHeight() ? badge.getRGB(x, y) : 0; |
| int mainColor = x < main.getWidth() && y < main.getHeight() ? main.getRGB(x, y) : 0; |
| int mergedColor = packARGB(overARGB(unpackARGB(badgeColor), unpackAGray(mainColor))); |
| result.setRGB(x, y, mergedColor); |
| } |
| } |
| // System.err.println("main:"); |
| // dump(main); |
| // System.err.println("badge:"); |
| // dump(badge); |
| // System.err.println("result:"); |
| // dump(result); |
| return result; |
| } |
| private static int[] unpackAGray(int c) { |
| int[] res = unpackARGB(c); |
| int gray = (res[1] * 30 + res[2] * 59 + res[3] * 11) / 100; |
| return new int[] {res[0], gray, gray, gray}; |
| } |
| private static int[] unpackARGB(int c) { |
| return new int[] {(c >> 24) & 0xFF, (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF}; |
| } |
| private static int packARGB(int[] c) { |
| return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; |
| } |
| /** @see <a href="http://en.wikipedia.org/wiki/Alpha_blending#Description">Alpha blending</a> */ |
| private static int[] overARGB(int[] a, int[] b) { |
| int[] r = new int[4]; |
| for (int c = 0; c < 4; c++) { |
| assert a[c] >= 0 && a[c] <= 255: a[c]; |
| assert b[c] >= 0 && b[c] <= 255: b[c]; |
| } |
| float alphaA = a[0] / 255.0f; |
| float alphaB = b[0] / 255.0f; |
| float alphaANeg = 1.0f - alphaA; |
| float alphaO = alphaA + alphaB * alphaANeg; |
| r[0] = (int) (alphaO * 255 + 0.5f); |
| for (int c = 1; c <= 3; c++) { |
| float cA = a[c] / 255.0f; |
| float cB = b[c] / 255.0f; |
| float cR = (cA * alphaA + cB * alphaB * alphaANeg) / alphaO; |
| r[c] = (int) (cR * 255 + 0.5f); |
| } |
| for (int c = 0; c < 4; c++) { |
| assert r[c] >= 0 && r[c] <= 255: r[c]; |
| } |
| // System.err.println("overARGB(" + show(a) + "," + show(b) + ")=" + show(r)); |
| return r; |
| } |
| // private static void dump(BufferedImage img) { |
| // for (int y = 0; y < img.getHeight(); y++) { |
| // for (int x = 0; x < img.getWidth(); x++) { |
| // System.err.format("%08X ", img.getRGB(x, y)); |
| // } |
| // System.err.println(); |
| // } |
| // } |
| static { |
| int[] argb = {0xAB, 0x12, 0xCD, 0x34}; |
| int p = packARGB(argb); |
| assert p == 0xAB12CD34 : p; |
| assert Arrays.equals(argb, unpackARGB(p)); |
| String s = show(argb); |
| assert s.equals("AB12CD34") : s; |
| int[] a = unpackARGB(0x0096989A); |
| int[] b = unpackARGB(0xFF50557D); |
| int[] r = overARGB(a, b); |
| assert packARGB(r) == 0xFF50557D : show(r); |
| } |
| private static String show(int[] argb) { |
| return String.format("%08X", packARGB(argb)); |
| } |
| |
| } |