Java BufferedImage to Shape imageToShape(BufferedImage image)

Here you can find the source of imageToShape(BufferedImage image)

Description

image To Shape

License

Open Source License

Declaration

public static Shape imageToShape(BufferedImage image) 

Method Source Code

//package com.java2s;
/*/*w  w  w.  j  a  v  a 2 s  .co  m*/
 *  Copyright (C) 2010-2016 JPEXS, All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.
 */

import java.awt.Polygon;

import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import java.util.ArrayList;

import java.util.BitSet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {
    private static final Map<BitSet, Area> shapeCache = new HashMap<>();

    public static Shape imageToShape(BufferedImage image) {
        Area area = new Area();
        int width = image.getWidth();
        int height = image.getHeight();

        int[] imgData;
        int type = image.getType();
        if (type == BufferedImage.TYPE_INT_ARGB_PRE
                || type == BufferedImage.TYPE_INT_RGB) {
            imgData = ((DataBufferInt) image.getRaster().getDataBuffer())
                    .getData();
        } else {
            imgData = image.getRGB(0, 0, width, height, null, 0, width);
        }

        BitSet bs = new BitSet(width * height);
        bs.set(type);
        int pixelCount = width * height;
        for (int i = 0; i < pixelCount; i++) {
            if ((imgData[i] >>> 24) > 0) {
                bs.set(i);
            }
        }

        if (shapeCache.containsKey(bs)) {
            return shapeCache.get(bs);
        }

        BitSet bsArea = new BitSet(width * height);
        boolean modified = true;

        List<Integer> leftCoordsX = new ArrayList<>();
        List<Integer> leftCoordsY = new ArrayList<>();
        List<Integer> rightCoordsX = new ArrayList<>();
        List<Integer> rightCoordsY = new ArrayList<>();
        while (modified) {
            modified = false;
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    int idx = width * y + x;
                    if ((imgData[idx] >>> 24) > 0 && !bsArea.get(idx)) {
                        leftCoordsX.clear();
                        leftCoordsY.clear();
                        rightCoordsX.clear();
                        rightCoordsY.clear();
                        int leftX = x;
                        int rightX = findRight(imgData, x, y, width);
                        leftCoordsX.add(leftX);
                        leftCoordsY.add(y);
                        rightCoordsX.add(rightX);
                        rightCoordsY.add(y);
                        setBitSet(bsArea, leftX, rightX, y, width);
                        int y2 = y + 1;
                        while (y2 < height) {
                            leftCoordsX.add(leftX);
                            leftCoordsY.add(y2);
                            rightCoordsX.add(rightX);
                            rightCoordsY.add(y2);

                            int leftX2 = findFirst(imgData, leftX, rightX,
                                    y2, width);
                            if (leftX2 == -1) {
                                break;
                            }

                            int rightX2 = findRight(imgData, leftX2, y2,
                                    width);

                            if (leftX2 != leftX) {
                                leftCoordsX.add(leftX2);
                                leftCoordsY.add(y2);
                            }

                            if (rightX2 != rightX) {
                                rightCoordsX.add(rightX2);
                                rightCoordsY.add(y2);
                            }

                            leftX = leftX2;
                            rightX = rightX2;

                            setBitSet(bsArea, leftX, rightX, y2, width);
                            y2++;
                        }

                        int cnt = leftCoordsX.size() + rightCoordsX.size();
                        int[] xCoords = new int[cnt];
                        int[] yCoords = new int[cnt];
                        for (int i = 0; i < rightCoordsX.size(); i++) {
                            xCoords[i] = rightCoordsX.get(i);
                            yCoords[i] = rightCoordsY.get(i);
                        }

                        int offset = rightCoordsX.size();
                        for (int i = 0; i < leftCoordsX.size(); i++) {
                            int idx2 = leftCoordsX.size() - i - 1;
                            xCoords[i + offset] = leftCoordsX.get(idx2);
                            yCoords[i + offset] = leftCoordsY.get(idx2);
                        }

                        Area area2 = new Area(new Polygon(xCoords, yCoords,
                                xCoords.length));
                        area.add(area2);
                        modified = true;
                    }
                }
            }
        }

        shapeCache.put(bs, area);
        return area;
    }

    private static int findRight(int[] imgData, int x, int y, int width) {
        int result = x;
        int idx = width * y + x;
        while (result < width && (imgData[idx] >>> 24) > 0) {
            result++;
            idx++;
        }

        return result;
    }

    private static void setBitSet(BitSet bitSet, int x1, int x2, int y,
            int width) {
        int idx = width * y + x1;
        int idx2 = width * y + x2;
        for (; idx < idx2; idx++) {
            bitSet.set(idx);
        }
    }

    private static int findFirst(int[] imgData, int x1, int x2, int y,
            int width) {
        int idx = width * y + x1;
        if ((imgData[idx] >>> 24) > 0) {
            while (x1 > 0 && (imgData[idx - 1] >>> 24) > 0) {
                x1--;
                idx--;
            }
            return x1;
        }

        int idx2 = width * y + x2;
        for (; idx < idx2; idx++) {
            if ((imgData[idx] >>> 24) > 0) {
                return x1;
            }

            x1++;
        }

        return -1;
    }
}

Related

  1. imageToShape(BufferedImage image)
  2. imageToShapeOld(BufferedImage image)