好的,所以你會遇到的基本問題。大多數圖像格式都會對圖像數據進行某種壓縮,它們也可能會將有關圖像的重要數據附加到文件末尾,例如顏色模型信息,這使得渲染它們時會產生一些困難。
您需要的是將圖像的「塊」寫入文件的某種方式,該文件可以輕鬆讀回但不會顯着增加文件大小。
我的測試圖像開始於301.68 kb,我的「chunk」文件格式最終爲1.42 mb,在我測試了一個最終爲5.63 mb的未壓縮文件之前,我並不特別滿意......想想我可以活着爲momement。
的例子使用內置的GZip
壓縮,可以使用類似Apache-Commons-Compress
在紙面上,這是什麼基本上沒有得到更好的壓縮...
- 讀取像素數據的塊,將其寫入以逗號分隔的
String
,其中每個值都是圖像中給定的像素值。該示例讀取每個塊的10%的文件。
- 然後使用
GZip
壓縮對每個塊進行壓縮
- 然後使用
Base64
編碼對得到的壓縮字節進行編碼。就個人而言,我寧願使用Apache-Commons-Encode
,因爲它減少了對內部/私人課程的依賴。
- 然後將生成的編碼
String
寫入File
,並將新行放在行的末尾。
圖像反向加載...
- 甲線從文件中讀出(Base64編碼
String
)
- 的
String
進行解碼(到壓縮byte
陣列)
- 然後
byte
陣列被解壓縮爲逗號分隔String
- 的將逗號分隔
String
然後split
,並將得到的像素數據繪製到背景緩衝區
- 將得到的背景緩衝區更新爲屏幕。 ..
理論是一切都很好,實施是...有點混亂,對不起,可能有點整齊,但你明白了。
這個想法的意圖是不一次讀取整個Image.dat
文件,而是將其保留在原來的位置並一次讀取一行......這可以實現延遲。現在
,在這個例子中,我使用了javax.swing.Timer
注入一點停頓,說實話,這將是更好地使用SwingWorker
...但我敢肯定,你的想法...
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;
}
}
請什麼的問題,爲更好地幫助越早張貼SSCCE或MCVE或MCTaRE – mKorbel
加入微小的解釋。 – Artemkller545
是的,它可能,但你必須加載圖像開始和訪問柵格數據,這也會給你的寬度和高度。 – MadProgrammer