通常这只是程序员自己的愚蠢;—)。在德语中有一句谚语:“看不见森林是因为有树。”。
Raster
的
BufferedImage
一次又一次地跳出环路而不是进入环路,会极大地提高速度:
...
// 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++;
}
}
...
这个
BkHim公司
记录指定纸张(1)背景的图像数据
cf(2字节)
:指定图像格式的有符号整数。必须是以下值:
值:0x0009
意思:位图格式。图像数据以位图格式存储,如[MSDN-BMP]所述
值:0x000E
意思:本机格式。图像数据以另一个应用程序的本机格式存储,不能直接处理。
0x000E
第一个字节而不是
0x0009
然后可以直接存储本地图片字节(PNG、JPG、BMP……)。明天试试这个。
嗯,微软的“文档”往往只是徒劳的努力。这个
https://interoperability.blob.core.windows.net/files/MS-XLS/[MS-XLS].pdf
打他。所以使用
0x000E
而不是
0x0009
不会简单地允许存储本机
imageBlob
0x0009
位图格式。图像数据以位图格式存储,如中所述
[MSDN-BMP]
只有链接到什么样的位图必须在这里使用不完整的描述。没有关于头结构的开始和像素字节从底线到顶行。而且也不需要在最后一个像素后插入零字节,将每行的大小调整为4的倍数。但即使使用位图也不知道这些
0x0009
不起作用。
当我把任何一种背景图像放进工作表中
*.xls
Excel
的GUI,然后使用十六进制转储查看该文件,则始终如下所示:
e900型
09000100
SSSSSSSS
0亿
wwwhhh
01001800
购买力平价。。。
https://www.openoffice.org/sc/excelfileformat.pdf
比微软的“文档”更有用。
所以下面的代码将背景图像放入
HSSFSheet
适用于我测试多种不同类型的图像文件(BMP、PNG、JPG)。
也改变了使用
List<Byte> data
到
byte[] data
. 所以呢
org.apache.poi.hssf.record.ContinueRecord
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);
}
}
}