Java将图像像素保存到数组中绘制图像 [英] Java save image pixels into an array & draw image

查看:72
本文介绍了Java将图像像素保存到数组中绘制图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个仅下载jar的游戏,当您下载jar时,游戏将下载新的缓存.

同时我想显示一个漂亮的背景,而不是将其加载到链接之外,我想到了这个主意,但不确定是否可行.

每个图像都加载并逐像素绘制,是否有可能获取图像的所有像素颜色,宽度,高度,然后打印值&然后将它们放在一个数组中,例如:

  public int [] imagePixels = new int [] {此处放置像素...}; 

然后简单地使用一种方法来绘制背景?那有可能吗?

是否有更好的解决方案,例如将图像包装到罐子中?

说明:

您有一张图片,我想加载该图片并加载每个像素,我们从第0行开始,按宽度&高度.

我想收集每个像素并将其保存到图像中,因此我可以在不使用任何文件的情况下加载图像,而只需从阵列上绘制像素即可.

解决方案

好的,所以您将面临基本问题.大多数图像格式都对图像数据进行某种压缩,它们也可能将有关图像的重要数据附加到文件末尾,例如颜色模型信息,这使得在读取它们时呈现它们变得有些困难.>

您需要的是一种将图像的块"写入文件的方法,该文件可以轻松读取但不会显着增加文件大小.

我的测试图像开始于301.68 kb,而我的块"文件格式最终为1.42 mb,直到我测试了一个未压缩的文件,最终为5.63 mb时,我对此并不特别满意.为了钱.

该示例使用内置的 GZip 压缩,您可以使用 Apache-Commons-Compress

在纸面上,这基本上是做什么的...

图像反向加载...

理论是好的,实现是...有点混乱,对不起,可能有点儿整洁,但是你明白了.

此想法的目的是不立即读取整个 Image.dat 文件,而是将其保留在原处并一次读取一行...这允许延迟.

