Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
683 views
in Technique[技术] by (71.8m points)

swing - Java save image pixels into an array & draw image

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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...

SlowLoad

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 i

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...