自动找到PNG精灵表的帧大小 [英] Automatically find frame sizes from png sprite sheet

查看:211
本文介绍了自动找到PNG精灵表的帧大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能重复:结果
  <一href=\"http://stackoverflow.com/questions/14432021/pyside-separating-a-spritesheet-separating-an-image-into-contiguous-regions-o\">PySide:分离spritesheet /图像分离成彩色的连续区域

由于具有透明像素的PNG图片和个人动画帧的一个网格(其中最后一行不一定是满),你会如何自动找到每一帧的大小,并检测多少帧中。 PNG?

Given a .png image with transparent pixels and a grid of individual animation frames (where the last row need not be full), how would you automatically find the dimensions of each individual frame, and detect how many frames are in the .png?

我想要的资源从毛刺的创意公地宝库转换成我们的内部格式,我我有隔离原始.pngs帧信息的问题。

I am trying to convert the resources from the creative-commons treasure-trove of Glitch into our internal format, and I am having problems isolating frame information from the raw .pngs.


(由毛刺下 http://creativecommons.org/licenses/by-发布NC-SA / 3.0 / deed.en_US 许可证)

在这种情况下,我能找到的帧189点¯x230像素;但看着这件事需要时间,而且有大量的图片潜在抬头。

In this case, I can find that frames are 189 x 230 px; but looking this up requires time, and there are a lot of images to potentially look up.

我想将图像分割成一个Java Swing的桌面应用程序中使用框架。我可以通过加载镜像的ImageIO 的BufferedImage ,轻松地检查像素的透明度。只有几个可能的帧大小:给定一个945x690帧中的例子中,并假设50像素的最小侧,唯一可行的帧宽度是5×189(正确),7×135,或9×105

I would like to split the image into frames for use inside a Java Swing desktop application. I can load the image using ImageIO into a BufferedImage, and easily check for pixel transparency. There are only a few possible frame sizes: given a 945x690 frame as in the example, and assuming a minimal side of 50px, the only plausible frame-widths are 5 x 189 (correct), 7 x 135, or 9 x 105.

那么,你将如何找到帧大小?这并不需要是极其有效的,因为资源转换是一次性的问题。伪code的答案是罚款;我在算法最感兴趣。

So, how would you find the frame size? This does not need to be tremendously efficient, as resource conversion is a one-time problem. Pseudo-code answers are fine; I am mostly interested in the algorithm.

注意: PySide:分离spritesheet /图像分离成彩色解释如何处理非动画精灵表,在表内的不规则尺寸图像的连续区域。我感兴趣的是检测行x列,可以用更简单的算法来解决(见接受的答案)。

Note: PySide: Separating a spritesheet / Separating an image into contiguous regions of color explains how to deal with non-animation sprite-sheets, with irregularly sized images within the sheet. I am interested in detecting rows x columns, which can be solved with a much simpler algorithm (see accepted answer).

推荐答案

由于所有的图像是由一个单一的颜色框,你可以看看跨越较大的图像中列的框架边框颜色酒吧和行。

Since all the images are framed by a single color, you could look for bars of 'frame border color' in columns and rows across the larger image.

使用列和得到的行数,相对于图像(宽×高)的尺寸,以确定每个子图像的像素的大小。

Use the number of columns and rows obtained, in relation to the size of the image (width x height), to determine the pixel sizes of each sub-image.

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);
    }
}

这篇关于自动找到PNG精灵表的帧大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