Browse our Products

Aspose.Imaging for Java 19.11 - Release notes

KeySummaryCategory
IMAGINGJAVA-1431Implement Svg native resizeFeature
IMAGINGJAVA-1440Support for document conversion progressFeature
IMAGINGJAVA-1401Image is cropped and not clearly visible on exporting EPS to PDFEnhancement
IMAGINGJAVA-1429Implement missed methods getUsedFonts, getMissedFonts in MetaImage. These methods were required by customer and exists in old metafile engine.Enhancement
IMAGINGJAVA-1441Backport Aspose.Psd code to Aspose.Imaging Q2/2019Enhancement
IMAGINGJAVA-1455Failed to save image into write-only streamEnhancement
IMAGINGJAVA-1456Fix parallel DNG processingEnhancement
IMAGINGJAVA-1457Fix parallel EMF processingEnhancement
IMAGINGJAVA-1470SVG not properly converted to PngEnhancement

Public API changes:

Added APIs:

Please see corresponding cumulative API changes for Aspose.Imaging for .NET19.10 version

h2. Removed APIs:

Usage Examples:

IMAGINGJAVA-1431 Implement Svg native resize

 String[] fileNames = new String[]

        {

                "Logotype.svg",

                "sample_car.svg",

                "rg1024_green_grapes.svg",

                "MidMarkerFigure.svg",

                "embeddedFonts.svg"

        };

PointF[] scales = new PointF[]

        {

                new PointF(0.5f, 0.5f),

                new PointF(1f, 1f),

                new PointF(2f, 2f),

                new PointF(3.5f, 9.2f),

        };

for (String inputFile : fileNames)

{

    for (PointF scale : scales)

    {

        String outputFile = String.format(Locale.ENGLISH, "%s_%2.1f_%2.1f.png", inputFile, scale.getX(), scale.getY());

        Image image = Image.load(inputFile);

        try

        {

            image.resize((int)(image.getWidth() * scale.getX()), (int)(image.getHeight() * scale.getY()));

            image.save(outputFile, new PngOptions());

        }

        finally

        {

            image.close();

        }

    }

}

IMAGINGJAVA-1441 Backport Aspose.Psd code to Aspose.Imaging Q2/2019

 // Ability to convert PSD file to PSB and vice versa

String sourceFilePathPsb = "2layers.psb";

String outputFilePathPsd = "ConvertFromPsb.psd";

Image img = Image.load(sourceFilePathPsb);

try

{

    PsdOptions options = new PsdOptions((PsdImage)img);

    // options.setFileFormatVersion(FileFormatVersion.Psd); // Not correct!

    options.setPsdVersion(PsdVersion.Psd); // Correct

    img.save(outputFilePathPsd, options);

}

finally

{

    img.close();

}

String sourceFilePathPsd = "2layers.psd";

String outputFilePathPsb = "ConvertFromPsd.psb";

img = Image.load(sourceFilePathPsd);

try

{

    PsdOptions options = new PsdOptions((PsdImage)img);

    // options.setFileFormatVersion(FileFormatVersion.Psb); // Not correct!

    options.setPsdVersion(PsdVersion.Psb); // Correct

    img.save(outputFilePathPsb, options);

}

finally

{

    img.close();

}
 {

// Support of RGB Color mode with 16bits/channel (64 bits per color)

    String sourceFileName = "inRgb16.psd.psd";

    String outputFilePathJpg = "outRgb16.jpg";

    String outputFilePathPsd = "outRgb16.psd";

    PsdLoadOptions options = new PsdLoadOptions();

    PsdImage image = (PsdImage) Image.load(sourceFileName, options);

    try

    {

        image.save(outputFilePathPsd, new PsdOptions(image));

        image.save(outputFilePathJpg, new JpegOptions()

        {{

            setQuality(100);

        }});

    }

    finally

    {

        image.close();

    }

// Files must be opened without exception and must be readable for Photoshop

    Image im = Image.load(outputFilePathPsd);

    im.close();

}

