java识别psd文件笔记
发表于 2021-04-09 | 更新于 2021-10-11 | 分类于 笔记 | 评论数: 0 | 阅读次数:
前言
最近在做网盘的一些需求
需要预览一些奇奇怪怪的文件
先记录下psd文件如何生成预览图
例子
由于jdk的ImageIO相关class 无法直接解析psd 所以要另寻方案
直接解析psd
参考文档: https://blog.csdn.net/WASONE_WU/article/details/27695723
直接按照psd文件格式进行解析 具体的参考文档博文
importjava.awt.image.BufferedImage;
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.io.RandomAccessFile;
importjava.nio.MappedByteBuffer;
importjava.nio.channels.FileChannel;
publicclassPsdReader{
privateBufferedImage img =null;
privateint[] pixels;
privateRandomAccessFile raf;
privateint[] byteArray;
//用来接住unsignedByte,byte不存作负数(否则抛异常,说越过颜色范围)
privateint[][][] channelColor;
privateint[][] numOfBytePerLine;
// private final static int RED = 0;
// private final static int GREEN = 1;
// private final static int BLUE = 2;
privateshortnumOfChannel;
privateintheight;
privateintwidth;
privateshortisRle;
privateMappedByteBuffer mbbi;
publicPsdReader(File file){
FileChannel fc =null;
try{
this.raf =newRandomAccessFile(file,"r");
fc = raf.getChannel();
longsize = fc.size();
this.mbbi = fc.map(FileChannel.MapMode.READ_ONLY,0, size);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}
this.readFile();
img =newBufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
pixels =newint[width*height];
this.initPixels(pixels);
this.setRGB(img,0,0, width, height, pixels);
try{
fc.close();
this.raf.close();
}catch(IOException e) {
e.printStackTrace();
}
}
publicBufferedImagegetImg(){
returnimg;
}
privatevoidinitPixels(int[] pixels){
intindex =0;
inta =255;
for(inth=0; h
for(intw=0; w
intr =this.channelColor[0][h][w];
intg =this.channelColor[1][h][w];
intb =this.channelColor[2][h][w];
if(this.numOfChannel>3) {
a =this.channelColor[3][h][w];
}
pixels[index] = (a<<24) | (r<<16)
| (g<<8) | b;
index++;
}
}
}
privatevoidsetRGB( BufferedImage image,intx,inty,intwidth,intheight,int[] pixels ){
inttype = image.getType();
if( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
image.getRaster().setDataElements( x, y, width, height, pixels );
else
image.setRGB( x, y, width, height, pixels,0, width );
}
privatevoidreadFile(){
try{
//-------第一部分:文件头------------------
//通道数量
// this.raf.seek(0x0c);
this.mbbi.position(0x0c);
// numOfChannel = this.raf.readShort();
numOfChannel =this.mbbi.getShort();
//System.out.println("numOfChannel="+numOfChannel);
//图像高度
// height = this.raf.readInt();
height =this.mbbi.getInt();
//System.out.println("height="+height);
//图像宽度
// width = this.raf.readInt();
width =this.mbbi.getInt();
//System.out.println("width="+width);
//图像深度(每个通道的颜色位数)
// short depth = this.raf.readShort();
shortdepth =this.mbbi.getShort();
//System.out.println("depth="+depth);
//是rgb模式则type=3
// short type = this.raf.readShort();
shorttype =this.mbbi.getShort();
//System.out.println("type="+type);
//--------第二部分:色彩模式信息,这部分的长度通常为0----
// int lenOfColorModel = raf.readInt();
intlenOfColorModel =this.mbbi.getInt();
//System.out.println("lenOfColorModel="+lenOfColorModel);
// this.raf.seek(lenOfColorModel+this.raf.getFilePointer());//长度信息占4个字节,但是不用加,下同
this.mbbi.position(lenOfColorModel+this.mbbi.position());
//--------第三部分:图像资源数据------------------
// int lenOfImageResourceBlock = raf.readInt();
intlenOfImageResourceBlock =this.mbbi.getInt();
//System.out.println("lenOfImageResourceBlock="+lenOfImageResourceBlock);
// this.raf.seek(lenOfImageResourceBlock+this.raf.getFilePointer());
this.mbbi.position(lenOfImageResourceBlock+this.mbbi.position());
//--------第四部分:图层与蒙版信息----------------
// int lenOfLayerInfo = raf.readInt();
intlenOfLayerInfo =this.mbbi.getInt();
//System.out.println("lenOfLayer="+lenOfLayerInfo);
// this.raf.seek(lenOfLayerInfo+raf.getFilePointer());
this.mbbi.position(lenOfLayerInfo+this.mbbi.position());
//--------第五部分:图像数据--------------------
// isRle = raf.readShort();
isRle =this.mbbi.getShort();
//System.out.println("isRle="+isRle);
// //System.out.println("nowPosition="+this.raf.getFilePointer());
//System.out.println("nowPosition="+this.mbbi.position());
}catch(Exception e1) {
e1.printStackTrace();
}
this.channelColor =newint[numOfChannel][height][width];
if(isRle==1){
this.numOfBytePerLine =newint[numOfChannel][height];
for(inti=0; i
for(intj=0; j
try{
//TODO
// this.numOfBytePerLine[i][j] = this.raf.readUnsignedShort();
intti =this.mbbi.getShort();
if(ti<0) { ti +=65536; }
this.numOfBytePerLine[i][j] = ti;
}catch(Exception e) {
e.printStackTrace();
}
}
}
for(intc=0; c
for(inth=0; h
this.unpackbits(numOfBytePerLine[c][h],channelColor[c][h]);
}
}
}elseif(isRle==0) {
for(intc=0; c
for(inth=0; h
for(intw=0; w
try{
// this.channelColor[c][h][w] = this.raf.readUnsignedByte();
intti =this.mbbi.get();
if(ti<0) { ti +=256; }
this.channelColor[c][h][w] = ti;
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
}
}
privatevoidunpackbits(intlenOfInput,int[] channelColor){
shortn =0;
intlast =0;
while(lenOfInput>0){
try{
// n = raf.readByte();
n =this.mbbi.get();
lenOfInput--;
}catch(Exception e) {
e.printStackTrace();
}
if(0<=n && n<=127) {
intrepeatTime = n;
++repeatTime;
for(intt=0; t
try{
// channelColor[last+t] = raf.readUnsignedByte();
intti =this.mbbi.get();
if(ti<0) { ti +=256; }
channelColor[last+t] = ti;
lenOfInput--;
}catch(Exception e) {
e.printStackTrace();
}
}
last += repeatTime;
}
elseif(-1>=n && n>=-127) {
intval =0;
intrepeatTime = -n;
++repeatTime;
try{
// val = raf.readUnsignedByte();
intti =this.mbbi.get();
if(ti<0) { ti +=256; }
val = ti;
//System.out.println(val);
lenOfInput--;
}catch(Exception e) {
e.printStackTrace();
}
for(intt=0; t
channelColor[last+t] = val;
}
last += repeatTime;
}
elseif(n==-128) {
//noop
}
}
}
}
importnet.coobird.thumbnailator.Thumbnails;
importjavax.imageio.ImageIO;
importjava.awt.image.BufferedImage;
importjava.io.File;
importjava.io.IOException;
publicclassmain{
publicstaticvoidmain(String[] args)throwsIOException{
longnow = System.currentTimeMillis();
PsdReader psdReader =newPsdReader(newFile("02.psd"));
BufferedImage bufferedImage = psdReader.getImg();
ImageIO.write(bufferedImage,"png",newFile("02.png"));
System.out.println((System.currentTimeMillis() - now));
}
}
twelvemonkeys + thumbnailator
参考文档:
https://www.cnblogs.com/interdrp/p/7076202.html
https://github.com/haraldk/TwelveMonkeys
https://github.com/coobird/thumbnailator
利用twelevemonkeys提供对ImageIo的增强直接读取 psd
net.coobird
thumbnailator
0.4.14
com.twelvemonkeys.imageio
imageio-core
3.6.4
com.twelvemonkeys.imageio
imageio-psd
3.6.4
importnet.coobird.thumbnailator.Thumbnails;
importjava.io.File;
importjava.io.IOException;
publicclassmain{
publicstaticvoidmain(String[] args){
longnow = System.currentTimeMillis();
try{
Thumbnails.of(newFile("03.psd"))
.size(1080,720)
.toFile(newFile("03.png"));
}catch(IOException e) {
e.printStackTrace();
}
System.out.println((System.currentTimeMillis() - now));
}
}
Aspose.psd for java
参考文档: https://downloads.aspose.com/psd/java
AsposeJavaAPI
Aspose Java API
http://repository.aspose.com/repo/
。。。。。
com.aspose
aspose-psd
20.9
jdk16
importnet.coobird.thumbnailator.Thumbnails;
importjava.io.File;
importjava.io.IOException;
publicclassmain{
publicstaticvoidmain(String[] args){
longnow = System.currentTimeMillis();
// Load image
Image img = Image.load("03.psd");
//按需选择不同类型options 例如 png pdf jpeg等等
PngOptions options =newPngOptions();
// Convert PSD to png
img.save("03.png", options);
System.out.println((System.currentTimeMillis() - now));
}
}
总结
如果要直接粗暴读取 直接按照psd 格式硬读取即可
如果有其他的一些需求 建议 twelvemonkeys + thumbnailator组合 不仅仅是读取psd 还可以做一些奇奇怪怪的事情
Aspose.psd for java方案的话 如果是部署在windows下 可以使用 如果要部署linux下 需要将windows字体库安装到linux下 否则会报错
个人建议还是 twelvemonkeys + thumbnailator 读取、打水印乱七八糟的操作 都可以简单直接快速处理
------ 本文结束 ------