Java 自动从png sprite工作表中查找帧大小

Java 自动从png sprite工作表中查找帧大小,java,image,image-processing,awt,sprite,Java,Image,Image Processing,Awt,Sprite,可能重复: 给定一个带有透明像素的.png图像和单个动画帧的网格(最后一行不需要满),如何自动查找每个帧的尺寸,并检测.png中有多少帧 我正试图将知识共享宝库中的资源转换为我们的内部格式,但我在将框架信息与原始的.png分离时遇到了问题 (由Glitch根据许可证发布) 在这种情况下,我可以发现帧是189x230像素;但是查找这个需要时间,而且有很多图像可能需要查找 我想将图像分割成框架,以便在JavaSwing桌面应用程序中使用。我可以使用ImageIO将图像加载到buffereImag

可能重复:

给定一个带有透明像素的.png图像和单个动画帧的网格(最后一行不需要满),如何自动查找每个帧的尺寸,并检测.png中有多少帧

我正试图将知识共享宝库中的资源转换为我们的内部格式,但我在将框架信息与原始的.png分离时遇到了问题

(由Glitch根据许可证发布)

在这种情况下,我可以发现帧是189x230像素;但是查找这个需要时间,而且有很多图像可能需要查找

我想将图像分割成框架,以便在JavaSwing桌面应用程序中使用。我可以使用
ImageIO
将图像加载到
buffereImage
中,并轻松检查像素透明度。只有几个可能的帧尺寸:给定示例中的945x690帧,并假设最小边为50px,唯一合理的帧宽度为5 x 189(正确)、7 x 135或9 x 105

那么,您如何找到框架尺寸?这不需要非常高效,因为资源转换是一次性的问题。伪代码答案很好;我对算法最感兴趣


注意:说明如何处理非动画精灵图纸,图纸中的图像大小不规则。我感兴趣的是检测行x列,这可以用一个简单得多的算法来解决(请参见接受的答案)。

因为所有图像都是由单一颜色构成的,所以您可以在较大的图像中的列和行中查找“边框颜色”条

使用获得的与图像大小(宽度x高度)相关的列数和行数来确定每个子图像的像素大小

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.net.*;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;

class TileSetUtility {

    /** Divide the tile into tiles based on the number of cols & rows 
     * supplied.  Exclude any images that are a solid color. */
    public static ArrayList<BufferedImage> getTiles(
            BufferedImage tile, int cols, int rows) {
        int w = tile.getWidth();
        int h = tile.getHeight();
        int wT = w / cols;
        int hT = h / rows;
        if (wT * cols != w || hT * rows != h) {
            throw new IllegalArgumentException("Tile is not an even " +
                    "multiple of pixels of WxCols or HxRows!");
        }
        ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
        for (int x = 0; x < cols; x++) {
            for (int y = 0; y < rows; y++) {
                BufferedImage i = tile.getSubimage(x * wT, y * hT, wT, hT);
                if (!isImageSolidColor(i)) {
                    tiles.add(i);
                }
            }
        }
        return tiles;
    }

    /** Takes an image that represents tiles of a tile set, and infers the 
     * number of columns based on the assumption that the color at 0x0 in the 
     * image represents a border color or frame for the contained tiles. */
    public static int inferNumberColumns(BufferedImage img) {
        boolean[] columnClear = new boolean[img.getWidth()];
        // after this loop, we should have a series of contiguous regions
        // of 'true' in the array.
        for (int ii = 0; ii < columnClear.length; ii++) {
            columnClear[ii] = isLineEmpty(img, ii, false);
        }
        return countContiguousRegions(columnClear);
    }

    /** Takes an image that represents tiles of a tile set, and infers the 
     * number of rows based on the assumption that the color at 0x0 in the 
     * image represents a border color or frame for the contained tiles. */
    public static int inferNumberRows(BufferedImage img) {
        boolean[] columnClear = new boolean[img.getHeight()];
        // after this loop, we should have a series of contiguous regions
        // of 'true' in the array.
        for (int ii = 0; ii < columnClear.length; ii++) {
            columnClear[ii] = isLineEmpty(img, ii, true);
        }
        return countContiguousRegions(columnClear);
    }

    /** Count the number of contiguous regions of 'true' */
    public static int countContiguousRegions(boolean[] array) {
        boolean newRegion = false;
        int count = 0;
        for (boolean bool : array) {
            if (bool) {
                if (newRegion) {
                    count++;
                }
                newRegion = false;
            } else {
                newRegion = true;
            }
        }
        return count;
    }

    /** Determine if this entire column or row of image pixels is empty. */
    public static boolean isLineEmpty(
            BufferedImage img, int pos, boolean row) {

        if (!row) {
            for (int y = 0; y < img.getHeight(); y++) {
                if (img.getRGB(pos, y) != img.getRGB(0, 0)) {
                    return false;
                }
            }
        } else {
            for (int x = 0; x < img.getWidth(); x++) {
                if (img.getRGB(x, pos) != img.getRGB(0, 0)) {
                    return false;
                }
            }
        }
        return true;
    }