{

// RotateFlip operation doesn't work as expected with PSD

    String sourceFile = "1.psd";

    String pngPath = "RotateFlipTest2617.png";

    String psdPath = "RotateFlipTest2617.psd";

    int flipType = RotateFlipType.Rotate270FlipXY;

    PsdImage im = (PsdImage) (Image.load(sourceFile));

    try

    {

        im.rotateFlip(flipType);

        im.save(pngPath, new PngOptions()

        {{

            setColorType(PngColorType.TruecolorWithAlpha);

        }});

        im.save(psdPath);

    }

    finally

    {

        im.close();

    }

}

{

// Add support of Fill layers: Pattern

    String sourceFileName = "PatternFillLayer.psd";

    String exportPath = "PatternFillLayer_Edited.psd";

    double tolerance = 0.0001;

    PsdImage im = (PsdImage) Image.load(sourceFileName);

    try

    {

        for (Layer layer : im.getLayers())

        {

            if (layer instanceof FillLayer)

            {

                FillLayer fillLayer = (FillLayer) layer;

                PatternFillSettings fillSettings = (PatternFillSettings) fillLayer.getFillSettings();

                if (fillSettings.getHorizontalOffset() != -46 ||

                        fillSettings.getVerticalOffset() != -45 ||

                        !fillSettings.getPatternId().equals("a6818df2-7532-494e-9615-8fdd6b7f38e5") ||

                        !fillSettings.getPatternName().equals("$$$/Presets/Patterns/OpticalSquares=Optical Squares") ||

                        !fillSettings.getAlignWithLayer() ||

                        !fillSettings.getLinked() ||

                        fillSettings.getPatternHeight() != 64 ||

                        fillSettings.getPatternWidth() != 64 ||

                        fillSettings.getPatternData().length != 4096 ||

                        Math.abs(fillSettings.getScale() - 50) > tolerance)

                {

                    throw new AssertionError("PSD Image was read wrong");

                }

// Editing

                fillSettings.setScale(300);

                fillSettings.setHorizontalOffset(2);

                fillSettings.setVerticalOffset(-20);

                fillSettings.setPatternData(new int[]

                        {

                                Color.getRed().toArgb(), Color.getBlue().toArgb(), Color.getBlue().toArgb(),

                                Color.getBlue().toArgb(), Color.getRed().toArgb(), Color.getBlue().toArgb(),

                                Color.getBlue().toArgb(), Color.getBlue().toArgb(), Color.getRed().toArgb()

                        });

                fillSettings.setPatternHeight(3);

                fillSettings.setPatternWidth(3);

                fillSettings.setAlignWithLayer(false);

                fillSettings.setLinked(false);

                fillSettings.setPatternId(UUID.randomUUID().toString());

                fillLayer.update();

                break;

            }

        }

        im.save(exportPath);

    }

    finally

    {

        im.close();

    }

}

{

// Support of PtFlResource

    String sourceFileName = "PatternFillLayer.psd";

    String exportPath = "PtFlResource_Edited.psd";

    double tolerance = 0.0001;

    PsdImage im = (PsdImage) Image.load(sourceFileName);

    try

    {

        for (Layer layer : im.getLayers())

        {

            if (layer instanceof FillLayer)

            {

                FillLayer fillLayer = (FillLayer) layer;

                LayerResource[] resources = fillLayer.getResources();

                for (LayerResource res : resources)

                {

                    if (res instanceof PtFlResource)

                    {

// Reading

                        PtFlResource resource = (PtFlResource) res;

                        if (

                                resource.getOffset().getX() != -46 ||

                                        resource.getOffset().getY() != -45 ||

                                        !resource.getPatternId().equals("a6818df2-7532-494e-9615-8fdd6b7f38e5\0") ||

                                        !resource.getPatternName().equals("$$$/Presets/Patterns/OpticalSquares=Optical Squares\0") ||

                                        !resource.getAlignWithLayer() ||

                                        !resource.isLinkedWithLayer() ||

                                        !(Math.abs(resource.getScale() - 50) < tolerance))

                        {

                            throw new AssertionError("PtFl Resource was read incorrect");

                        }

// Editing

                        resource.setOffset(new Point(-11, 13));

                        resource.setScale(200);

                        resource.setAlignWithLayer(false);

                        resource.setLinkedWithLayer(false);

                        fillLayer.setResources(fillLayer.getResources());

// We haven't pattern data in PattResource, so we can add it.

                        PatternFillSettings fillSettings = (PatternFillSettings) fillLayer.getFillSettings();

                        fillSettings.setPatternData(new int[]

                                {

                                        Color.getBlack().toArgb(),

                                        Color.getWhite().toArgb(),

                                        Color.getWhite().toArgb(),

                                        Color.getWhite().toArgb(),

                                });

                        fillSettings.setPatternHeight(1);

                        fillSettings.setPatternWidth(4);

                        fillSettings.setPatternName("$$$/Presets/Patterns/VerticalLine=Vertical Line New\0");

                        fillSettings.setPatternId(UUID.randomUUID().toString() + "\0");

                        fillLayer.update();

                    }

                    break;

                }

                break;

            }

        }

        im.save(exportPath);

    }

    finally

    {

        im.close();

    }

}

