原文链接
https://code.google.com/archive/p/javastruct/wikis/example_photoshop_acb_file_reader_writer.wiki
翻译用工具
翻译使用的是个人免费版Transmate
译文
如何使用JavaStruct读写Adobe Photoshop Color book文件
JavaStruct对于读写特定的二进制文件也是非常理想的。在这个例子中,我们将写一个 Photoshop Color book 文件读写器。这种文件格式的细节可在这里找到。
完整的代码请到:http://javastruct.googlecode.com/svn/trunk/javastruct/samples/photoshop/
备注:我注意到使用一个nio ByteBuffer写这样一个读写器并不是非常困难(可能更短)。但是JavaStruct提供了更清晰,可维护性更好的代码。并且如果有许多的二进制文件或消息,处理解封包将是非常容易引入错误的。
文件头
在头部,有一个特定的字符串字段. ±-------±----------------------//----------------------------------------+ | Length | UTF-16 Characters \ | ±-------±----------------------//----------------------------------------+
这样首先我们需要将这些字符串用一个特别的结构类表示,姑且叫 A 结构体。我们使用数组长度标记来声明。
@StructClass
public class AString {
@StructField (order = 0 )
@ArrayLengthMarker (fieldName = "chars")
public int length;
@StructField (order = 1)
public char[] chars;
public AString(String content){
this.length = content.length();
this.chars = content.toCharArray();
}
...
}
下面是实际的头。
@StructClass
public class ACBHeader {
public static final short RGB = 0;
public static final short CMYK = 2;
public static final short LAB = 7;
// 签名通常是ASCII字符串“8BCB"
@StructField (order = 0)
public byte[] signature = {'8', 'B', 'C', 'B'};
//Photoshop 7 仅打开版本为1(0x0001)的文件
@StructField (order = 1)
public short fileVersion;
// 唯一识别符
@StructField (order = 2)
public short colorBookIdentifier;
@StructField (order = 3)
public AString title;
@StructField (order = 4)
public AString colorNamePrefix;
@StructField (order = 5)
public AString colorNamePostfix;
// 通常是一个版权声明
@StructField (order = 6)
public AString description;
@StructField (order = 7)
public short colorCount;
// Photoshop 每页显示颜色数.这个字段指定了
// 能够在一个页面上显示的颜色的最大数量.
@StructField (order = 8)
public short colorsPerPage;
@StructField (order = 9)
public short pageSelectorOffset;
// RGB, CMYK or Lab
@StructField (order = 10)
public short colorSpaceID;
...
读取颜色
这里是比较棘手的部分。通过格式化,颜色值和它的格式是依赖于 colorSpaceID 字段。其可以是RGB,CMYK或者Lab。这样我们对每一个颜色域写一个类。这里有颜色数据的”colorCount"数量值。
@StructClass
public class RGBColor{
@StructField (order = 0)
public AString name;
@StructField (order = 1)
public byte[] code = new byte[6];
@StructField (order = 2)
public byte red;
@StructField (order = 3)
public byte green;
@StructField (order = 4)
public byte blue;
...
}
@StructClass
public class LabColor {
@StructField (order = 0)
public AString name;
@StructField (order = 1)
public byte[] code = new byte[6];
@StructField (order = 2)
public byte lightness;
@StructField (order = 3)
public byte aChrom;
@StructField (order = 4)
public byte bChrom;
...
}
注意对于每个颜色类都包含名字和编码字段。这是必要的,因为当前结构体类并不是从一个结构体基类派生的。
读写器
为了读和写acb文件,我们初始化了包含FileStream的StructPacker和StructUnpacker类。之后,读文件头和颜色值就直截了当。
public class AdobeColorBook {
ACBHeader header;
RGBColor[] rgbColors = null;
CMYKColor[] cmykColors = null;
LabColor[] labColors = null;
public void read(String acbFile){
try {
FileInputStream fis = new FileInputStream(new File(acbFile));
header = new ACBHeader();
StructUnpacker up = JavaStruct.getUnpacker(fis, ByteOrder.BIG_ENDIAN);
up.readObject(header);
switch(header.ColorSpaceID){
case ACBHeader.RGB :
rgbColors = new RGBColor[header.colorCount];
for(int i=0; i<header.colorCount; i++){
rgbColors[i] = new RGBColor();
up.readObject(rgbColors[i]);
}
break;
case ACBHeader.CMYK :
cmykColors = new CMYKColor[header.colorCount];
for(int i=0; i<header.colorCount; i++){
cmykColors[i] = new CMYKColor();
up.readObject(cmykColors[i]);
}
break;
case ACBHeader.LAB :
labColors = new LabColor[header.colorCount];
for(int i=0; i<header.colorCount; i++){
labColors[i] = new LabColor();
up.readObject(labColors[i]);
}
break;
default:
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (StructException e) {
e.printStackTrace();
}
}
public void write(String name){
try{
FileOutputStream fo = new FileOutputStream(new File(name));
StructPacker packer = JavaStruct.getPacker(fo, ByteOrder.BIG_ENDIAN);
packer.writeObject(header);
switch(header.ColorSpaceID){
case ACBHeader.RGB :
for(RGBColor color : rgbColors){
packer.writeObject(color);
}
break;
case ACBHeader.CMYK :
for(CMYKColor color : cmykColors){
packer.writeObject(color);
}
break;
case ACBHeader.LAB :
for(LabColor color : labColors){
packer.writeObject(color);
}
break;
default:
}
fo.close();
} catch(StructException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public String toString(){
String str = "";
if (header != null){
str += header;
}
switch(header.ColorSpaceID){
case ACBHeader.RGB :
for(RGBColor color : rgbColors) {
str += color + "\n";
}
break;
case ACBHeader.CMYK :
for(CMYKColor color : cmykColors) {
str += color + "\n";
}
break;
case ACBHeader.LAB :
for(LabColor color : labColors) {
str += color + "\n";
}
break;
}
return str;
}
public static void main(String[] args) {
AdobeColorBook anpaBook = new AdobeColorBook();
anpaBook.read("ANPA Color.acb");
anpaBook.write("ANPA_my_Color.acb");
System.out.println(anpaBook);
}
}