Psd文件解析出来的图层对象Layer,无法序列化

现场景就是,源PSD文件解析出来,我想保存每个图层的序列化值,下次对该图层编辑时,只需要直接反序列化Layer对象,进行操作。而目前的情况是,PsdImage、Layer对象都无法序列化,即使通过Gson.toString浅度复制,再反序列化时,无法还原其原对象,所以只能每次读取源解析。只因为解析psd文件太消耗性能了,而且效率也低。平均1个10M+的PSD文件解析,需要14s平均。
PS:1.PsdImage、Layer无法尝试clone序列化、反序列化原对象; 2.Psd文件解析慢,1个10M+的Psd文件平均解析时间达到14秒左右。

@xielong

您的要求是要获得对PSD图像层进行序列化的支持吗?

恩是的,基于图层对象的序列化,使其下次,可以反序列化原图层对象,进行图层的操作。

获取 Outlook for iOS

@xielong

您能否详细说明要求,以便我可以在我们的问题跟踪系统中添加调查凭单。 目前,该支持在API中不可用。

场景:首次解析出psd源文件,得到psdImage对象,layer对象列表,将其序列化字节码,存储至数据库中。而后所有的操作,都是基于单图层对象,所以希望从数据库中读取出layer的序列化字节码能够将其反序列化为源layer类对象,进行操作。要不然的话,每次都得解析,遍历图层列表,定位到某一层进行操作,影响性能和效率。如果对象支持序列化,和反序列化源对象还原的话,我就可以将其存储数据库中了。现该api不支持此场景,只能操作一次,解析加载一次遍历操作。比如,多人操作同一psd文件,你就必须加载解析多次,如果对象对白露塘序列化存储,只需解析一次存储对象序列化字节码,后面所有的操作都只需读取字节码反序列化源对象,进行其操作即可,然后再组装还原反序列化为psdImage源对象即可。

获取 Outlook for iOS

场景:首次解析出psd源文件,得到psdImage对象,layer对象列表,将其序列化字节码,存储至数据库中。而后所有的操作,都是基于单图层对象,所以希望从数据库中读取出layer的序列化字节码能够将其反序列化为源layer类对象,进行操作。要不然的话,每次都得解析,遍历图层列表,定位到某一层进行操作,影响性能和效率。如果对象支持序列化,和反序列化源对象还原的话,我就可以将其存储数据库中了。现该api不支持此场景,只能操作一次,解析加载一次遍历操作。比如,多人操作同一psd文件,你就必须加载解析多次,如果对象支持序列化存储,只需解析一次存储对象序列化字节码,后面所有的操作都只需读取字节码反序列化源对象,进行其操作即可,然后再组装还原反序列化为psdImage源对象即可。

获取 Outlook for iOS

@xielong
目前,API中不提供所请求的支持。 我已经在我们的问题跟踪系统中创建了一个ID为PSDNET-850的票证,以进一步调查提供请求的支持的可能性。 该线程已与问题联系在一起,因此一旦支持可用,您可能会收到通知。

收到,非常感谢

获取 Outlook for iOS

@xielong

随时欢迎你

您好,请问下问题跟踪系统中的,问题单,大概何时可以得到解决?因我们这边产品比较紧急,所以想确认下具体的时间,一切都得以解决的话,我们就要开始走付费购买以及付费技术支持等商务合同事宜了。

@jsczxielong

Now we support serialization only simple data of layer, so serialization/deserialization can work only for simple layers(without effects or any other dependencies from image global resources).

The following code example will make bytes from layer and move it to other PsdImage:

            string src1 = "testFile1.psd";
            string src2 = "testFile2.psd";
            string output2 = "out_testFile2.psd";

            using (var image1 = (PsdImage)Image.Load(src1))
            {
                byte[] layerBytes;
                using (MemoryStream layerMem = new MemoryStream())
                {
                    image1.Layers[1].Save(layerMem, new PsdOptions());
                    layerBytes = layerMem.ToArray();
                }

                using (var image2 = (PsdImage)Image.Load(src2))
                {
                    using (MemoryStream layerMem = new MemoryStream(layerBytes))
                    {
                        Layer copiedLayer = new Layer(layerMem);
                        image2.AddLayer(copiedLayer);
                    }

                    image2.Save(output2);
                }
            }