{

// Implement correct Crop method for PSD files.

    String sourceFileName = "1.psd";

    String exportPathPsd = "CropTest.psd";

    String exportPathPng = "CropTest.png";

    RasterImage rasterImage = (RasterImage) Image.load(sourceFileName);

    try

    {

        rasterImage.crop(new Rectangle(10, 30, 100, 100));

        rasterImage.save(exportPathPsd, new PsdOptions());

        rasterImage.save(exportPathPng, new PngOptions()

        {{

            setColorType(PngColorType.TruecolorWithAlpha);

        }});

    }

    finally

    {

        rasterImage.close();

    }

}

{

// Newly added text layer position is shifted on editing in Photoshop

    String sourceFileName = "OneLayer.psd";

    String exportPath = "OneLayer_Edited.psd";

    int leftPos = 99;

    int topPos = 47;

    PsdImage im = (PsdImage) Image.load(sourceFileName);

    try

    {

        im.addTextLayer("Some text", new Rectangle(leftPos, topPos, 99, 47));

        TextLayer textLayer = (TextLayer) im.getLayers()[1];

        if (textLayer.getLeft() != leftPos || textLayer.getTop() != topPos)

        {

            throw new AssertionError("Was created incorrect Text Layer");

        }

// We can't test Transform Matrix with a public API,

// but if we start edit text layer in PSD we should get the same bounds as we created

        im.save(exportPath);

    }

    finally

    {

        im.close();

    }

}

{

// VsmsResource Support

    String sourceFileName = "EmptyRectangle.psd";

    String exportPath = "EmptyRectangle_changed.psd";

    PsdImage im = (PsdImage) Image.load(sourceFileName);

    try

    {

        VsmsResource resource = getVsmsResource(im);

// Reading

        VectorPathRecord[] paths = resource.getPaths();

        if (resource.isDisabled() ||

                resource.isInverted() ||

                resource.isNotLinked() ||

                paths.length != 7 ||

                paths[0].getType() != VectorPathType.PathFillRuleRecord ||

                paths[1].getType() != VectorPathType.InitialFillRuleRecord ||

                paths[2].getType() != VectorPathType.ClosedSubpathLengthRecord ||

                paths[3].getType() != VectorPathType.ClosedSubpathBezierKnotUnlinked ||

                paths[4].getType() != VectorPathType.ClosedSubpathBezierKnotUnlinked ||

                paths[5].getType() != VectorPathType.ClosedSubpathBezierKnotUnlinked ||

                paths[6].getType() != VectorPathType.ClosedSubpathBezierKnotUnlinked)

        {

            throw new AssertionError("VsmsResource was read wrong");

        }

        PathFillRuleRecord pathFillRule = (PathFillRuleRecord) paths[0];

        InitialFillRuleRecord initialFillRule = (InitialFillRuleRecord) paths[1];

        LengthRecord subpathLength = (LengthRecord) paths[2];

// Path fill rule doesn't contain any additional information

        if (pathFillRule.getType() != VectorPathType.PathFillRuleRecord ||

                initialFillRule.getType() != VectorPathType.InitialFillRuleRecord ||

                initialFillRule.isFillStartsWithAllPixels() ||

                subpathLength.getType() != VectorPathType.ClosedSubpathLengthRecord ||

                !subpathLength.isClosed() ||

                subpathLength.isOpen())

        {

            throw new AssertionError("VsmsResource paths were read wrong");

        }

// Editing

        resource.setDisabled(true);

        resource.setInverted(true);

        resource.setNotLinked(true);

        BezierKnotRecord bezierKnot = (BezierKnotRecord) paths[3];

        bezierKnot.getPoints()[0] = new Point(0, 0);

        bezierKnot = (BezierKnotRecord) paths[4];

        bezierKnot.getPoints()[0] = new Point(8039798, 10905191);

        initialFillRule.setFillStartsWithAllPixels(true);

        subpathLength.setClosed(false);

        im.save(exportPath);

    }

    finally

    {

        im.close();

    }

}

