diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/draw9patch/graphics/NinePatchedImage.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/draw9patch/graphics/NinePatchedImage.java | 882 |
1 files changed, 0 insertions, 882 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/draw9patch/graphics/NinePatchedImage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/draw9patch/graphics/NinePatchedImage.java deleted file mode 100644 index f1022c3a2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/draw9patch/graphics/NinePatchedImage.java +++ /dev/null @@ -1,882 +0,0 @@ -/* - * Copyright (C) 2013 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.ide.eclipse.adt.internal.editors.draw9patch.graphics; - -import static com.android.SdkConstants.DOT_9PNG; -import static com.android.SdkConstants.DOT_PNG; -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Rectangle; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * The model of 9-patched image. - */ -public class NinePatchedImage { - private static final boolean DEBUG = false; - - /** - * Get 9-patched filename as like image.9.png . - */ - public static String getNinePatchedFileName(String fileName) { - if (fileName.endsWith(DOT_9PNG)) { - return fileName; - } - return fileName.substring(0, fileName.lastIndexOf(DOT_PNG)) + DOT_9PNG; - } - - // For stretch regions and padding - public static final int BLACK_TICK = 0xFF000000; - // For Layout Bounds - public static final int RED_TICK = 0xFFFF0000; - // Blank - public static final int TRANSPARENT_TICK = 0x00000000; - - private ImageData mBaseImageData; - - private Image mBaseImage = null; - - private boolean mHasNinePatchExtension = false; - - private boolean mDirtyFlag = false; - - private int[] mHorizontalPatchPixels = null; - private int[] mVerticalPatchPixels = null; - - private int[] mHorizontalContentPixels = null; - private int[] mVerticalContentPixels = null; - - // for Prevent unexpected stretch in StretchsView - private boolean mRedTickOnlyInHorizontalFlag = false; - private boolean mRedTickOnlyInVerticalFlag = false; - - private final List<Tick> mHorizontalPatches = new ArrayList<Tick>(); - private final List<Tick> mVerticalPatches = new ArrayList<Tick>(); - - private final List<Tick> mHorizontalContents = new ArrayList<Tick>(); - private final List<Tick> mVerticalContents = new ArrayList<Tick>(); - - - private static final int CHUNK_BIN_SIZE = 100; - private final List<Chunk> mChunkBin = new ArrayList<Chunk>(CHUNK_BIN_SIZE); - - private int mHorizontalFixedPatchSum = 0; - private int mVerticalFixedPatchSum = 0; - - private static final int PROJECTION_BIN_SIZE = 100; - private final List<Projection> mProjectionBin = new ArrayList<Projection>(PROJECTION_BIN_SIZE); - - private Chunk[][] mPatchChunks = null; - - public ImageData getImageData() { - return mBaseImageData; - } - - public int getWidth() { - return mBaseImageData.width; - } - - public int getHeight() { - return mBaseImageData.height; - } - - public Image getImage() { - if (mBaseImage == null) { - mBaseImage = new Image(AdtPlugin.getDisplay(), mBaseImageData); - } - return mBaseImage; - } - - public boolean hasNinePatchExtension() { - return mHasNinePatchExtension; - } - - /** - * Get the image has/hasn't been edited flag. - * @return If has been edited, return true - */ - public boolean isDirty() { - return mDirtyFlag; - } - - /** - * Clear dirty(edited) flag. - */ - public void clearDirtyFlag() { - mDirtyFlag = false; - } - - public NinePatchedImage(String fileName) { - boolean hasNinePatchExtension = fileName.endsWith(DOT_9PNG); - ImageData data = new ImageData(fileName); - - initNinePatchedImage(data, hasNinePatchExtension); - } - - public NinePatchedImage(InputStream inputStream, String fileName) { - boolean hasNinePatchExtension = fileName.endsWith(DOT_9PNG); - ImageData data = new ImageData(inputStream); - - initNinePatchedImage(data, hasNinePatchExtension); - } - - private Chunk getChunk() { - if (mChunkBin.size() > 0) { - Chunk chunk = mChunkBin.remove(0); - chunk.init(); - return chunk; - } - return new Chunk(); - } - - private static final void recycleChunks(Chunk[][] patchChunks, List<Chunk> bin) { - int yLen = patchChunks.length; - int xLen = patchChunks[0].length; - - for (int y = 0; y < yLen; y++) { - for (int x = 0; x < xLen; x++) { - if (bin.size() < CHUNK_BIN_SIZE) { - bin.add(patchChunks[y][x]); - } - patchChunks[y][x] = null; - } - } - } - - private Projection getProjection() { - if (mProjectionBin.size() > 0) { - Projection projection = mProjectionBin.remove(0); - return projection; - } - return new Projection(); - } - - private static final void recycleProjections(Projection[][] projections, List<Projection> bin) { - int yLen = projections.length; - int xLen = 0; - if (yLen > 0) { - xLen = projections[0].length; - } - - for (int y = 0; y < yLen; y++) { - for (int x = 0; x < xLen; x++) { - if (bin.size() < CHUNK_BIN_SIZE) { - bin.add(projections[y][x]); - } - projections[y][x] = null; - } - } - } - - private static final int[] initArray(int[] array) { - int len = array.length; - for (int i = 0; i < len; i++) { - array[i] = TRANSPARENT_TICK; - } - return array; - } - - /** - * Get one pixel with alpha from the image. - * @return packed integer value as ARGB8888 - */ - private static final int getPixel(ImageData image, int x, int y) { - return (image.getAlpha(x, y) << 24) + image.getPixel(x, y); - } - - private static final boolean isTransparentPixel(ImageData image, int x, int y) { - return image.getAlpha(x, y) == 0x0; - } - - private static final boolean isValidTickColor(int pixel) { - return (pixel == BLACK_TICK || pixel == RED_TICK); - } - - private void initNinePatchedImage(ImageData imageData, boolean hasNinePatchExtension) { - mBaseImageData = imageData; - mHasNinePatchExtension = hasNinePatchExtension; - } - - private boolean ensurePixel(int x, int y, int[] pixels, int index) { - boolean isValid = true; - int pixel = getPixel(mBaseImageData, x, y); - if (!isTransparentPixel(mBaseImageData, x, y)) { - if (index == 0 || index == pixels.length - 1) { - isValid = false; - } - if (isValidTickColor(pixel)) { - pixels[index] = pixel; - } else { - isValid = false; - } - // clear pixel - mBaseImageData.setAlpha(x, y, 0x0); - } - return isValid; - } - - private boolean ensureHorizontalPixel(int x, int y, int[] pixels) { - return ensurePixel(x, y, pixels, x); - } - - private boolean ensureVerticalPixel(int x, int y, int[] pixels) { - return ensurePixel(x, y, pixels, y); - } - - /** - * Ensure that image data is 9-patch. - */ - public boolean ensure9Patch() { - boolean isValid = true; - - int width = mBaseImageData.width; - int height = mBaseImageData.height; - - createPatchArray(); - createContentArray(); - - // horizontal - for (int x = 0; x < width; x++) { - // top row - if (!ensureHorizontalPixel(x, 0, mHorizontalPatchPixels)) { - isValid = false; - } - // bottom row - if (!ensureHorizontalPixel(x, height - 1, mHorizontalContentPixels)) { - isValid = false; - } - } - // vertical - for (int y = 0; y < height; y++) { - // left column - if (!ensureVerticalPixel(0, y, mVerticalPatchPixels)) { - isValid = false; - } - // right column - if (!ensureVerticalPixel(width -1, y, mVerticalContentPixels)) { - isValid = false; - } - } - findPatches(); - findContentsArea(); - - return isValid; - } - - private void createPatchArray() { - mHorizontalPatchPixels = initArray(new int[mBaseImageData.width]); - mVerticalPatchPixels = initArray(new int[mBaseImageData.height]); - } - - private void createContentArray() { - mHorizontalContentPixels = initArray(new int[mBaseImageData.width]); - mVerticalContentPixels = initArray(new int[mBaseImageData.height]); - } - - /** - * Convert to 9-patch image. - * <p> - * This method doesn't consider that target image is already 9-patched or - * not. - * </p> - */ - public void convertToNinePatch() { - mBaseImageData = GraphicsUtilities.convertToNinePatch(mBaseImageData); - mHasNinePatchExtension = true; - - createPatchArray(); - createContentArray(); - - findPatches(); - findContentsArea(); - } - - public boolean isValid(int x, int y) { - return (x == 0) ^ (y == 0) - ^ (x == mBaseImageData.width - 1) ^ (y == mBaseImageData.height - 1); - } - - /** - * Set patch or content. - */ - public void setPatch(int x, int y, int color) { - if (isValid(x, y)) { - if (x == 0) { - mVerticalPatchPixels[y] = color; - } else if (y == 0) { - mHorizontalPatchPixels[x] = color; - } else if (x == mBaseImageData.width - 1) { - mVerticalContentPixels[y] = color; - } else if (y == mBaseImageData.height - 1) { - mHorizontalContentPixels[x] = color; - } - - // Mark as dirty - mDirtyFlag = true; - } - } - - /** - * Erase the pixel. - */ - public void erase(int x, int y) { - if (isValid(x, y)) { - int color = TRANSPARENT_TICK; - if (x == 0) { - mVerticalPatchPixels[y] = color; - } else if (y == 0) { - mHorizontalPatchPixels[x] = color; - } else if (x == mBaseImageData.width - 1) { - mVerticalContentPixels[y] = color; - } else if (y == mBaseImageData.height - 1) { - mHorizontalContentPixels[x] = color; - } - - // Mark as dirty - mDirtyFlag = true; - } - } - - public List<Tick> getHorizontalPatches() { - return mHorizontalPatches; - } - - public List<Tick> getVerticalPatches() { - return mVerticalPatches; - } - - /** - * Find patches from pixels array. - * @param pixels Target of seeking ticks. - * @param out Add the found ticks. - * @return If BlackTick is not found but only RedTick is found, returns true - */ - private static boolean findPatches(int[] pixels, List<Tick> out) { - boolean redTickOnly = true; - Tick patch = null; - int len = 0; - - // find patches - out.clear(); - len = pixels.length - 1; - for (int i = 1; i < len; i++) { - int pixel = pixels[i]; - - if (redTickOnly && pixel != TRANSPARENT_TICK && pixel != RED_TICK) { - redTickOnly = false; - } - - if (patch != null) { - if (patch.color != pixel) { - patch.end = i; - out.add(patch); - patch = null; - } - } - if (patch == null) { - patch = new Tick(pixel); - patch.start = i; - } - } - - if (patch != null) { - patch.end = len; - out.add(patch); - } - return redTickOnly; - } - - public void findPatches() { - - // find horizontal patches - mRedTickOnlyInHorizontalFlag = findPatches(mHorizontalPatchPixels, mHorizontalPatches); - - // find vertical patches - mRedTickOnlyInVerticalFlag = findPatches(mVerticalPatchPixels, mVerticalPatches); - } - - public Rectangle getContentArea() { - Tick horizontal = getContentArea(mHorizontalContents); - Tick vertical = getContentArea(mVerticalContents); - - Rectangle rect = new Rectangle(0, 0, 0, 0); - rect.x = 1; - rect.width = mBaseImageData.width - 1; - rect.y = 1; - rect.height = mBaseImageData.height - 1; - - if (horizontal != null) { - rect.x = horizontal.start; - rect.width = horizontal.getLength(); - } - if (vertical != null) { - rect.y = vertical.start; - rect.height = vertical.getLength(); - } - - return rect; - } - - private Tick getContentArea(List<Tick> list) { - int size = list.size(); - if (size == 0) { - return null; - } - if (size == 1) { - return list.get(0); - } - - Tick start = null; - Tick end = null; - - for (int i = 0; i < size; i++) { - Tick t = list.get(i); - if (t.color == BLACK_TICK) { - if (start == null) { - start = t; - end = t; - } else { - end = t; - } - } - } - - // red tick only - if (start == null) { - return null; - } - - Tick result = new Tick(start.color); - result.start = start.start; - result.end = end.end; - - return result; - } - - /** - * This is for unit test use only. - * @see com.android.ide.eclipse.adt.internal.editors.draw9patch.graphics.NinePatchedImageTest - */ - public List<Tick> getHorizontalContents() { - return mHorizontalContents; - } - - /** - * This is for unit test use only. - * @see com.android.ide.eclipse.adt.internal.editors.draw9patch.graphics.NinePatchedImageTest - */ - public List<Tick> getVerticalContents() { - return mVerticalContents; - } - - private static void findContentArea(int[] pixels, List<Tick> out) { - Tick contents = null; - int len = 0; - - // find horizontal contents area - out.clear(); - len = pixels.length - 1; - for (int x = 1; x < len; x++) { - if (contents != null) { - if (contents.color != pixels[x]) { - contents.end = x; - out.add(contents); - contents = null; - } - } - if (contents == null) { - contents = new Tick(pixels[x]); - contents.start = x; - } - } - - if (contents != null) { - contents.end = len; - out.add(contents); - } - } - - public void findContentsArea() { - - // find horizontal contents area - findContentArea(mHorizontalContentPixels, mHorizontalContents); - - // find vertical contents area - findContentArea(mVerticalContentPixels, mVerticalContents); - } - - /** - * Get raw image data. - * <p> - * The raw image data is applicable for save. - * </p> - */ - public ImageData getRawImageData() { - ImageData image = GraphicsUtilities.copy(mBaseImageData); - - final int width = image.width; - final int height = image.height; - int len = 0; - - len = mHorizontalPatchPixels.length; - for (int x = 0; x < len; x++) { - int pixel = mHorizontalPatchPixels[x]; - if (pixel != TRANSPARENT_TICK) { - image.setAlpha(x, 0, 0xFF); - image.setPixel(x, 0, pixel); - } - } - - len = mVerticalPatchPixels.length; - for (int y = 0; y < len; y++) { - int pixel = mVerticalPatchPixels[y]; - if (pixel != TRANSPARENT_TICK) { - image.setAlpha(0, y, 0xFF); - image.setPixel(0, y, pixel); - } - } - - len = mHorizontalContentPixels.length; - for (int x = 0; x < len; x++) { - int pixel = mHorizontalContentPixels[x]; - if (pixel != TRANSPARENT_TICK) { - image.setAlpha(x, height - 1, 0xFF); - image.setPixel(x, height - 1, pixel); - } - } - - len = mVerticalContentPixels.length; - for (int y = 0; y < len; y++) { - int pixel = mVerticalContentPixels[y]; - if (pixel != TRANSPARENT_TICK) { - image.setAlpha(width - 1, y, 0xFF); - image.setPixel(width - 1, y, pixel); - } - } - - return image; - } - - public Chunk[][] getChunks(Chunk[][] chunks) { - int lenY = mVerticalPatches.size(); - int lenX = mHorizontalPatches.size(); - - if (lenY == 0 || lenX == 0) { - return null; - } - - if (chunks == null) { - chunks = new Chunk[lenY][lenX]; - } else { - int y = chunks.length; - int x = chunks[0].length; - if (lenY != y || lenX != x) { - recycleChunks(chunks, mChunkBin); - chunks = new Chunk[lenY][lenX]; - } - } - - // for calculate weights - float horizontalPatchSum = 0; - float verticalPatchSum = 0; - - mVerticalFixedPatchSum = 0; - mHorizontalFixedPatchSum = 0; - - for (int y = 0; y < lenY; y++) { - Tick yTick = mVerticalPatches.get(y); - - for (int x = 0; x < lenX; x++) { - Tick xTick = mHorizontalPatches.get(x); - Chunk t = getChunk(); - chunks[y][x] = t; - - t.rect.x = xTick.start; - t.rect.width = xTick.getLength(); - t.rect.y = yTick.start; - t.rect.height = yTick.getLength(); - - if (mRedTickOnlyInHorizontalFlag - || xTick.color == BLACK_TICK || lenX == 1) { - t.type += Chunk.TYPE_HORIZONTAL; - if (y == 0) { - horizontalPatchSum += t.rect.width; - } - } - if (mRedTickOnlyInVerticalFlag - || yTick.color == BLACK_TICK || lenY == 1) { - t.type += Chunk.TYPE_VERTICAL; - if (x == 0) { - verticalPatchSum += t.rect.height; - } - } - - if ((t.type & Chunk.TYPE_HORIZONTAL) == 0 && lenX > 1 && y == 0) { - mHorizontalFixedPatchSum += t.rect.width; - } - if ((t.type & Chunk.TYPE_VERTICAL) == 0 && lenY > 1 && x == 0) { - mVerticalFixedPatchSum += t.rect.height; - } - - } - } - - // calc weights - for (int y = 0; y < lenY; y++) { - for (int x = 0; x < lenX; x++) { - Chunk chunk = chunks[y][x]; - if ((chunk.type & Chunk.TYPE_HORIZONTAL) != 0) { - chunk.horizontalWeight = chunk.rect.width / horizontalPatchSum; - } - if ((chunk.type & Chunk.TYPE_VERTICAL) != 0) { - chunk.verticalWeight = chunk.rect.height / verticalPatchSum; - - } - } - } - - return chunks; - } - - public Chunk[][] getCorruptedChunks(Chunk[][] chunks) { - chunks = getChunks(chunks); - - if (chunks != null) { - int yLen = chunks.length; - int xLen = chunks[0].length; - - for (int yPos = 0; yPos < yLen; yPos++) { - for (int xPos = 0; xPos < xLen; xPos++) { - Chunk c = chunks[yPos][xPos]; - Rectangle r = c.rect; - if ((c.type & Chunk.TYPE_HORIZONTAL) != 0 - && isHorizontalCorrupted(mBaseImageData, r)) { - c.type |= Chunk.TYPE_CORRUPT; - } - if ((c.type & Chunk.TYPE_VERTICAL) != 0 - && isVerticalCorrupted(mBaseImageData, r)) { - c.type |= Chunk.TYPE_CORRUPT; - } - } - } - } - return chunks; - } - - private static boolean isVerticalCorrupted(ImageData data, Rectangle r) { - int[] column = new int[r.width]; - int[] sample = new int[r.width]; - - GraphicsUtilities.getHorizontalPixels(data, r.x, r.y, r.width, column); - - int lenY = r.y + r.height; - for (int y = r.y; y < lenY; y++) { - GraphicsUtilities.getHorizontalPixels(data, r.x, y, r.width, sample); - if (!Arrays.equals(column, sample)) { - return true; - } - } - return false; - } - - private static boolean isHorizontalCorrupted(ImageData data, Rectangle r) { - int[] column = new int[r.height]; - int[] sample = new int[r.height]; - GraphicsUtilities.getVerticalPixels(data, r.x, r.y, r.height, column); - - int lenX = r.x + r.width; - for (int x = r.x; x < lenX; x++) { - GraphicsUtilities.getVerticalPixels(data, x, r.y, r.height, sample); - if (!Arrays.equals(column, sample)) { - return true; - } - } - return false; - } - - public Projection[][] getProjections(int width, int height, Projection[][] projections) { - mPatchChunks = getChunks(mPatchChunks); - if (mPatchChunks == null) { - return null; - } - - if (DEBUG) { - System.out.println(String.format("width:%d, height:%d", width, height)); - } - - int lenY = mPatchChunks.length; - int lenX = mPatchChunks[0].length; - - if (projections == null) { - projections = new Projection[lenY][lenX]; - } else { - int y = projections.length; - int x = projections[0].length; - if (lenY != y || lenX != x) { - recycleProjections(projections, mProjectionBin); - projections = new Projection[lenY][lenX]; - } - } - - float xZoom = ((float) width / mBaseImageData.width); - float yZoom = ((float) height / mBaseImageData.height); - - if (DEBUG) { - System.out.println(String.format("xZoom:%f, yZoom:%f", xZoom, yZoom)); - } - - int destX = 0; - int destY = 0; - int streatchableWidth = width - mHorizontalFixedPatchSum; - streatchableWidth = streatchableWidth > 0 ? streatchableWidth : 1; - - int streatchableHeight = height - mVerticalFixedPatchSum; - streatchableHeight = streatchableHeight > 0 ? streatchableHeight : 1; - - if (DEBUG) { - System.out.println(String.format("streatchable %d %d", streatchableWidth, - streatchableHeight)); - } - - for (int yPos = 0; yPos < lenY; yPos++) { - destX = 0; - Projection p = null; - for (int xPos = 0; xPos < lenX; xPos++) { - Chunk chunk = mPatchChunks[yPos][xPos]; - - if (DEBUG) { - System.out.println(String.format("Tile[%d, %d] = %s", - yPos, xPos, chunk.toString())); - } - - p = getProjection(); - projections[yPos][xPos] = p; - - p.chunk = chunk; - p.src = chunk.rect; - p.dest.x = destX; - p.dest.y = destY; - - // fixed size - p.dest.width = chunk.rect.width; - p.dest.height = chunk.rect.height; - - // horizontal stretch - if ((chunk.type & Chunk.TYPE_HORIZONTAL) != 0) { - p.dest.width = Math.round(streatchableWidth * chunk.horizontalWeight); - } - // vertical stretch - if ((chunk.type & Chunk.TYPE_VERTICAL) != 0) { - p.dest.height = Math.round(streatchableHeight * chunk.verticalWeight); - } - - destX += p.dest.width; - } - destY += p.dest.height; - } - return projections; - } - - /** - * Projection class for make relation between chunked image and resized image. - */ - public static class Projection { - public Chunk chunk = null; - public Rectangle src = null; - public final Rectangle dest = new Rectangle(0, 0, 0, 0); - - @Override - public String toString() { - return String.format("src[%d, %d, %d, %d] => dest[%d, %d, %d, %d]", - src.x, src.y, src.width, src.height, - dest.x, dest.y, dest.width, dest.height); - } - } - - public static class Chunk { - public static final int TYPE_FIXED = 0x0; - public static final int TYPE_HORIZONTAL = 0x1; - public static final int TYPE_VERTICAL = 0x2; - public static final int TYPE_CORRUPT = 0x80000000; - - public int type = TYPE_FIXED; - - public Rectangle rect = new Rectangle(0, 0, 0, 0); - - public float horizontalWeight = 0.0f; - public float verticalWeight = 0.0f; - - void init() { - type = Chunk.TYPE_FIXED; - horizontalWeight = 0.0f; - verticalWeight = 0.0f; - rect.x = 0; - rect.y = 0; - rect.width = 0; - rect.height = 0; - } - - private String typeToString() { - switch (type) { - case TYPE_FIXED: - return "FIXED"; - case TYPE_HORIZONTAL: - return "HORIZONTAL"; - case TYPE_VERTICAL: - return "VERTICAL"; - case TYPE_HORIZONTAL + TYPE_VERTICAL: - return "BOTH"; - default: - return "UNKNOWN"; - } - } - - @Override - public String toString() { - return String.format("%s %f/%f %s", typeToString(), horizontalWeight, verticalWeight, - rect.toString()); - } - } - - public static class Tick { - public int start; - public int end; - public int color; - - /** - * Get the tick length. - */ - public int getLength() { - return end - start; - } - - public Tick(int tickColor) { - color = tickColor; - } - - @Override - public String toString() { - return String.format("%d tick: %d to %d", color, start, end); - } - } -} |