image.png (24.3 KB)
实际没看到有此方法

请问是,最aspose-psd.jar(20.9)这版本?

groupLayer序列化还是有问题,请问下,此问题可以解决修复?
image.png (9.8 KB)

@jsczxielong

请共享有效的示例代码和重现此问题的实际源文件。 我们将尽力对此进行调查,以进一步为您提供帮助。

您好,单图层也可实际序列化、反序列化。现最大的问题,就是,是否有支持:PsdImage image =(PsdImage) Image.load(sourceFileName,loadOptions);对整个PsdImage序列化、反序列化?我们的场景,就是希望,只load一次源psd文件,而后序列化成byte[]字节持久化存储,下次再进行图层编辑时,只需反序列化原对象即可。因为现最大的性能消耗,主要就是loadPsd源文件,非常吃性能。

如若官方团队,loadpsd到输出png整个过程,时间性能上可以缩小到3~5秒内,那实际应用倒也是可以接受。但实际的运行效果下来,就最标准的loadpsd到存储 png图片就需要将近10秒左右。
1.代码:
public static void main(String[] args) throws FileNotFoundException
{

    License license = new License();
    String licFileDir = "E:\\mysite\\openproj\\Aspose.PSD-for-Java\\Examples\\src\\main\\resources\\Lic\\Aspose.Total.Product.Family.lic";
    license.setLicense(licFileDir);

    long startTime = System.currentTimeMillis();    //获取开始时间

    String dataDir = "E:\\mysite\\openproj\\Aspose.PSD-for-Java\\Examples\\src\\main\\resources\\PSD\\";
    Cache.setCacheFolder(dataDir);
    // Set cache on disk.
    Cache.setCacheType(CacheType.CacheInMemoryOnly);
    // The default cache max value is 0, which means that there is no upper limit
    Cache.setMaxMemoryForCache(1073741824); // 1 gigabyte
    // We do not recommend that you change the following property because it may greatly affect performance
    Cache.setExactReallocateOnly(false);

    String sourceFileName = dataDir+ "nvwang.psd";
    String exportPath = dataDir+ "nvwangBakNew1.png";
    PsdLoadOptions loadOptions = new PsdLoadOptions();
    PsdImage image =(PsdImage) Image.load(sourceFileName,loadOptions);
    PngOptions options = new PngOptions();
    options.setCompressionLevel(Compression.NONE.getValue());
    options.setColorType(PngColorType.TruecolorWithAlpha);
    image.save(exportPath,options);
    long endTime = System.currentTimeMillis();    //获取结束时间

    System.out.println("程序运行时间:" + (endTime - startTime)/1000 + "s");    //输出程序运行时间
}

2.实际运行效果:
image.png (25.7 KB)

3.源文件:
nvwangcopy.zip (118.8 KB)

所以,我们就想到了,是否有支持PsdImage整个对象的序列化、反充列化,以及Layer图层的序列化、反序列化。从而达到间接提升性能。

能否请您解释一下。 该API支持从MemoryStream加载PSD和将PSD保存到MemoryStream。 如果要将PSD保留为字节数组,可以将PSD保存为流,然后从Stream中将其另存为字节数组到持久性存储中。 同样,如果要加载字节数组,可以将字节数组转换为MemoryStream,然后加载它。 如果这不是您想要的,请解释一下您希望Aspose.PSD为您提供的内容。

恩,可否提供示例代码。谢谢

获取 Outlook for iOS