static VsmsResource getVsmsResource(PsdImage image)

{

    Layer layer = image.getLayers()[1];

    VsmsResource resource = null;

    LayerResource[] resources = layer.getResources();

    for (LayerResource layerResource : resources)

    {

        if (layerResource instanceof VsmsResource)

        {

            resource = (VsmsResource) layerResource;

            break;

        }

    }

    if (resource == null)

    {

        throw new AssertionError("VsmsResource not found");

    }

    return resource;

}

IMAGINGJAVA-1456 Fix parallel DNG processing

  public class Tuple<T1, T2> {

    private T1 item1;

    private T2 item2;

    public Tuple(T1 item1, T2 item2) {

        this.item1 = item1;

        this.item2 = item2;

    }

    public final T1 getItem1() {

        return this.item1;

    }

    public final T2 getItem2() {

        return this.item2;

    }

}

protected String TestDirectory = "D:\\";

private List<Tuple<ImageOptionsBase, String>> getImageSaveData()

{

    List<Tuple<ImageOptionsBase, String>> imageSaveData = new ArrayList<Tuple<ImageOptionsBase, String>>();

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new BmpOptions(), ".bmp"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new PngOptions(), ".png"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new JpegOptions(), ".jpg"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new WebPOptions(), ".webp"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new GifOptions(), ".gif"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new TiffOptions(TiffExpectedFormat.Default), ".tiff"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new PsdOptions(), ".psd"));

    return imageSaveData;

}

public void testDngCrop() throws InterruptedException

{

    executeAll(true);

}

public void testDngExport() throws InterruptedException

{

    executeAll(false);

}

public void executeAll(final boolean crop) throws InterruptedException

{

    boolean[] parallels = {true, false};

    final boolean[] error = {false};

    for (final boolean parallel : parallels)

    {

        final Rectangle rect = new Rectangle(1000, 1500, 350, 450);

        List<Tuple<ImageOptionsBase, String>> imageSaveData = getImageSaveData();

        List<Runnable> tasks = new ArrayList<Runnable>();

        for (final Tuple<ImageOptionsBase, String> t : imageSaveData)

        {

            tasks.add(new Runnable()

            {

                @Override

                public void run()

                {

                    try

                    {

                        saveAs("test.dng", crop, rect, parallel, t.getItem1(), t.getItem2());

                    }

                    catch (IOException e)

                    {

                        e.printStackTrace();

                        error[0] = true;

                    }

                }

            });

        }

        if (parallel)

        {

            ExecutorService service = Executors.newFixedThreadPool(tasks.size());

            for (Runnable task : tasks)

            {

                service.execute(task);

            }

            service.awaitTermination(60, TimeUnit.SECONDS);

        }

        else

        {

            for (Runnable task : tasks)

            {

                task.run();

            }

        }

    }

    if (error[0])

    {

        Assert.fail("There was the errors during processing!");

    }

}

private void saveAs(String fileName, boolean crop, Rectangle rect, boolean parallel, ImageOptionsBase optionsBase, String extension) throws IOException