现在,在此示例中,我使用了 javax.swing.Timer 注入一点暂停,说实话,最好使用 SwingWorker ...但我确定您知道这个主意...

  import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;导入java.awt.BorderLayout;导入java.awt.Color;导入java.awt.Dimension;导入java.awt.EventQueue;导入java.awt.Graphics;导入java.awt.Graphics2D;导入java.awt.Point;导入java.awt.event.ActionEvent;导入java.awt.event.ActionListener;导入java.awt.image.BufferedImage;导入java.io.BufferedReader;导入java.io.BufferedWriter;导入java.io.ByteArrayInputStream;导入java.io.ByteArrayOutputStream;导入java.io.File;导入java.io.FileReader;导入java.io.FileWriter;导入java.io.IOException;导入java.util.zip.GZIPInputStream;导入java.util.zip.GZIPOutputStream;导入javax.imageio.ImageIO;导入javax.swing.JFrame;导入javax.swing.JPanel;导入javax.swing.Timer;导入javax.swing.UIManager;导入javax.swing.UnsupportedLookAndFeelException;公共类ConvertImage {公共静态void main(String [] args){尝试 {exportImage(新文件("/path/to/your/image.jpg"),新文件("Image.dat"));} catch(IOException ex){ex.printStackTrace();}新的ConvertImage();}公共ConvertImage(){EventQueue.invokeLater(new Runnable(){@Override公共无效run(){尝试 {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch(ClassNotFoundException ex){} catch(InstantiationException ex){}捕获(前为IllegalAccessException){} catch(ex UnsupportedLookAndFeelException ex){}JFrame frame = new JFrame("Test");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setLayout(new BorderLayout());frame.add(new TestPane());frame.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共类TestPane扩展了JPanel {private int imgWidth = 0;private int imgHeight = 0;private BufferedReader br = null;私有BufferedImage imgBuffer;私有int偏移量;公共TestPane(){尝试 {br = new BufferedReader(new FileReader(new File("Image.dat"))));字符串标头= br.readLine();String []部分= header.split("x");imgWidth = Integer.parseInt(parts [0]);imgHeight = Integer.parseInt(parts [1]);imgBuffer =新的BufferedImage(imgWidth,imgHeight,BufferedImage.TYPE_INT_ARGB);计时器计时器=新计时器(1000,新ActionListener(){@Override公共无效actionPerformed(ActionEvent e){Graphics2D g2d = null;尝试 {字符串文本= br.readLine();if(text!= null){//将字符串解码回压缩的字节数组字节[]解码= Base64.decode(文本);GZIPInputStream zis = null;尝试 {//解压缩字节数组zis = new GZIPInputStream(new ByteArrayInputStream(decode));//建立像素的文字表示StringBuilder sb =新的StringBuilder(128);byte []缓冲区=新的byte [1024];int bytesRead = -1;而((bytesRead = zis.read(buffer))> -1){sb.append(new String(buffer,0,bytesRead,"UTF-8"));}//将像素拆分为单个打包的intString []元素= sb.toString().split(,");g2d = imgBuffer.createGraphics();对于(String element:elements){点p = getPointAt(offset,imgWidth,imgHeight);g2d.setColor(new Color(Integer.parseInt(element),true));g2d.drawLine(p.x,p.y,p.x,p.y);偏移++;}g2d.dispose();repaint();} catch(Exception exp){exp.printStackTrace();}} 别的 {尝试 {br.close();} catch(Exception exp){}((计时器)e.getSource()).stop();}} catch(IOException ex){ex.printStackTrace();尝试 {br.close();} catch(Exception exp){}((计时器)e.getSource()).stop();} 最后 {尝试 {g2d.dispose();} catch(Exception exp){}}}});timer.start();} catch(IOException ex){ex.printStackTrace();尝试 {br.close();} catch(Exception e){}}}@Override公共维度getPreferredSize(){返回新的Dimension(imgWidth,imgHeight);}@Override受保护的void paintComponent(Graphics g){super.paintComponent(g);int x =(getWidth()-imgBuffer.getWidth())/2;int y =(getHeight()-imgBuffer.getHeight())/2;g.drawImage(imgBuffer,x,y,this);}}受保护的静态void exportImage(文件输入,文件输出)抛出IOException {BufferedImage img = ImageIO.read(in);int width = img.getWidth();int height = img.getHeight();//计算图像的总长度"int imageLength =宽度*高度;//计算我们将产生的每一行的长度//这是每个块的像素数int runLength = Math.round((width * height)* 0.1f);//写入输出的位置BufferedWriter bw = null;尝试 {bw = new BufferedWriter(new FileWriter(out));bw.write(width +"x" + height);bw.newLine();//开始转换像素...int偏移= 0;while(offset< imageLength){//计算下一个缓冲区运行的大小,我们不想//超出图片的末尾int bufferSize = runLength;if(offset + bufferSize> imageLength){bufferSize = imageLength-偏移量;}//创建一个缓冲区以将像素结果存储在...StringBuilder sb =新的StringBuilder(bufferSize * 2);for(int index = 0; index< bufferSize; index ++){点p = getPointAt(offset + index,width,height);如果(sb.length()> 0){sb.append(,");}//存储像素sb.append(img.getRGB(p.x,p.y));}//将内容写入压缩流中...ByteArrayOutputStream baos = new ByteArrayOutputStream();GZIPOutputStream zos =新的GZIPOutputStream(baos);zos.write(sb.toString().getBytes());zos.flush();zos.close();//将压缩结果编码为Base64编码的字符串= Base64.encode(baos.toByteArray());//写内容bw.write(已编码);bw.newLine();//跳至下一个大块"偏移量+ = bufferSize;}} catch(IOException exp){exp.printStackTrace();} 最后 {尝试 {bw.close();} catch(Exception e){}}}公共静态Point getPointAt(int index,int width,int height){点p = new Point();p.y =索引/宽度;p.x =索引%宽度;返回p;}} 

I am working on a game where you only download the jar, and when you download the jar, the game will download the new cache.

Meanwhile I want to show a nice background, without loading it off a link, I've thought of this idea, I am not sure if it is possible though.

Every image is loaded and is being drawn pixel by pixel, is it possible to get ALL pixels colors of an image, width, height and then print the values & then put them in an array eg:

public int[] imagePixels = new int[]{PUT PIXELS HERE...};

And then simply use a method to draw that background? Is that possible to do?

Are there any better solutions for this like packing the image into the jar or something?

Explanation:

You have an image, I want to load that image and load every single pixel, we start from row 0, by width & height.

I want to collect every single pixel and save it into an image, so then I can load the image without using any file, and just draw the pixels off the array.

解决方案

Okay, so the basic problems you will face. Most image formats employee some kind of compression on the image data, they may also append important data about the image to the end of the file, such as the color model information, which makes rendering them as they are read some what difficult.

What you need is some way to write "chunks" of the image to a file that can be easily read back but does not dramatically increase the file size.

My test image started at 301.68 kb and my "chunk" file format end up as 1.42 mb, which I wasn't particularly happy with until I tested a uncompressed file which ended up at 5.63 mb...think I can live for the momement.

The example uses the inbuilt GZip compression, you can get better compression by using something like Apache-Commons-Compress

On paper, what this basically does...

  • Reads a chunk of the pixel data, writing this to a comma-separated String, where it each value is a given pixel value from the image. The example reads 10% of the file per chunk.
  • Each chunk is then compressed using a GZip compression
  • The resulting compressed bytes are then encoded using a Base64 encoding. Personally I'd prefer to use Apache-Commons-Encode as it places less relience on an internal/private class.
  • The resulting encoded String is then written to a File and a new line is placed at the end of the line.

The image is loaded in reverse...

  • A line is read from the file (Base64 encoded String)
  • The String is decoded (to a compressed byte array)
  • The byte array is then decompressed into a comma separated String
  • The comma separated String is then split and the resulting pixel data is drawn to a backing buffer
  • The resulting backing buffer is updated to the screen...

The theory is all good, the implementation is...a little messy, sorry, could be a little tidier, but you get the idea.

The intention with this idea would be to not read the entire Image.dat file at once, but instead, leaving it where it is and read a line at a time...this allows for latency.

Now, in this example, I've used a javax.swing.Timer to inject a little pause, to be honest, it would be better to use a SwingWorker...but I'm sure you get the idea...

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ConvertImage {

    public static void main(String[] args) {
        try {
            exportImage(new File("/path/to/your/image.jpg"), new File("Image.dat"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        new ConvertImage();
    }

    public ConvertImage() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int imgWidth = 0;
        private int imgHeight = 0;

        private BufferedReader br = null;
        private BufferedImage imgBuffer;
        private int offset;

        public TestPane() {
            try {
                br = new BufferedReader(new FileReader(new File("Image.dat")));
                String header = br.readLine();
                String[] parts = header.split("x");
                imgWidth = Integer.parseInt(parts[0]);
                imgHeight = Integer.parseInt(parts[1]);

                imgBuffer = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_ARGB);

                Timer timer = new Timer(1000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Graphics2D g2d = null;
                        try {
                            String text = br.readLine();
                            if (text != null) {
                                // Decode the String back to a compressed byte array
                                byte[] decode = Base64.decode(text);
                                GZIPInputStream zis = null;
                                try {
                                    // Decompress the byte array
                                    zis = new GZIPInputStream(new ByteArrayInputStream(decode));
                                    // Build the text representation of the pixels
                                    StringBuilder sb = new StringBuilder(128);
                                    byte[] buffer = new byte[1024];
                                    int bytesRead = -1;
                                    while ((bytesRead = zis.read(buffer)) > -1) {
                                        sb.append(new String(buffer, 0, bytesRead, "UTF-8"));
                                    }
                                    // Split the pixels into individual packed ints
                                    String[] elements = sb.toString().split(",");
                                    g2d = imgBuffer.createGraphics();
                                    for (String element : elements) {
                                        Point p = getPointAt(offset, imgWidth, imgHeight);
                                        g2d.setColor(new Color(Integer.parseInt(element), true));
                                        g2d.drawLine(p.x, p.y, p.x, p.y);
                                        offset++;
                                    }
                                    g2d.dispose();
                                    repaint();
                                } catch (Exception exp) {
                                    exp.printStackTrace();
                                }
                            } else {
                                try {
                                    br.close();
                                } catch (Exception exp) {
                                }
                                ((Timer) e.getSource()).stop();
                            }
                        } catch (IOException ex) {
                            ex.printStackTrace();
                            try {
                                br.close();
                            } catch (Exception exp) {
                            }
                            ((Timer) e.getSource()).stop();
                        } finally {
                            try {
                                g2d.dispose();
                            } catch (Exception exp) {
                            }
                        }
                    }
                });
                timer.start();
            } catch (IOException ex) {
                ex.printStackTrace();
                try {
                    br.close();
                } catch (Exception e) {
                }
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(imgWidth, imgHeight);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int x = (getWidth() - imgBuffer.getWidth()) / 2;
            int y = (getHeight() - imgBuffer.getHeight()) / 2;
            g.drawImage(imgBuffer, x, y, this);
        }

    }

    protected static void exportImage(File in, File out) throws IOException {
        BufferedImage img = ImageIO.read(in);
        int width = img.getWidth();
        int height = img.getHeight();

        // Calculate the total "length" of the image
        int imageLength = width * height;
        // Calculate the length of each line we will produce
        // This is the number of pixels per chunk
        int runLength = Math.round((width * height) * 0.1f);

        // The place to write the output
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new FileWriter(out));
            bw.write(width + "x" + height);
            bw.newLine();

            // Start converting the pixels...
            int offset = 0;
            while (offset < imageLength) {

                // Calculate the size of the next buffer run, we don't want to 
                // over run the end of the image
                int bufferSize = runLength;
                if (offset + bufferSize > imageLength) {
                    bufferSize = imageLength - offset;
                }

                // Create a buffer to store the pixel results in...
                StringBuilder sb = new StringBuilder(bufferSize * 2);
                for (int index = 0; index < bufferSize; index++) {
                    Point p = getPointAt(offset + index, width, height);
                    if (sb.length() > 0) {
                        sb.append(",");
                    }
                    // Store the pixel
                    sb.append(img.getRGB(p.x, p.y));
                }
                // Write the contents to a compressed stream...
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream zos = new GZIPOutputStream(baos);
                zos.write(sb.toString().getBytes());
                zos.flush();
                zos.close();
                // Encode the compressed results to Base64
                String encoded = Base64.encode(baos.toByteArray());
                // Write the content...
                bw.write(encoded);
                bw.newLine();

                // Jump to the next "chunk"
                offset += bufferSize;
            }
        } catch (IOException exp) {
            exp.printStackTrace();
        } finally {
            try {
                bw.close();
            } catch (Exception e) {
            }
        }
    }

    public static Point getPointAt(int index, int width, int height) {
        Point p = new Point();
        p.y = index / width;
        p.x = index % width;
        return p;
    }

}

这篇关于Java将图像像素保存到数组中绘制图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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