你好,实际我们这边验证了。可以序列化,但是无法反序列化为原对象。
1.源代码:
public static void main(String[] args) throws FileNotFoundException {
License license = new License();
String licFileDir = “E:\mysite\openproj\Aspose.PSD-for-Java\Examples\src\main\resources\Lic\Aspose.Total.Product.Family.lic”;
license.setLicense(licFileDir);

    String dataDir = "E:\\mysite\\openproj\\Aspose.PSD-for-Java\\Examples\\src\\main\\resources\\PSD\\";

    String sourceFileName = dataDir + "6d006ea3baa81d8cba9f25ce56a2c970.psd";
    String exportPath = dataDir + "nvwangNewITextPortion.png";

    PsdLoadOptions loadOptions = new PsdLoadOptions();

    PsdImage image1 =(PsdImage) Image.load(sourceFileName,loadOptions);

    byte[] layerBytes;
    MemoryStream layerMem = new MemoryStream();
    OutputStream dstStream = layerMem.toOutputStream();
    image1.save(dstStream, new PsdOptions());
    layerBytes = layerMem.toArray();
    //layerMem = new MemoryStream(layerBytes);
    InputStream inputStream = new ByteArrayInputStream(layerBytes);
    PsdImage image = new PsdImage(inputStream);

    for(int i=0; i < image.getLayers().length; i++ )
    {
        Layer layer = (Layer) image.getLayers()[i];
        System.out.println(i + "DisplayName:" + layer.getDisplayName() + "name:" + layer.getName());

        if (i == 10 && image.getLayers()[i] instanceof TextLayer)
        {
            TextLayer textLayer = (TextLayer)image.getLayers()[i];
            //IText textData = textLayer.getTextData();
            //System.out.println("textData producePortion text:"+textData.producePortion().getText());
            //方案一.直接获取producePortion对象修改文本:报错Line break '\r' character can be only in the end of text
            //textData.producePortion().setText("靠你就是我的你的");
            //方案二.创建新ITextPortion
            //ITextStyle defaultStyle = textData.producePortion().getStyle();
            //defaultStyle.setFillColor(textLayer.getTextColor());
            //defaultStyle.setFontSize(textLayer.getFont().getSize());
            //ITextParagraph defaultParagraph = textData.producePortion().getParagraph();

            /*textData.getItems()[1].getStyle().setStrikethrough(true);
            ITextPortion[] newTextPortions = textData.producePortions(new String[] {
                            "E=mc",  "2\r",  "Bold",  "Italic\r",  "Lowercasetext" },
                    textData.producePortion().getStyle(), textData.producePortion().getParagraph());
            newTextPortions[0].getStyle().setUnderline(true); // edit text style of "E=mc"
            newTextPortions[1].getStyle().setFontBaseline(FontBaseline.Superscript); // edit text style of "2\r"
            newTextPortions[2].getStyle().setFauxBold(true); // edit text style of "Bold"
            newTextPortions[3].getStyle().setFauxItalic(true); // edit text style of "Italic\r"
            newTextPortions[3].getStyle().setBaselineShift(-25); // edit text style of "Italic\r"
            newTextPortions[4].getStyle().setFontCaps(FontCaps.SmallCaps); // edit text style of "Lowercasetext"
            for (ITextPortion newTextPortion : newTextPortions)
            {
                textData.addPortion(newTextPortion);
            }
            textData.updateLayerData();*/

            Point leftTopCoordinate = new Point();
            leftTopCoordinate.setX(textLayer.getLeft());
            leftTopCoordinate.setY(textLayer.getTop());
            textLayer.updateText("我的你的", leftTopCoordinate, textLayer.getFont().getSize(), textLayer.getTextColor());

        }
    }
    PngOptions options = new PngOptions();
    options.setColorType(PngColorType.TruecolorWithAlpha);

    image.save(exportPath,options);
}

2.运行结果:
nvwangNewITextPortion.jpg (1.5 MB)

3.实际期望(源psd文本层文字有替换):
nvwangNewITextPortion1.jpg (1.5 MB)

4.psd源文件"
nvwangJy.zip (2.6 MB)