{

    RandomAccessFile fs = new RandomAccessFile(this.TestDirectory + fileName, "r");

    try

    {

        RasterImage image = (RasterImage)Image.load(fs);

        try

        {

            if (crop)

            {

                image.crop(rect);

            }

            image.save(this.TestDirectory + String.format("%s_%s_%s.%s"

                    , fileName

                    , parallel ? "parallel" : "ordered"

                    , crop ? "crop" : ""

                    ,  extension)

                    , optionsBase);

        }

        finally

        {

            image.close();

        }

    }

    finally

    {

        fs.close();

    }

}

IMAGINGJAVA-1401 Image is cropped and not clearly visible on exporting EPS to PDF

 String fileName = "input.eps";

String baseFolder = "D:\\";

String inputFile = baseFolder + fileName;

String outputFile = inputFile + ".pdf";

Image image = Image.load(inputFile);

try

{

    image.save(outputFile, new PdfOptions());

}

finally

{

    image.close();

}

IMAGINGJAVA-1470 SVG not properly converted to Png

 Image image = Image.load("test.svg");

try

{

	SvgRasterizationOptions rasterizationOptions = new SvgRasterizationOptions();

	rasterizationOptions.setPageSize(Size.to_SizeF(image.getSize()));

	rasterizationOptions.setTextRenderingHint(TextRenderingHint.SingleBitPerPixel);

	rasterizationOptions.setSmoothingMode(SmoothingMode.None);

	image.save("test.svg.png", new PngOptions());

}

finally

{

	image.close();

}

IMAGINGJAVA-1455 Failed to save image into write-only stream

 String baseFolder = "D:\\";

String fileName = "sample.png";

String inputFileName = baseFolder + fileName;

String outputFileName = inputFileName + ".png";

RandomAccessFile readStream = new RandomAccessFile(inputFileName, "r");

try

{

    RandomAccessFile writeStream = new RandomAccessFile(outputFileName, "rw");

    try

    {

        Image image = Image.load(readStream);

        try

        {

            image.save(writeStream, new PngOptions());

        }

        finally

        {

            image.close();

        }

    }

    finally

    {

        writeStream.close();

    }

}

finally

{

    readStream.close();

}

IMAGINGJAVA-1457 Fix parallel EMF processing

 public class Tuple<T1, T2>

{

    private T1 item1;

    private T2 item2;

    public Tuple(T1 item1, T2 item2)

    {

        this.item1 = item1;

        this.item2 = item2;

    }

    public final T1 getItem1()

    {

        return this.item1;

    }

    public final T2 getItem2()

    {

        return this.item2;

    }

}

protected String TestDirectory = "D:\\";

private List<Tuple<ImageOptionsBase, String>> getImageSaveData()

{

    List<Tuple<ImageOptionsBase, String>> imageSaveData = new ArrayList<Tuple<ImageOptionsBase, String>>();

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new BmpOptions(), ".bmp"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new PngOptions(), ".png"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new JpegOptions(), ".jpg"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new WebPOptions(), ".webp"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new GifOptions(), ".gif"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new TiffOptions(TiffExpectedFormat.Default), ".tiff"));

    imageSaveData.add(new Tuple<ImageOptionsBase, String>(new PsdOptions(), ".psd"));

    return imageSaveData;

}

public void testEmfExport() throws InterruptedException

{

    boolean[] parallels = {true, false};

    final boolean[] error = {false};

    for (final boolean parallel : parallels)

    {

        List<Tuple<ImageOptionsBase, String>> imageSaveData = getImageSaveData();

        List<Runnable> tasks = new ArrayList<Runnable>();

        for (final Tuple<ImageOptionsBase, String> t : imageSaveData)

        {

            tasks.add(new Runnable()

            {

                @Override

                public void run()

                {

                    try

                    {

                        saveAs("test.emf", parallel, t.getItem1(), t.getItem2());

                    }

                    catch (IOException e)

                    {

                        e.printStackTrace();

                        error[0] = true;

                    }

                }

            });

        }

        if (parallel)

        {

            ExecutorService service = Executors.newFixedThreadPool(tasks.size());

            for (Runnable task : tasks)

            {

                service.execute(task);

            }

            service.awaitTermination(60, TimeUnit.SECONDS);

        }

        else

        {

            for (Runnable task : tasks)

            {

                task.run();

            }

        }

    }

    if (error[0])

    {

        Assert.fail("There was the errors during processing!");

    }

}

