使用java.awt.image.buffereImage创建BIFF8位图记录需要很多时间-有没有更好的方法?
因此,我正在创建一个使用java.awt.image.buffereImage创建BIFF8位图记录需要很多时间-有没有更好的方法?,java,apache-poi,awt,bufferedimage,Java,Apache Poi,Awt,Bufferedimage,因此,我正在创建一个HSSFSheet,使用apache poi设置背景位图,并拥有自己的低级代码。记录位图的声明,BIFF8: 像素数据(位图的高度线阵列,从底线到顶线,见下文) 在每一行中,所有像素都从左向右写入。每个像素存储为3字节数组:像素颜色的红色、绿色和蓝色分量,按此顺序排列。通过在最后一个像素后插入零字节,将每行的大小对齐为4的倍数 完整声明见PDF图片: 为了实现这一点,我的方法是使用java.awt.image.BufferedImage类型BufferedImage.ty
HSSFSheet
,使用apache poi
设置背景位图,并拥有自己的低级代码。记录位图的声明,BIFF8
:
像素数据(位图的高度线阵列,从底线到顶线,见下文)
在每一行中,所有像素都从左向右写入。每个像素存储为3字节数组:像素颜色的红色、绿色和蓝色分量,按此顺序排列。通过在最后一个像素后插入零字节,将每行的大小对齐为4的倍数
完整声明见PDF图片:
为了实现这一点,我的方法是使用java.awt.image.BufferedImage
类型BufferedImage.type\u3byte\ubgr
。然后从BuffereImage的光栅中以正确的顺序(从底行到顶行)获取所有字节R G B,并在宽度(x方向)上填充到4的倍数
见代码:
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);
}
}
}
}
及
需要花费很多时间,因为根据上述奇怪的格式,需要获得每个像素的3字节rgb
有人知道更好的方法吗?也许上面这种奇怪的格式并不像我想象的那么奇怪,它已经有了其他的用途了?通常只是程序员自己的愚蠢;-)。在德语中有一句谚语:“因为有树,所以看不见森林。” 只需将
buffereImage的光栅
从循环外部获取一次,而不是一次又一次地从循环内部获取,即可极大地提高速度:
...
// put the bytes R G B into the data; lines of the bitmap must be from bottom line to top line
int bytes = 0;
Raster raster = image.getData();
for (short y = (short)(height - 1); y >= 0; y--) {
for (short x = 0; x < width; x++) {
int r = raster.getSample(x, y, 2);
data.add(Byte.valueOf((byte)r));
bytes++;
int g = raster.getSample(x, y, 1);
data.add(Byte.valueOf((byte)g));
bytes++;
int b = raster.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++;
}
}
...
这是你的代码的一个修改版本,对我来说很有效,而且速度非常快
我到处使用byte[]
(和ByteArrayOutputStream
),没有更多的列表
李>
由于我们已经有了类型为3BYTE\u BGR
的缓冲图像
,我们几乎可以直接将其用作BMP输出。我们只需要a)预先设置一个有效的BMP头,b)自下而上写入,c)将每个扫描线(行)填充到32位边界,d)切换BGR->RGB顺序李>
我使用光栅
将数据行复制(填充)到输出中,因为复制较大的数据块比复制单个字节快
如注释中所述,该结构是标准BMP,带有BITMAPCOREHEADER
(且无文件头)。不幸的是,ImageIO
BMPImageWriter
总是写入文件头并使用40字节的BitMapInfo头。您可能可以绕过这些问题,使用标准的书写器,只需稍微调整一下数据(提示:文件头包含偏移量为10的像素数据偏移量),但由于核心BMP格式实现起来很简单,因此可能与下面的操作一样简单
虽然文档中明确表示直接使用其他格式,如PNG和JPEG,但我没有做到这一点
如果您愿意,可能还有改进的余地,以避免某些字节数组复制(即使用偏移量/长度,并将整个数据数组传递给位图/连续记录
s,而不是数组。copyOfRange()
)
代码:
导入java.awt.Graphics2D;
导入java.awt.image.buffereImage;
导入java.awt.image.graster;
导入java.io.ByteArrayOutputStream;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.lang.reflect.Field;
导入java.nio.ByteBuffer;
导入java.nio.ByteOrder;
导入java.util.ArrayList;
导入java.util.array;
导入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 -位图
//获取BuffereImage.type_3BYTE_BGR类型中的文件字节数据
BuffereImage in=ImageIO.read(新文件输入流(文件路径));
BuffereImage=新的BuffereImage(in.getWidth()、in.getHeight()、BuffereImage.TYPE_3BYTE_BGR);
Graphics2D graphics=image.createGraphics();
graphics.drawImage(in,null,0,0);
graphics.dispose();
//计算行大小(c)
int rowSize=((24*image.getWidth()+31)/32)*4;
ByteArrayOutputStream输出=新建ByteArrayOutputStream(image.getHeight()*行大小*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);//图像流的大小
//BITMAPCOREHEADER(a)
标题。putInt(12);
header.putShort((short)image.getWidth());
header.putShort((short)image.getHeight());//如果自顶向下写入,则使用-height
header.putShort((short)1);//平面,始终为1
header.putShort((short)24);//位计数
output.write(header.array());
//自下而上的输出行(b)
光栅=image.getRaster()
.createChild(0,0,image.getWidth(),image.getHeight(),0,0,新int[]{2,1,0});//反向BGR->RGB(d)
byte[]行=新字节[rowSize];//填充(c)
对于(int i=image.getHeight()-1;i>=0;i--){
行=(字节[])raster.getDataElements(0,i,image.getWidth(),1,行);
输出。写入(行);
}
返回output.toByteArray();
}
公共静态vo
// ---
...
// put the bytes R G B into the data; lines of the bitmap must be from bottom line to top line
int bytes = 0;
Raster raster = image.getData();
for (short y = (short)(height - 1); y >= 0; y--) {
for (short x = 0; x < width; x++) {
int r = raster.getSample(x, y, 2);
data.add(Byte.valueOf((byte)r));
bytes++;
int g = raster.getSample(x, y, 1);
data.add(Byte.valueOf((byte)g));
bytes++;
int b = raster.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++;
}
}
...
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ByteArrayOutputStream;
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.record.ContinueRecord;
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.image.Raster;
import java.awt.Graphics2D;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.imageio.ImageIO;
public class CreateExcelHSSFSheetBackgroundBMP {
static byte[] getBackgroundBitmapData(String filePath) throws Exception {
// see https://www.openoffice.org/sc/excelfileformat.pdf - 5.6 BITMAP
// and https://interoperability.blob.core.windows.net/files/MS-XLS/[MS-XLS].pdf - 2.4.19 BkHim
// 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);
// size 12 bytes (additional headers, see below) + picture bytes
int size = 12 + height * widthBytesMultOf4;
// create the header section
ByteBuffer headers = ByteBuffer.allocate(20);
headers.order(ByteOrder.LITTLE_ENDIAN);
headers.putShort((short)0x09); // 0x0009 = signed integer that specifies the image format BMP
headers.putShort((short)0x01); // reserved (2 bytes): MUST be 0x0001
headers.putInt(size); // signed integer that specifies the size of imageBlob in bytes
// BMP header section:
headers.putInt(0x0C); // length 0x0C = 12 bytes
headers.putShort(width); // pixels width
headers.putShort(height); // pixels heigth
headers.putShort((short)0x01); // number of planes: always 1
headers.putShort((short)0x18); // color depth 0x018 = 24 bit
//create data ByteArrayOutputStream
ByteArrayOutputStream data = new ByteArrayOutputStream();
// write headers section
data.write(headers.array());
// put the bytes R G B into the data; lines of the bitmap must be from bottom line to top line
Raster raster = image.getData();
for (short y = (short)(height - 1); y >= 0; y--) {
for (short x = 0; x < width; x++) {
int r = raster.getSample(x, y, 2);
data.write((byte)r);
int g = raster.getSample(x, y, 1);
data.write((byte)g);
int b = raster.getSample(x, y, 0);
data.write((byte)b);
}
// fill up x with 0 bytes up to multiple of 4
for (int x = width * 3; x < widthBytesMultOf4; x++) {
data.write((byte)0);
}
}
return data.toByteArray();
}
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
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.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.getClass());
}
// write out workbook
FileOutputStream out = new FileOutputStream("CreateExcelHSSFSheetBackgroundBMP.xls");
workbook.write(out);
workbook.close();
out.close();
}
static class BitmapRecord extends StandardRecord {
// see https://www.openoffice.org/sc/excelfileformat.pdf - 5.6 BITMAP
// and https://interoperability.blob.core.windows.net/files/MS-XLS/[MS-XLS].pdf - 2.4.19 BkHim
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);
}
}
}
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);
}
}
}