java识别psd文件笔记

前言

最近在做网盘的一些需求
需要预览一些奇奇怪怪的文件
先记录下psd文件如何生成预览图

例子

由于jdk的ImageIO相关class 无法直接解析psd 所以要另寻方案

直接解析psd

参考文档: https://blog.csdn.net/WASONE_WU/article/details/27695723

直接按照psd文件格式进行解析 具体的参考文档博文


import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class PsdReader {

    private BufferedImage img = null;

    private int[] pixels;

    private RandomAccessFile raf;
    private int[] byteArray;
    //用来接住unsignedByte,byte不存作负数(否则抛异常,说越过颜色范围)
    private int[][][] channelColor;
    private int[][] numOfBytePerLine;
    //	private final static int RED = 0;
//	private final static int GREEN = 1;
//	private final static int BLUE = 2;
    private short numOfChannel;
    private int height;
    private int width;
    private short isRle;
    private MappedByteBuffer mbbi;

    public PsdReader(File file) {
        FileChannel fc = null;
        try {
            this.raf = new RandomAccessFile(file, "r");
            fc = raf.getChannel();
            long size = 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 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        pixels = new int[width*height];
        this.initPixels(pixels);
        this.setRGB(img, 0, 0, width, height, pixels);
        try {
            fc.close();
            this.raf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public BufferedImage getImg() {
        return img;
    }

    private void initPixels(int[] pixels) {
        int index = 0;
        int a = 255;
        for(int h=0; h<this.height; h++) {
            for(int w=0; w<this.width; w++) {
                int r = this.channelColor[0][h][w];
                int g = this.channelColor[1][h][w];
                int b = 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++;
            }
        }
    }

    private void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
        int type = 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 );
    }

    private void readFile() {
        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();
            short depth = this.mbbi.getShort();
            //System.out.println("depth="+depth);
            //是rgb模式则type=3
//			short type = this.raf.readShort();
            short type = this.mbbi.getShort();
            //System.out.println("type="+type);
            //--------第二部分:色彩模式信息,这部分的长度通常为0----
//			int lenOfColorModel = raf.readInt();
            int lenOfColorModel = 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();
            int lenOfImageResourceBlock = 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();
            int lenOfLayerInfo = 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 = new int[numOfChannel][height][width];
        if(isRle==1){
            this.numOfBytePerLine = new int[numOfChannel][height];
            for(int i=0; i<numOfChannel; i++) {
                for(int j=0; j<height; j++) {
                    try {
                        //TODO
//					this.numOfBytePerLine[i][j] = this.raf.readUnsignedShort();
                        int ti = this.mbbi.getShort();
                        if(ti<0) { ti += 65536; }
                        this.numOfBytePerLine[i][j] = ti;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            for(int c=0; c<numOfChannel; c++) {
                for(int h=0; h<height; h++) {
                    this.unpackbits(numOfBytePerLine[c][h],channelColor[c][h]);
                }
            }
        }else if(isRle==0) {
            for(int c=0; c<numOfChannel; c++) {
                for(int h=0; h<height; h++) {
                    for(int w=0; w<width; w++) {
                        try {
//							this.channelColor[c][h][w] = this.raf.readUnsignedByte();
                            int ti = this.mbbi.get();
                            if(ti<0) { ti += 256; }
                            this.channelColor[c][h][w] = ti;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private void unpackbits(int lenOfInput, int[] channelColor) {
        short n = 0;
        int last = 0;

        while(lenOfInput>0){
            try {
//			n = raf.readByte();
                n = this.mbbi.get();
                lenOfInput--;
            } catch (Exception e) {
                e.printStackTrace();
            }

            if(0<=n && n<=127) {
                int repeatTime = n;
                ++repeatTime;
                for(int t=0; t<repeatTime; t++) {
                    try {
//					channelColor[last+t] = raf.readUnsignedByte();
                        int ti = this.mbbi.get();
                        if(ti<0) { ti += 256; }
                        channelColor[last+t] = ti;

                        lenOfInput--;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                last += repeatTime;
            }
            else if(-1>=n && n>=-127) {
                int val = 0;
                int repeatTime = -n;
                ++repeatTime;
                try {
//				val = raf.readUnsignedByte();
                    int ti = this.mbbi.get();
                    if(ti<0) { ti += 256; }
                    val = ti;
                    //System.out.println(val);
                    lenOfInput--;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                for(int t=0; t<repeatTime; t++) {
                    channelColor[last+t] = val;
                }
                last += repeatTime;
            }
            else if(n==-128) {
                //noop
            }
        }
    }
}

import net.coobird.thumbnailator.Thumbnails;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class main {
    public static void main(String[] args) throws IOException {
        long now = System.currentTimeMillis();
        PsdReader psdReader = new PsdReader(new File("02.psd"));
        BufferedImage bufferedImage = psdReader.getImg();
        ImageIO.write(bufferedImage,"png",new File("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

   <!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.14</version>
</dependency>

<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-core</artifactId>
    <version>3.6.4</version>
</dependency>
        <!-- https://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-psd -->
<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-psd</artifactId>
    <version>3.6.4</version>
</dependency>
import net.coobird.thumbnailator.Thumbnails;

import java.io.File;
import java.io.IOException;

public class main {
    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        try {
            Thumbnails.of(new File("03.psd"))
                    .size(1080, 720)
                    .toFile(new File("03.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println((System.currentTimeMillis() - now));
    }
}
Aspose.psd for java

参考文档: https://downloads.aspose.com/psd/java


<repository>
    <id>AsposeJavaAPI</id>
    <name>Aspose Java API</name>
    <url>http://repository.aspose.com/repo/</url>
</repository>

。。。。。


<dependency>
    <groupId>com.aspose</groupId>
    <artifactId>aspose-psd</artifactId>
    <version>20.9</version>
    <classifier>jdk16</classifier>
</dependency>
import net.coobird.thumbnailator.Thumbnails;

import java.io.File;
import java.io.IOException;

public class main {
    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        // Load image
        Image img = Image.load("03.psd");
        //按需选择不同类型options 例如 png pdf jpeg等等
        PngOptions options = new PngOptions();
        // 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 读取、打水印乱七八糟的操作 都可以简单直接快速处理

© 2024 ming博客. All rights reserved.基于rust salvo性能猛的很!