使用 java.awt.image.BufferedImage 创建 BIFF8 BITMAP 记录需要很多时间 - 有没有更好的方法? [英] Using java.awt.image.BufferedImage for creating BIFF8 BITMAP record takes much time - Is there any better approach?
问题描述
所以我正在创建一个 HSSFSheet
,它有一个使用 apache poi
和自己的低级代码设置的背景位图.
为了实现这一点,我的方法是使用类型为 BufferedImage.TYPE_3BYTE_BGR
的 java.awt.image.BufferedImage
.然后以正确的顺序(从底线到顶线)从该 BufferedImage 的栅格中获取所有字节 R G B,并在宽度(x 方向)上填充到 4 的倍数.
查看代码:
import java.io.FileOutputStream;导入 java.io.FileInputStream;导入 org.apache.poi.hssf.usermodel.*;导入 org.apache.poi.hssf.record.RecordBase;导入 org.apache.poi.hssf.record.StandardRecord;导入 org.apache.poi.hssf.model.InternalSheet;导入 org.apache.poi.util.LittleEndianOutput;导入 java.lang.reflect.Field;导入 java.util.List;导入 java.util.ArrayList;导入 java.util.Arrays;导入 java.awt.image.BufferedImage;导入 java.awt.Graphics2D;导入 java.nio.ByteBuffer;导入 java.nio.ByteOrder;导入 javax.imageio.ImageIO;公共类 CreateExcelHSSFSheetBackgroundBitmap {静态列表<字节>getBackgroundBitmapData(String filePath) 抛出异常 {//参见 https://www.openoffice.org/sc/excelfileformat.pdf - 位图列表<字节>数据 = 新的 ArrayList();//获取 BufferedImage.TYPE_3BYTE_BGR 类型的文件字节数据BufferedImage in = ImageIO.read(new FileInputStream(filePath));BufferedImage image = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_3BYTE_BGR);Graphics2D 图形 = image.createGraphics();graphics.drawImage(in, null, 0, 0);图形处理();短宽度 = (短)image.getWidth();短高度 = (短)image.getHeight();//每个像素有 3 个字节,但宽度字节必须填充为 4 的倍数int widthBytesMultOf4 = (int)((width * 3 + 3)/4 * 4);//--- 这部分需要很多时间,但我没有找到更好的可能性//将字节 R G B 放入数据中;位图的行必须从底线到顶线整数字节 = 0;for (short y = (short)(height - 1); y >= 0; y--) {for (short x = 0; x <宽度; x++) {int r = image.getData().getSample(x, y, 2);data.add(Byte.valueOf((byte)r));字节++;int g = image.getData().getSample(x, y, 1);data.add(Byte.valueOf((byte)g));字节++;int b = image.getData().getSample(x, y, 0);data.add(Byte.valueOf((byte)b));字节++;}//用 0 字节填充 x 到 4 的倍数for (int x = width * 3; x )_records.get(internalsheet);//获取图像文件的字节数列表<字节>data = getBackgroundBitmapData("dummyText.png");//PNG不能有透明度//从 8220 字节的数据中创建 BitmapRecord 和 ContinueRecordsBitmapRecord bitmapRecord = null;列表<ContinueRecord>continueRecords = new ArrayList();整数字节 = 0;如果(数据大小()> 8220){bitmapRecord = new BitmapRecord(data.subList(0, 8220));字节 = 8220;while (bytes < data.size()) {if ((bytes + 8220) < data.size()) {continueRecords.add(new ContinueRecord(data.subList(bytes, bytes + 8220)));字节 += 8220;} 别的 {continueRecords.add(new ContinueRecord(data.subList(bytes, data.size())));休息;}}} 别的 {bitmapRecord = new BitmapRecord(data);}//在 PageSettingsBlock 之后添加记录int i = 0;for (RecordBase r : 记录) {如果(r instanceof org.apache.poi.hssf.record.aggregates.PageSettingsBlock){休息;}我++;}record.add(++i, bitmapRecord);for (ContinueRecord continueRecord : continueRecords) {record.add(++i, continueRecord);}//调试输出for (RecordBase r : internalsheet.getRecords()) {System.out.println(r);}//写出工作簿workbook.write(new FileOutputStream("CreateExcelHSSFSheetBackgroundBitmap.xls"));workbook.close();}静态类 BitmapRecord 扩展了 StandardRecord {//参见 https://www.openoffice.org/sc/excelfileformat.pdf - 位图列表<字节>数据 = 新的 ArrayList();BitmapRecord(列表<字节>数据){this.data = 数据;}公共 int getDataSize() {返回数据大小();}公共短 getSid() {返回(短)0x00E9;}公共无效序列化(LittleEndianOutput 输出){对于(字节 b:数据){out.writeByte(b);}}}静态类 ContinueRecord 扩展 StandardRecord {//参见 https://www.openoffice.org/sc/excelfileformat.pdf - 继续列表<字节>数据 = 新的 ArrayList();继续记录(列表<字节>数据){this.data = 数据;}公共 int getDataSize() {返回数据大小();}公共短 getSid() {返回(短)0x003C;}公共无效序列化(LittleEndianOutput 输出){对于(字节 b:数据){out.writeByte(b);}}}}
代码有效,但
之间的部分//--- 这部分需要很多时间,但我没有找到更好的可能性
和
//---
需要很多时间,因为需要为每个像素获取 3 个字节的 R GB 才能根据上述奇怪的格式获取它们.
有人知道更好的方法吗?也许上面奇怪的格式并没有我想象的那么奇怪,而且已经有其他的用法了?
这是对我有用的代码的修改版本,而且速度非常快.
- 我正在使用
byte[]
(和ByteArrayOutputStream
),不再使用List
. - 因为我们已经有一个
TYPE_3BYTE_BGR
的BufferedImage
,我们几乎可以直接使用它作为 BMP 输出.我们只需要 a) 预先添加一个有效的 BMP 标头和 b) 自底向上写入,c) 将每个扫描线(行)填充到 32 位边界和 d) 切换 BGR -> RGB 顺序. - 我正在使用
Raster
将数据行复制(填充)到输出中,因为复制更大的块比复制单个字节更快.
正如评论中已经指出的,该结构是一个标准的 BMP,带有 BITMAPCOREHEADER
(没有文件头).不幸的是,ImageIO
BMPImageWriter
总是写入文件头并使用 40 字节的 BITMAPINFOHEADER
.您可能可以绕过这些问题,并使用标准编写器,通过稍微按摩数据(提示:文件头包含偏移量 10 处像素数据的偏移量),但由于核心 BMP 格式实现起来很简单,它可能和下面一样容易.
虽然文档肯定暗示直接使用其他格式,如 PNG 和 JPEG,但我没有设法正确地做到这一点.
如果你愿意,可能还有改进的余地,以避免一些字节数组复制(即使用偏移量/长度并将整个数据数组传递给 Bitmap/ContinueRecord
s 而不是 Arrays.copyOfRange()
).
代码:
import java.awt.Graphics2D;导入 java.awt.image.BufferedImage;导入 java.awt.image.Raster;导入 java.io.ByteArrayOutputStream;导入 java.io.FileInputStream;导入 java.io.FileOutputStream;导入 java.lang.reflect.Field;导入 java.nio.ByteBuffer;导入 java.nio.ByteOrder;导入 java.util.ArrayList;导入 java.util.Arrays;导入 java.util.List;导入 javax.imageio.ImageIO;导入 org.apache.poi.hssf.model.InternalSheet;导入 org.apache.poi.hssf.record.RecordBase;导入 org.apache.poi.hssf.record.StandardRecord;导入 org.apache.poi.hssf.usermodel.HSSFSheet;导入 org.apache.poi.hssf.usermodel.HSSFWorkbook;导入 org.apache.poi.util.LittleEndianOutput;公共类 CreateExcelHSSFSheetBackgroundBitmap {静态字节[] getBackgroundBitmapData(字符串文件路径)抛出异常{//参见 https://www.openoffice.org/sc/excelfileformat.pdf - 位图//获取 BufferedImage.TYPE_3BYTE_BGR 类型的文件字节数据BufferedImage in = ImageIO.read(new FileInputStream(filePath));BufferedImage image = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_3BYTE_BGR);Graphics2D 图形 = image.createGraphics();graphics.drawImage(in, null, 0, 0);图形处理();//计算行大小 (c)int rowSize = ((24 * image.getWidth() + 31)/32) * 4;ByteArrayOutputStream output = new ByteArrayOutputStream(image.getHeight() * rowSize * 3 + 1024);//将记录头放入数据中ByteBuffer 头 = ByteBuffer.allocate(8 + 12);header.order(ByteOrder.LITTLE_ENDIAN);//未记录的 XLS 内容header.putShort((short) 0x09);header.putShort((short) 0x01);header.putInt(image.getHeight() * rowSize + 12);//图像流的大小//位图核心头(a)header.putInt(12);header.putShort((short) image.getWidth());header.putShort((short) image.getHeight());//如果自上而下书写,则使用 -heightheader.putShort((short) 1);//平面,总是 1header.putShort((short) 24);//位数output.write(header.array());//自底向上输出行 (b)光栅 raster = image.getRaster().createChild(0, 0, image.getWidth(), image.getHeight(), 0, 0, new int[]{2, 1, 0});//反向 BGR ->RGB (d)字节[]行=新字节[行大小];//填充 (c)for (int i = image.getHeight() - 1; i >= 0; i--) {row = (byte[]) raster.getDataElements(0, i, image.getWidth(), 1, row);输出.写(行);}返回 output.toByteArray();}public static void main(String[] args) 抛出异常 {HSSFWorkbook 工作簿 = new HSSFWorkbook();HSSFSheet sheet = workbook.createSheet("Sheet2");//这个sheet获取背景图片集//我们需要工作表的二进制记录//获取内部表Field _sheet = HSSFSheet.class.getDeclaredField("_sheet");_sheet.setAccessible(true);InternalSheet internalsheet = (InternalSheet)_sheet.get(sheet);//获取记录库列表Field _records = InternalSheet.class.getDeclaredField("_records");_records.setAccessible(true);@SuppressWarnings("未选中")列表<RecordBase>record = (List)_records.get(internalsheet);//获取图像文件的字节数byte[] data = getBackgroundBitmapData("dummy.png");//PNG不能有透明度//从 8220 字节的数据中创建 BitmapRecord 和 ContinueRecordsBitmapRecord bitmapRecord;列表<ContinueRecord>continueRecords = new ArrayList<>();整数字节;如果(数据长度> 8220){bitmapRecord = new BitmapRecord(Arrays.copyOfRange(data, 0, 8220));字节 = 8220;while (bytes < data.length) {if ((bytes + 8220)
So I am creating a HSSFSheet
having a background bitmap set using apache poi
and own low level code. The https://www.openoffice.org/sc/excelfileformat.pdf declares for the Record BITMAP, BIFF8
:
Pixel data (array of height lines of the bitmap, from bottom line to top line, see below)
...
In each line all pixels are written from left to right. Each pixel is stored as 3-byte array: the red, green, and blue component of the colour of the pixel, in this order. The size of each line is aligned to multiples of 4 by inserting zero bytes after the last pixel.
See picture of the PDF for complete declaration:
For fulfilling this my approach is using java.awt.image.BufferedImage
having type BufferedImage.TYPE_3BYTE_BGR
. Then getting all bytes R G B from that BufferedImage's raster in correct order (from bottom line to top line) and filled up up to multiple of 4 in width (x direction).
See code:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.StandardRecord;
import org.apache.poi.hssf.model.InternalSheet;
import org.apache.poi.util.LittleEndianOutput;
import java.lang.reflect.Field;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.imageio.ImageIO;
public class CreateExcelHSSFSheetBackgroundBitmap {
static List<Byte> getBackgroundBitmapData(String filePath) throws Exception {
//see https://www.openoffice.org/sc/excelfileformat.pdf - BITMAP
List<Byte> data = new ArrayList<Byte>();
// get file byte data in type BufferedImage.TYPE_3BYTE_BGR
BufferedImage in = ImageIO.read(new FileInputStream(filePath));
BufferedImage image = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D graphics = image.createGraphics();
graphics.drawImage(in, null, 0, 0);
graphics.dispose();
short width = (short)image.getWidth();
short height = (short)image.getHeight();
// each pixel has 3 bytes but the width bytes must be filled up to multiple of 4
int widthBytesMultOf4 = (int)((width * 3 + 3) / 4 * 4);
// --- this part takes much time but I have not found any better possibility
// put the bytes R G B into the data; lines of the bitmap must be from bottom line to top line
int bytes = 0;
for (short y = (short)(height - 1); y >= 0; y--) {
for (short x = 0; x < width; x++) {
int r = image.getData().getSample(x, y, 2);
data.add(Byte.valueOf((byte)r));
bytes++;
int g = image.getData().getSample(x, y, 1);
data.add(Byte.valueOf((byte)g));
bytes++;
int b = image.getData().getSample(x, y, 0);
data.add(Byte.valueOf((byte)b));
bytes++;
}
// fill up x with 0 bytes up to multiple of 4
for (int x = width * 3; x < widthBytesMultOf4; x++) {
data.add(Byte.valueOf((byte)0));
bytes++;
}
}
// ---
// size 12 bytes (additional headers, see below) + picture bytes
int size = 12 + bytes;
// get size int as LITTLE_ENDIAN bytes
ByteBuffer bSize = ByteBuffer.allocate(4);
bSize.order(ByteOrder.LITTLE_ENDIAN);
bSize.putInt(size);
// get width short as LITTLE_ENDIAN bytes
ByteBuffer bWidth = ByteBuffer.allocate(2);
bWidth.order(ByteOrder.LITTLE_ENDIAN);
bWidth.putShort(width);
// get height short as LITTLE_ENDIAN bytes
ByteBuffer bHeight = ByteBuffer.allocate(2);
bHeight.order(ByteOrder.LITTLE_ENDIAN);
bHeight.putShort(height);
// put the record headers into the data
Byte[] dataPart = new Byte[] { 0x09, 0x00, 0x01, 0x00,
bSize.array()[0], bSize.array()[1], bSize.array()[2], bSize.array()[3], // size
//now 12 bytes follow
0x0C, 0x00, 0x00, 0x00,
bWidth.array()[0], bWidth.array()[1], // width
bHeight.array()[0], bHeight.array()[1], // height
0x01, 0x00, 0x18, 0x00
};
data.addAll(0, Arrays.asList(dataPart));
return data;
}
public static void main(String[] args) throws Exception {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Sheet1");
sheet = workbook.createSheet("Sheet2"); // this sheet gets the background image set
// we need the binary records of the sheet
// get InternalSheet
Field _sheet = HSSFSheet.class.getDeclaredField("_sheet");
_sheet.setAccessible(true);
InternalSheet internalsheet = (InternalSheet)_sheet.get(sheet);
// get List of RecordBase
Field _records = InternalSheet.class.getDeclaredField("_records");
_records.setAccessible(true);
@SuppressWarnings("unchecked")
List<RecordBase> records = (List<RecordBase>)_records.get(internalsheet);
// get bytes of the image file
List<Byte> data = getBackgroundBitmapData("dummyText.png"); //PNG must not have transparency
// do creating BitmapRecord and ContinueRecords from the data in parts of 8220 bytes
BitmapRecord bitmapRecord = null;
List<ContinueRecord> continueRecords = new ArrayList<ContinueRecord>();
int bytes = 0;
if (data.size() > 8220) {
bitmapRecord = new BitmapRecord(data.subList(0, 8220));
bytes = 8220;
while (bytes < data.size()) {
if ((bytes + 8220) < data.size()) {
continueRecords.add(new ContinueRecord(data.subList(bytes, bytes + 8220)));
bytes += 8220;
} else {
continueRecords.add(new ContinueRecord(data.subList(bytes, data.size())));
break;
}
}
} else {
bitmapRecord = new BitmapRecord(data);
}
// add the records after PageSettingsBlock
int i = 0;
for (RecordBase r : records) {
if (r instanceof org.apache.poi.hssf.record.aggregates.PageSettingsBlock) {
break;
}
i++;
}
records.add(++i, bitmapRecord);
for (ContinueRecord continueRecord : continueRecords) {
records.add(++i, continueRecord);
}
// debug output
for (RecordBase r : internalsheet.getRecords()) {
System.out.println(r);
}
// write out workbook
workbook.write(new FileOutputStream("CreateExcelHSSFSheetBackgroundBitmap.xls"));
workbook.close();
}
static class BitmapRecord extends StandardRecord {
//see https://www.openoffice.org/sc/excelfileformat.pdf - BITMAP
List<Byte> data = new ArrayList<Byte>();
BitmapRecord(List<Byte> data) {
this.data = data;
}
public int getDataSize() {
return data.size();
}
public short getSid() {
return (short)0x00E9;
}
public void serialize(LittleEndianOutput out) {
for (Byte b : data) {
out.writeByte(b);
}
}
}
static class ContinueRecord extends StandardRecord {
//see https://www.openoffice.org/sc/excelfileformat.pdf - CONTINUE
List<Byte> data = new ArrayList<Byte>();
ContinueRecord(List<Byte> data) {
this.data = data;
}
public int getDataSize() {
return data.size();
}
public short getSid() {
return (short)0x003C;
}
public void serialize(LittleEndianOutput out) {
for (Byte b : data) {
out.writeByte(b);
}
}
}
}
The code works but the part between
// --- this part takes much time but I have not found any better possibility
and
// ---
takes much time since 3 bytes R G B for each single pixel needs to be got for getting them according to the above strange format.
Does anyone knows of a better approach? Maybe the above strange format is not as strange as I think it is and there are already other usages of it?
Here's a modified version of your code that works for me, AND is pretty fast.
- I'm using
byte[]
(andByteArrayOutputStream
) all around, no moreList<Byte>
. - As we already have a
BufferedImage
ofTYPE_3BYTE_BGR
, we can use that almost directly as the BMP output. We just need to a) prepend a valid BMP header and b) write bottom-up, c) pad each scanline (row) to a 32 bit boundary and d) switch BGR -> RGB order. - I'm using the
Raster
to copy (padded) rows of data into the output, as copying larger chunks is faster than copying single bytes.
As already noted in the comments, the structure is a standard BMP with BITMAPCOREHEADER
(and no file header). Unfortunately, the ImageIO
BMPImageWriter
always write the file header and uses the BITMAPINFOHEADER
which is 40 bytes. You could probably get around these things, and use the standard writer, by massaging the data a little (hint: the file header contains an offset to the pixel data at offset 10), but as the core BMP format is trivial to implement, it might be just as easy to do as below.
While the documentation certainly implies that using other formats like PNG and JPEG directly, I haven't managed to do this properly.
There's probably still room for improvement if you like, to avoid some byte array copying (ie. use offset/length and pass the entire data array to the Bitmap/ContinueRecord
s instead of Arrays.copyOfRange()
).
Code:
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import org.apache.poi.hssf.model.InternalSheet;
import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.StandardRecord;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndianOutput;
public class CreateExcelHSSFSheetBackgroundBitmap {
static byte[] getBackgroundBitmapData(String filePath) throws Exception {
//see https://www.openoffice.org/sc/excelfileformat.pdf - BITMAP
// get file byte data in type BufferedImage.TYPE_3BYTE_BGR
BufferedImage in = ImageIO.read(new FileInputStream(filePath));
BufferedImage image = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D graphics = image.createGraphics();
graphics.drawImage(in, null, 0, 0);
graphics.dispose();
// calculate row size (c)
int rowSize = ((24 * image.getWidth() + 31) / 32) * 4;
ByteArrayOutputStream output = new ByteArrayOutputStream(image.getHeight() * rowSize * 3 + 1024);
// put the record headers into the data
ByteBuffer header = ByteBuffer.allocate(8 + 12);
header.order(ByteOrder.LITTLE_ENDIAN);
// Undocumented XLS stuff
header.putShort((short) 0x09);
header.putShort((short) 0x01);
header.putInt(image.getHeight() * rowSize + 12); // Size of image stream
// BITMAPCOREHEADER (a)
header.putInt(12);
header.putShort((short) image.getWidth());
header.putShort((short) image.getHeight()); // Use -height if writing top-down
header.putShort((short) 1); // planes, always 1
header.putShort((short) 24); // bitcount
output.write(header.array());
// Output rows bottom-up (b)
Raster raster = image.getRaster()
.createChild(0, 0, image.getWidth(), image.getHeight(), 0, 0, new int[]{2, 1, 0}); // Reverse BGR -> RGB (d)
byte[] row = new byte[rowSize]; // padded (c)
for (int i = image.getHeight() - 1; i >= 0; i--) {
row = (byte[]) raster.getDataElements(0, i, image.getWidth(), 1, row);
output.write(row);
}
return output.toByteArray();
}
public static void main(String[] args) throws Exception {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Sheet2"); // this sheet gets the background image set
// we need the binary records of the sheet
// get InternalSheet
Field _sheet = HSSFSheet.class.getDeclaredField("_sheet");
_sheet.setAccessible(true);
InternalSheet internalsheet = (InternalSheet)_sheet.get(sheet);
// get List of RecordBase
Field _records = InternalSheet.class.getDeclaredField("_records");
_records.setAccessible(true);
@SuppressWarnings("unchecked")
List<RecordBase> records = (List<RecordBase>)_records.get(internalsheet);
// get bytes of the image file
byte[] data = getBackgroundBitmapData("dummy.png"); //PNG must not have transparency
// do creating BitmapRecord and ContinueRecords from the data in parts of 8220 bytes
BitmapRecord bitmapRecord;
List<ContinueRecord> continueRecords = new ArrayList<>();
int bytes;
if (data.length > 8220) {
bitmapRecord = new BitmapRecord(Arrays.copyOfRange(data, 0, 8220));
bytes = 8220;
while (bytes < data.length) {
if ((bytes + 8220) < data.length) {
continueRecords.add(new ContinueRecord(Arrays.copyOfRange(data, bytes, bytes + 8220)));
bytes += 8220;
} else {
continueRecords.add(new ContinueRecord(Arrays.copyOfRange(data, bytes, data.length)));
break;
}
}
} else {
bitmapRecord = new BitmapRecord(data);
}
// add the records after PageSettingsBlock
int i = 0;
for (RecordBase r : records) {
if (r instanceof org.apache.poi.hssf.record.aggregates.PageSettingsBlock) {
break;
}
i++;
}
records.add(++i, bitmapRecord);
for (ContinueRecord continueRecord : continueRecords) {
records.add(++i, continueRecord);
}
// debug output
for (RecordBase r : internalsheet.getRecords()) {
System.out.println(r);
}
// write out workbook
workbook.write(new FileOutputStream("backgroundImage.xls"));
workbook.close();
}
static class BitmapRecord extends StandardRecord {
//see https://www.openoffice.org/sc/excelfileformat.pdf - BITMAP
byte[] data;
BitmapRecord(byte[] data) {
this.data = data;
}
public int getDataSize() {
return data.length;
}
public short getSid() {
return (short)0x00E9;
}
public void serialize(LittleEndianOutput out) {
out.write(data);
}
}
static class ContinueRecord extends StandardRecord {
//see https://www.openoffice.org/sc/excelfileformat.pdf - CONTINUE
byte[] data;
ContinueRecord(byte[] data) {
this.data = data;
}
public int getDataSize() {
return data.length;
}
public short getSid() {
return (short)0x003C;
}
public void serialize(LittleEndianOutput out) {
out.write(data);
}
}
}
这篇关于使用 java.awt.image.BufferedImage 创建 BIFF8 BITMAP 记录需要很多时间 - 有没有更好的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!