    /** Determine if this image is one solid color (implies redundant tile) */
    public static boolean isImageSolidColor(BufferedImage img) {
        int c = img.getRGB(0,0);
        for (int x=0; x<img.getWidth(); x++) {
            for (int y=0; y<img.getHeight(); y++) {
                if (c!=img.getRGB(x,y)) {
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i.stack.imgur.com/ttXm6.png");
        final BufferedImage tileSet = ImageIO.read(url);
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new BorderLayout(5, 5));

                int cols = inferNumberColumns(tileSet);
                System.out.println("tileSet cols: " + cols);
                int rows = inferNumberRows(tileSet);
                System.out.println("tileSet rows: " + rows);

                ArrayList<BufferedImage> tiles = getTiles(tileSet, cols, rows);
                JPanel p = new JPanel(new GridLayout(0, 7, 1, 1));
                for (BufferedImage tile : tiles) {
                    JLabel l = new JLabel(new ImageIcon(tile));
                    l.setBorder(new LineBorder(Color.BLACK));
                    p.add(l);
                }

                gui.add(new JLabel(new ImageIcon(tileSet)));

                JOptionPane.showMessageDialog(null, p);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        SwingUtilities.invokeLater(r);
    }
}

import java.awt.*;
导入java.awt.image.buffereImage;
导入javax.swing.*;
导入javax.swing.border.LineBorder;
导入java.net。*;
导入java.net.URL;
导入java.util.ArrayList;
导入javax.imageio.imageio;
类别可替代性{
/**根据列数和行数将互动程序划分为互动程序
*提供。排除任何纯色图像*/
公共静态数组列表getTiles(
BuffereImage平铺、整数列、整数行){
int w=tile.getWidth();
int h=tile.getHeight();
int wT=w/cols;
int hT=h/行;
如果(wT*cols!=w | | hT*rows!=h){
抛出新的IllegalArgumentException(“平铺不是偶数”+
“WxCols或HxRows的像素倍数!”);
}
ArrayList tiles=新的ArrayList();
对于(int x=0;x对于(int x=0;x由于所有图像都是由单一颜色构成的,因此可以在较大图像的列和行中查找“边框颜色”条

使用获得的与图像大小(宽度x高度)相关的列数和行数来确定每个子图像的像素大小

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.net.*;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;

class TileSetUtility {

    /** Divide the tile into tiles based on the number of cols & rows 
     * supplied.  Exclude any images that are a solid color. */
    public static ArrayList<BufferedImage> getTiles(
            BufferedImage tile, int cols, int rows) {
        int w = tile.getWidth();
        int h = tile.getHeight();
        int wT = w / cols;
        int hT = h / rows;
        if (wT * cols != w || hT * rows != h) {
            throw new IllegalArgumentException("Tile is not an even " +
                    "multiple of pixels of WxCols or HxRows!");
        }
        ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
        for (int x = 0; x < cols; x++) {
            for (int y = 0; y < rows; y++) {
                BufferedImage i = tile.getSubimage(x * wT, y * hT, wT, hT);
                if (!isImageSolidColor(i)) {
                    tiles.add(i);
                }
            }
        }
        return tiles;
    }

    /** Takes an image that represents tiles of a tile set, and infers the 
     * number of columns based on the assumption that the color at 0x0 in the 
     * image represents a border color or frame for the contained tiles. */
    public static int inferNumberColumns(BufferedImage img) {
        boolean[] columnClear = new boolean[img.getWidth()];
        // after this loop, we should have a series of contiguous regions
        // of 'true' in the array.
        for (int ii = 0; ii < columnClear.length; ii++) {
            columnClear[ii] = isLineEmpty(img, ii, false);
        }
        return countContiguousRegions(columnClear);
    }

    /** Takes an image that represents tiles of a tile set, and infers the 
     * number of rows based on the assumption that the color at 0x0 in the 
     * image represents a border color or frame for the contained tiles. */
    public static int inferNumberRows(BufferedImage img) {
        boolean[] columnClear = new boolean[img.getHeight()];
        // after this loop, we should have a series of contiguous regions
        // of 'true' in the array.
        for (int ii = 0; ii < columnClear.length; ii++) {
            columnClear[ii] = isLineEmpty(img, ii, true);
        }
        return countContiguousRegions(columnClear);
    }

    /** Count the number of contiguous regions of 'true' */
    public static int countContiguousRegions(boolean[] array) {
        boolean newRegion = false;
        int count = 0;
        for (boolean bool : array) {
            if (bool) {
                if (newRegion) {
                    count++;
                }
                newRegion = false;
            } else {
                newRegion = true;
            }
        }
        return count;
    }

    /** Determine if this entire column or row of image pixels is empty. */
    public static boolean isLineEmpty(
            BufferedImage img, int pos, boolean row) {

        if (!row) {
            for (int y = 0; y < img.getHeight(); y++) {
                if (img.getRGB(pos, y) != img.getRGB(0, 0)) {
                    return false;
                }
            }
        } else {
            for (int x = 0; x < img.getWidth(); x++) {
                if (img.getRGB(x, pos) != img.getRGB(0, 0)) {
                    return false;
                }
            }
        }
        return true;
    }

    /** Determine if this image is one solid color (implies redundant tile) */
    public static boolean isImageSolidColor(BufferedImage img) {
        int c = img.getRGB(0,0);
        for (int x=0; x<img.getWidth(); x++) {
            for (int y=0; y<img.getHeight(); y++) {
                if (c!=img.getRGB(x,y)) {
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i.stack.imgur.com/ttXm6.png");
        final BufferedImage tileSet = ImageIO.read(url);
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new BorderLayout(5, 5));

                int cols = inferNumberColumns(tileSet);
                System.out.println("tileSet cols: " + cols);
                int rows = inferNumberRows(tileSet);
                System.out.println("tileSet rows: " + rows);

                ArrayList<BufferedImage> tiles = getTiles(tileSet, cols, rows);
                JPanel p = new JPanel(new GridLayout(0, 7, 1, 1));
                for (BufferedImage tile : tiles) {
                    JLabel l = new JLabel(new ImageIcon(tile));
                    l.setBorder(new LineBorder(Color.BLACK));
                    p.add(l);
                }

                gui.add(new JLabel(new ImageIcon(tileSet)));

                JOptionPane.showMessageDialog(null, p);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        SwingUtilities.invokeLater(r);
    }
}

import java.awt.*;
导入java.awt