private void saveAs(String fileName, boolean parallel, ImageOptionsBase optionsBase, String extension) throws IOException

{

    RandomAccessFile fs = new RandomAccessFile(this.TestDirectory + fileName, "r");

    try

    {

        Image image = Image.load(fs);

        try

        {

            EmfRasterizationOptions rasterizationOptions = new EmfRasterizationOptions();

            rasterizationOptions.setPageSize(Size.to_SizeF(image.getSize()));

            optionsBase.setVectorRasterizationOptions(rasterizationOptions);

            image.save(this.TestDirectory + String.format("%s_%s.%s"

                    , fileName

                    , parallel ? "parallel" : "ordered"

                    , extension)

                    , optionsBase);

        }

        finally

        {

            image.close();

        }

    }

    finally

    {

        fs.close();

    }

}

IMAGINGJAVA-1429 Implement missed methods getUsedFonts, getMissedFonts in MetaImage. These methods were required by customer and exists in old metafile engine.

 String[] files = {

                "TestWmfText.wmf",

                "TestEmfFonts.emf",

                "TestEmfPlusFonts.emf"

        };

// To make all fonts inaccessible

String[] fontDirectories = FontSettings.getFontsFolders();

FontSettings.setFontsFolder("empty");

try

{

	for (String file : files)

	{

		System.out.println("Testing the file: " + file);

		final MetaImage image = (MetaImage) Image.load(file);

		try

		{

			System.out.println("Used fonts:");

			String[] used = image.getUsedFonts();

			for (String it : used)

			{

				System.out.println("Used font: " + it);

			}

			System.out.println("Missed fonts:");

			String[] missed = image.getMissedFonts();

			for (String it : missed)

			{

				System.out.println("Missed font: " + it);

			}

			int ui = 0, mi = 0;

			for (String it : used)

			{

				if (it.contains("Times"))

				{

					ui++;

					continue;

				}

				Assert.assertEquals(used[ui], missed[mi], "Font lists must be equal!");

				ui++; mi++;

			}

		}

		finally

		{

			image.close();

		}

	}

}

finally

{

	FontSettings.setFontsFolders(fontDirectories, true);

}

IMAGINGJAVA-1440 Support for document conversion progress 

 String fileName = "somefile.png";

// Example of use of separate operation progress event handlers for load/export operations

 final ProgressEventHandler loadHandler = new ProgressEventHandler()

        {

            @Override

 public void invoke(ProgressEventHandlerInfo info)

            {

                System.out.format("Load event %s : %d/%d\n", EventType.toString(EventType.class, info.getEventType()), info.getValue(), info.getMaxValue());

 }

        };

 final ProgressEventHandler exportHandler = new ProgressEventHandler()

        {

            @Override

 public void invoke(ProgressEventHandlerInfo info)

            {

                System.out.format("Export event %s : %d/%d\n", EventType.toString(EventType.class, info.getEventType()), info.getValue(), info.getMaxValue());

 }

        };

 Image image = Image.load(fileName, new LoadOptions() {{ setProgressEventHandler(loadHandler); }} );

 try

 {

            image.save(fileName + ".psd",

 new PsdOptions() {{ setProgressEventHandler( exportHandler); }});

 }

        finally

 {

            image.close();

 }
 String fileName = "somefile.png";

// Example of use of operation progress event handler

final ProgressEventHandler handler = new ProgressEventHandler()

{

    @Override

 public void invoke(ProgressEventHandlerInfo info)

    {

        System.out.format("%s : %d/%d\n", EventType.toString(EventType.class, info.getEventType()), info.getValue(), info.getMaxValue());

 }

};

Image image = Image.load(fileName, new LoadOptions() {{ setProgressEventHandler(handler); }} );

try

{

    image.save();

}

finally

{

    image.close();

}