/* * Copyright (C) 2008 The Android Open Source Project * * Licensed 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 com.android.ninepatch; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; /** * Represents a 9-Patch bitmap. * * DO NOT CHANGE THIS API OR OLDER VERSIONS OF LAYOUTLIB WILL CRASH. * * This is a full representation of a NinePatch with both a {@link BufferedImage} and a * {@link NinePatchChunk}. * * Newer versions of the Layoutlib will use only the {@link NinePatchChunk} as the default * nine patch drawable references a normal Android bitmap which contains a BufferedImage * through a Bitmap_Delegate. * */ public class NinePatch { public static final String EXTENSION_9PATCH = ".9.png"; private BufferedImage mImage; private NinePatchChunk mChunk; public BufferedImage getImage() { return mImage; } public NinePatchChunk getChunk() { return mChunk; } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * Loads a 9 patch or regular bitmap. * @param fileUrl the URL of the file to load. * @param convert if <code>true</code>, non 9-patch bitmap will be converted into a 9 patch. * If <code>false</code> and the bitmap is not a 9 patch, the method will return * <code>null</code>. * @return a {@link NinePatch} or <code>null</code>. * @throws IOException */ public static NinePatch load(URL fileUrl, boolean convert) throws IOException { BufferedImage image = null; try { image = GraphicsUtilities.loadCompatibleImage(fileUrl); } catch (MalformedURLException e) { // really this shouldn't be happening since we're not creating the URL manually. return null; } boolean is9Patch = fileUrl.getPath().toLowerCase(Locale.US).endsWith(EXTENSION_9PATCH); return load(image, is9Patch, convert); } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * Loads a 9 patch or regular bitmap. * @param stream the {@link InputStream} of the file to load. * @param is9Patch whether the file represents a 9-patch * @param convert if <code>true</code>, non 9-patch bitmap will be converted into a 9 patch. * If <code>false</code> and the bitmap is not a 9 patch, the method will return * <code>null</code>. * @return a {@link NinePatch} or <code>null</code>. * @throws IOException */ public static NinePatch load(InputStream stream, boolean is9Patch, boolean convert) throws IOException { BufferedImage image = null; try { image = GraphicsUtilities.loadCompatibleImage(stream); } catch (MalformedURLException e) { // really this shouldn't be happening since we're not creating the URL manually. return null; } return load(image, is9Patch, convert); } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * Loads a 9 patch or regular bitmap. * @param image the source {@link BufferedImage}. * @param is9Patch whether the file represents a 9-patch * @param convert if <code>true</code>, non 9-patch bitmap will be converted into a 9 patch. * If <code>false</code> and the bitmap is not a 9 patch, the method will return * <code>null</code>. * @return a {@link NinePatch} or <code>null</code>. * @throws IOException */ public static NinePatch load(BufferedImage image, boolean is9Patch, boolean convert) { if (is9Patch == false) { if (convert) { image = convertTo9Patch(image); } else { return null; } } else { ensure9Patch(image); } return new NinePatch(image); } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * @return */ public int getWidth() { return mImage.getWidth(); } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * @return */ public int getHeight() { return mImage.getHeight(); } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * @param padding array of left, top, right, bottom padding * @return */ public boolean getPadding(int[] padding) { mChunk.getPadding(padding); return true; } /** * LEGACY METHOD to run older versions of Android Layoutlib. * ==== DO NOT CHANGE ==== * * @param graphics2D * @param x * @param y * @param scaledWidth * @param scaledHeight */ public void draw(Graphics2D graphics2D, int x, int y, int scaledWidth, int scaledHeight) { mChunk.draw(mImage, graphics2D, x, y, scaledWidth, scaledHeight, 0 , 0); } private NinePatch(BufferedImage image) { mChunk = NinePatchChunk.create(image); mImage = extractBitmapContent(image); } private static void ensure9Patch(BufferedImage image) { int width = image.getWidth(); int height = image.getHeight(); for (int i = 0; i < width; i++) { int pixel = image.getRGB(i, 0); if (pixel != 0 && pixel != 0xFF000000) { image.setRGB(i, 0, 0); } pixel = image.getRGB(i, height - 1); if (pixel != 0 && pixel != 0xFF000000) { image.setRGB(i, height - 1, 0); } } for (int i = 0; i < height; i++) { int pixel = image.getRGB(0, i); if (pixel != 0 && pixel != 0xFF000000) { image.setRGB(0, i, 0); } pixel = image.getRGB(width - 1, i); if (pixel != 0 && pixel != 0xFF000000) { image.setRGB(width - 1, i, 0); } } } private static BufferedImage convertTo9Patch(BufferedImage image) { BufferedImage buffer = GraphicsUtilities.createTranslucentCompatibleImage( image.getWidth() + 2, image.getHeight() + 2); Graphics2D g2 = buffer.createGraphics(); g2.drawImage(image, 1, 1, null); g2.dispose(); return buffer; } private BufferedImage extractBitmapContent(BufferedImage image) { return image.getSubimage(1, 1, image.getWidth() - 2, image.getHeight() - 2); } }