Aspose.Imaging for Java 20.6 - Release notes

KeySummaryCategory
IMAGINGNET-1672Implement support of APNG (animated PNG) file formatFeature
IMAGINGNET-1687Support of a new compression method DXT1 for BMPFeature
IMAGINGNET-1702Support batch export to WebP for multi-page imagesFeature
IMAGINGNET-1676Cannot extract Azure label information from XMP metadataEnhancement
IMAGINGNET-1617The shape collapsed on saving WMF to PNGEnhancement

Public API changes:

Added APIs:

Please see corresponding cumulative API changes for Aspose.Imaging for .NET 20.6 version

Removed APIs:

Please see corresponding cumulative API changes for Aspose.Imaging for .NET 20.6 version

Usage Examples:

Edit

IMAGINGJAVA-1687 Support of a new compression method DXT1 for BMP

DXT Compression

DXTn is a group of related lossy texture compression algorithms. There are five variations of the algorithm (named DXT1 through DXT5), each designed for specific types of image data. All convert a 4X4 block of pixels to a 64-bit or 128-bit quantity, resulting in compression ratios of 6:1 with 24-bit RGB input data or 4:1 with 32-bit RGBA input data. Its inclusion in Microsoft’s DirectX 6.0 and OpenGL 1.3 led to widespread adoption of the technology among hardware and software makers.

DXT1 Algorithm

DXT1 (also known as Block Compression 1 or BC1) is the most simple compression and also the basis for the other types of DXT algorithms. It is the smallest variation of DXT, storing 16 input pixels in 64 bits of output, consisting of two 16-bit color values and a 4X4 two-bit lookup table. The color information is also stored with a compression so that only 16 bits are used per color. This means that these 16 pixels of the texture only take 64 bits to store (32 for the palette and 32 for the indexing). That is a compression ratio of 1:8.

How to use DXT1 compression

The following code demonstrates how you can compress an existing image using DXT1 compression:

try (Image image = Image.load(“Tiger.bmp”)) {  BmpOptions options = new BmpOptions(); options.setCompression(BitmapCompression.Dxt1);     image.save(“CompressedTiger.bmp”, options); }

How to decompress image

The following code shows how to decompress previously compressed

todo:image_alt_text

try (Image image = Image.load(“CompressedTiger.bmp”)) {     image.save(“DecompressedTiger.bmp”, new BmpOptions()); }

IMAGINGJAVA-1672 Implement support of APNG (animated PNG) file format

Creating an image and setting its pixels.

// Example 1. Creating an image and setting its pixels. import com.aspose.imaging.; import com.aspose.imaging.fileformats.apng.; import com.aspose.imaging.fileformats.png.PngColorType; import com.aspose.imaging.imageoptions.ApngOptions; import com.aspose.imaging.sources.FileCreateSource;

// Load pixels from source raster image Size imageSize; int[] imagePixels; try (RasterImage sourceImage = (RasterImage)Image.load(“not_animated.png”)) {     imageSize = sourceImage.getSize();     imagePixels = sourceImage.loadArgb32Pixels(sourceImage.getBounds()); }

// Create APNG image and set its pixels ApngOptions options = new ApngOptions(); options.setSource(new FileCreateSource(outputFilePath, false)); options.setColorType(PngColorType.TruecolorWithAlpha); try (ApngImage image = (ApngImage)Image.create(options, imageSize.getWidth(), imageSize.getHeight())) {  image.saveArgb32Pixels(image.getBounds(), imagePixels);  image.save(); }

// Check output file format try (Image image = Image.load(“created_apng.png”)) {    assert (image.FileFormat == FileFormat.Apng);    assert (image instanceof ApngImage); }

 Raster image operations

// The brightness adjustment operation

using com.aspose.imaging; using com.aspose.imaging.fileformats.apng;

try (ApngImage image = (ApngImage)Image.load(“elephant.png”)) {  image.adjustBrightness(100);  image.save(“AdjustBrightness.png”); } 

 Create an animated image from another single-page image

// Create an animated image from another single-page image

import com.aspose.imaging.Image; import com.aspose.imaging.RasterImage; import com.aspose.imaging.fileformats.apng.ApngFrame; import com.aspose.imaging.fileformats.apng.ApngImage; import com.aspose.imaging.fileformats.png.PngColorType; import com.aspose.imaging.imageoptions.ApngOptions; import com.aspose.imaging.sources.FileCreateSource;

final int AnimationDuration = 1000; // 1 s final int FrameDuration = 70; // 70 ms try (RasterImage sourceImage = (RasterImage)Image.load(“not_animated.png”)) { try (ApngOptions createOptions = new ApngOptions())  {   createOptions.setSource(new FileCreateSource(“raster_animation.png”, false));   createOptions.setDefaultFrameTime(FrameDuration);   createOptions.setColorType(PngColorType.TruecolorWithAlpha);

 try (ApngImage apngImage = (ApngImage)Image.create(     createOptions,     sourceImage.getWidth(),     sourceImage.getHeight()))   {   int numOfFrames = AnimationDuration / FrameDuration;   int numOfFrames2 = numOfFrames / 2;

   apngImage.removeAllFrames();

  // add first frame    apngImage.addFrame(sourceImage, FrameDuration);

  // add intermediate frames   for (int frameIndex = 1; frameIndex < numOfFrames - 1; ++frameIndex)    {     apngImage.addFrame(sourceImage, FrameDuration);     ApngFrame lastFrame = (ApngFrame)apngImage.getPages()[apngImage.getPageCount() - 1];    float gamma = frameIndex >= numOfFrames2 ? numOfFrames - frameIndex - 1 : frameIndex;     lastFrame.adjustGamma(gamma);    }

  // add last frame    apngImage.addFrame(sourceImage, FrameDuration);

   apngImage.save();   }  } }

 Create APNG animation based on vector graphics operations

// Create APNG animation based on vector graphics operations import com.aspose.imaging.; import com.aspose.imaging.fileformats.apng.; import com.aspose.imaging.fileformats.png.PngColorType;

// preparing the animation scene

final int SceneWidth = 400; final int SceneHeigth = 400; // Act duration, in milliseconds final /UInt32/ long ActDuration = 1000; // Total duration, in milliseconds final /UInt32/ long TotalDuration = 4000; // Frame duration, in milliseconds final /UInt32/ long FrameDuration = 50; Scene scene = new Scene(); final Ellipse[] ellipse = { new Ellipse() }; ellipse[0].setFillColor(Color.fromArgb(128, 128, 128)); ellipse[0].setCenterPoint(new PointF(SceneWidth / 2f, SceneHeigth / 2f)); ellipse[0].setRadiusX(80); ellipse[0].setRadiusY(80); scene.addObject(ellipse[0]); final Line[] line = { new Line() }; line[0].setColor(Color.getBlue()); line[0].setLineWidth(10); line[0].setStartPoint(new PointF(30, 30)); line[0].setEndPoint(new PointF(SceneWidth - 30, 30)); scene.addObject(line[0]); IAnimation lineAnimation1 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   line[0].setStartPoint(new PointF(30 + (progress * (SceneWidth - 60)), 30 + (progress * (SceneHeigth - 60))));   line[0].setColor(Color.fromArgb(Operators.f32_s32((progress * 255)), 0, 255 - Operators.f32_s32((progress * 255))));  } }); lineAnimation1.setDuration(ActDuration); IAnimation lineAnimation2 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   line[0].setEndPoint(new PointF(SceneWidth - 30 - (progress * (SceneWidth - 60)), 30 + (progress * (SceneHeigth - 60))));   line[0].setColor(Color.fromArgb(255, Operators.f32_s32((progress * 255)), 0));  } }); lineAnimation2.setDuration(ActDuration); IAnimation lineAnimation3 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   line[0].setStartPoint(new PointF(SceneWidth - 30 - (progress * (SceneWidth - 60)), SceneHeigth - 30 - (progress * (SceneHeigth - 60))));   line[0].setColor(Color.fromArgb(255 - Operators.f32_s32((progress * 255)), 255, 0));  } }); lineAnimation3.setDuration(ActDuration); IAnimation lineAnimation4 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   line[0].setEndPoint(new PointF(30 + (progress * (SceneWidth - 60)), SceneHeigth - 30 - (progress * (SceneHeigth - 60))));   line[0].setColor(Color.fromArgb(0, 255 - Operators.f32_s32((progress * 255)), Operators.f32_s32((progress * 255))));  } }); lineAnimation4.setDuration(ActDuration); SequentialAnimation fullLineAnimation = new SequentialAnimation(); fullLineAnimation.add(lineAnimation1); fullLineAnimation.add(lineAnimation2); fullLineAnimation.add(lineAnimation3); fullLineAnimation.add(lineAnimation4); IAnimation ellipseAnimation1 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   ellipse[0].setRadiusX(ellipse[0].getRadiusX() + (progress * 10));   ellipse[0].setRadiusY(ellipse[0].getRadiusY() + (progress * 10));  int compValue = Operators.f32_s32((128 + (progress * 112)));   ellipse[0].setFillColor(Color.fromArgb(compValue, compValue, compValue));  } }); ellipseAnimation1.setDuration(ActDuration); IAnimation ellipseAnimation2 = new Delay(); ellipseAnimation2.setDuration(ActDuration); IAnimation ellipseAnimation3 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   ellipse[0].setRadiusX(ellipse[0].getRadiusX() - (progress * 10));  int compValue = Operators.f32_s32((240 - (progress * 224)));   ellipse[0].setFillColor(Color.fromArgb(compValue, compValue, compValue));  } }); ellipseAnimation3.setDuration(ActDuration); IAnimation ellipseAnimation4 = new LinearAnimation(new LinearAnimation.AnimationProgressHandler() {

 public void invoke(float progress)  {   ellipse[0].setRadiusY(ellipse[0].getRadiusY() - (progress * 10));  int compValue = Operators.f32_s32((16 + (progress * 112)));   ellipse[0].setFillColor(Color.fromArgb(compValue, compValue, compValue));  } }); ellipseAnimation4.setDuration(ActDuration); SequentialAnimation fullEllipseAnimation = new SequentialAnimation(); fullEllipseAnimation.add(ellipseAnimation1); fullEllipseAnimation.add(ellipseAnimation2); fullEllipseAnimation.add(ellipseAnimation3); fullEllipseAnimation.add(ellipseAnimation4); ParallelAnimation tmp0 = new ParallelAnimation(); tmp0.add(fullLineAnimation); tmp0.add(fullEllipseAnimation); scene.setAnimation(tmp0); // playing the scene on the newly created ApngImage String outputFilePath = this.getFileInOutputFolder(“animation.png”); String etalonFilePath = this.getFileInEthalonFolder(TestDirectoryHelper.combinePath(this.getCurrentTestingMethodName()  , “animation.png”));

try (ApngOptions createOptions = new ApngOptions()) {  createOptions.setSource(new FileCreateSource(outputFilePath, false));  createOptions.setColorType(PngColorType.TruecolorWithAlpha);

try(ApngImage image = (ApngImage) Image.create(createOptions, SceneWidth, SceneHeigth))  {   image.setDefaultFrameTime(FrameDuration);   scene.play(image, TotalDuration);   image.save();  } }

/////////////////////////// Scene.java /////////////////////////////

import com.aspose.imaging.fileformats.apng.ApngFrame; import com.aspose.imaging.fileformats.apng.ApngImage; import com.aspose.tests.blackboxtest.fileformats.apng.graphicsscene.animation.IAnimation; import com.aspose.tests.blackboxtest.fileformats.apng.graphicsscene.graphicsobjects.IGraphicsObject;

import java.util.ArrayList;

/** *

* The graphics scene *

*/ public class Scene {

   /**     *

    * The graphics objects     *

    */     private final java.util.List graphicsObjects = new ArrayList();

   /**     *

    * Gets the animation.     *

    */     public final IAnimation getAnimation()     {        return animation;     }

   /**     *

    * Sets the animation.     *

    */     public final void setAnimation(IAnimation value)     {         animation = value;     }

    private IAnimation animation;

   /**     *

    * Adds the graphics object.     *

    *     * @param graphicsObject The graphics object.     */     public final void addObject(IGraphicsObject graphicsObject)     {         this.graphicsObjects.add(graphicsObject);     }

   /**     *

    * Plays scene on the specified animation image.     *

    *     * @param animationImage The animation image.     * @param totalDuration  The total duration.     */     public final void play(ApngImage animationImage, /*UInt32*/ long totalDuration)     {        /*UInt32*/        long frameDuration = animationImage.getDefaultFrameTime();        /*UInt32*/        long numFrames = (totalDuration / frameDuration);        /*UInt32*/        long totalElapsed = 0;        for (/*UInt32*/long frameIndex = 0; frameIndex < numFrames; frameIndex++)         {            if (this.getAnimation() != null)             {                 this.getAnimation().update(totalElapsed);             }             ApngFrame frame = animationImage.getPageCount() == 0 || frameIndex > 0 ? animationImage.addFrame() : (ApngFrame) animationImage.getPages()[0];             com.aspose.imaging.Graphics graphics = new com.aspose.imaging.Graphics(frame);            //foreach to while statements conversion            for (IGraphicsObject graphicsObject : graphicsObjects)             {                 graphicsObject.render(graphics);             }             totalElapsed = (totalElapsed + frameDuration);         }     } }

/////////////////////////// IGraphicsObject.java /////////////////////////////

/** *

* The graphics object *

*/ public interface IGraphicsObject {

   /**     *

    * Renders this instance using specified graphics.     *

    *     * @param graphics The graphics.     */     void render(com.aspose.imaging.Graphics graphics); }

/////////////////////////// Line.java /////////////////////////////

import com.aspose.imaging.Color; import com.aspose.imaging.Pen; import com.aspose.imaging.PointF;

/** *

* The line *

*/ public class Line implements IGraphicsObject {

   /**     *

    * Gets the start point.     *

    *     * @return the start point.     */     public final PointF getStartPoint()     {        return startPoint.Clone();     }

   /**     *

    * Sets the start point.     *

    *     */     public final void setStartPoint(PointF value)     {         startPoint = value.Clone();     }

    private PointF startPoint = new PointF();

   /**     *

    * Gets the end point.     *

    *     */     public final PointF getEndPoint()     {        return endPoint.Clone();     }

   /**     *

    * Sets the end point.     *

    *     */     public final void setEndPoint(PointF value)     {         endPoint = value.Clone();     }

    private PointF endPoint = new PointF();

   /**     *

    * Gets the width of the line.     *

    *     */     public final float getLineWidth()     {        return lineWidth;     }

   /**     *

    * Sets the width of the line.     *

    *     * @param value the width of the line.     */     public final void setLineWidth(float value)     {         lineWidth = value;     }

    private float lineWidth;

   /**     *

    * Gets the color.     *

    *     * @return the color.     */     public final Color getColor()     {        return color;     }

   /**     *

    * Sets the color.     *

    *     * @param value the color.     */     public final void setColor(Color value)     {         color = value.Clone();     }

    private Color color = new Color();

   /**     *

    * Renders this instance using specified graphics.     *

    *     * @param graphics The graphics.     */     public final void render(com.aspose.imaging.Graphics graphics)     {         graphics.drawLine(new Pen(color, lineWidth), startPoint, endPoint);     } }

/////////////////////////// Ellipse.java /////////////////////////////

import com.aspose.imaging.Color; import com.aspose.imaging.PointF; import com.aspose.imaging.brushes.SolidBrush;

/** *

* The ellipse *

*/ public class Ellipse implements IGraphicsObject {

   /**     *

    * Gets the color of the fill.     *

    *     * @return the color of the fill.     */     public final Color getFillColor()     {        return fillColor.Clone();     }

   /**     *

    * Sets the color of the fill.     *

    *     * @param value the color of the fill.     */     public final void setFillColor(Color value)     {         fillColor = value.Clone();     }

    private Color fillColor = new Color();

   /**     *

    * Gets the center point.     *

    *     * @return the center point.     */     public final PointF getCenterPoint()     {        return centerPoint.Clone();     }

   /**     *

    * Sets the center point.     *

    *     * @param value the center point.     */     public final void setCenterPoint(PointF value)     {         centerPoint = value.Clone();     }

    private PointF centerPoint = new PointF();

   /**     *

    * Gets the radius x.     *

    *     * @return the radius x.     */     public final float getRadiusX()     {        return radiusX;     }

   /**     *

    * Sets the radius x.     *

    *     * @param value the radius x.     */     public final void setRadiusX(float value)     {         radiusX = value;     }

    private float radiusX;

   /**     *

    * Gets the radius y.     *

    *     * @return the radius y.     */     public final float getRadiusY()     {        return radiusY;     }

   /**     *

    * Sets the radius y.     *

    *     * @param value the radius y.     */     public final void setRadiusY(float value)     {         radiusY = value;     }

    private float radiusY;

   /**     *

    * Renders this instance using specified graphics.     *

    *     * @param graphics The graphics.     */    @Override     public final void render(com.aspose.imaging.Graphics graphics)     {         graphics.fillEllipse(new SolidBrush(fillColor), centerPoint.getX() - radiusX                 , centerPoint.getY() - radiusY, radiusX * 2, radiusY * 2);     } }

/////////////////////////// IAnimation.java /////////////////////////////

/** *

* The animation *

*/ public interface IAnimation {

   /**     *

    * Gets the duration.     *

    *     * @return the duration.     */    long getDuration();

   /**     *

    * Sets the duration.     *

    *     * @param value the duration.     */     void setDuration(long value);

   /**     *

    * Updates the animation progress.     *

    *     * @param elapsed The elapsed time, in milliseconds.     */     void update(long elapsed); }

/////////////////////////// LinearAnimation.java /////////////////////////////

/** *

* The linear animation *

*/ public class LinearAnimation implements IAnimation {

   /**     *

    * The progress handler     *

    */     private final AnimationProgressHandler progressHandler;

   /**     *

    * Animation progress handler delegate     *

    */     public interface AnimationProgressHandler     {        /**         *

        * Animation progress handler delegate         *

        *         * @param progress The progress, in [0;1] range.         */         void invoke(float progress);     }

   /**     *

    * Initializes a new instance of the {@link LinearAnimation} class.     *

    *     * @param progressHandler The progress handler.     * @throws NullPointerException progressHandler is null.     */     public LinearAnimation(AnimationProgressHandler progressHandler)     {        if (progressHandler == null)         {             throw new NullPointerException(“progressHandler”);         }         this.progressHandler = progressHandler;     }

   /**     *

    * Gets the duration.     *

    *     * @return the duration.     */    @Override     public final long getDuration()     {        return duration;     }

   /**     *

    * Sets the duration.     *

    *     * @param value the duration.     */    @Override     public final void setDuration(long value)     {         duration = value;     }

    private long duration;

   /**     *

    * Updates the animation progress.     *

    *     * @param elapsed The elapsed time, in milliseconds.     */    @Override     public final void update(long elapsed)     {        if (elapsed <= duration)         {             this.progressHandler.invoke((float) elapsed / duration);         }     } }

/////////////////////////// Delay.java /////////////////////////////

/** *

* The simple delay between other animations *

*/ public class Delay implements IAnimation {

   /**     *

    * Gets the duration.     *

    *     * @return the duration.     */    @Override     public final long getDuration()     {        return duration;     }

   /**     *

    * Sets the duration.     *

    *     * @param value the duration.     */    @Override     public final void setDuration(long value)     {         duration = value;     }

    private long duration;

   /**     *

    * Updates the animation progress.     *

    *     * @param elapsed The elapsed time, in milliseconds.     */    @Override     public final void update(long elapsed)     {        // Do nothing     } }

/////////////////////////// ParallelAnimation.cs /////////////////////////////

import java.util.ArrayList; import java.util.Collection;

/** *

* The parallel animation processor *

*/ public class ParallelAnimation extends ArrayList implements IAnimation {

   /**     *

    * Initializes a new instance of the {@link ParallelAnimation} class.     *

    */     public ParallelAnimation()     {        // Do nothing

    }

   /**     *

    * Initializes a new instance of the {@link ParallelAnimation} class.     *

    *     * @param animations The animations.     */     public ParallelAnimation(Collection animations)     {        super(animations);     }

   /**     *

    * Gets the duration.     *

    *     * @return the duration.     */    @Override     public final long getDuration()     {        long maxDuration = 0;        for (IAnimation animation : this)         {            if (maxDuration < animation.getDuration())             {                 maxDuration = animation.getDuration();             }         }        return maxDuration;     }

   /**     *

    * Sets the duration.     *

    *     * @param value the duration.     */    @Override     public final void setDuration(long value)     {         throw new UnsupportedOperationException();     }

   /**     *

    * Updates the animation progress.     *

    *     * @param elapsed The elapsed time, in milliseconds.     */    @Override     public final void update(long elapsed)     {        for (IAnimation animation : this)         {             animation.update(elapsed);         }     } }

/////////////////////////// SequentialAnimation.java /////////////////////////////

import java.util.ArrayList; import java.util.Collection;

/** *

* The sequential animation processor *

*/ public class SequentialAnimation extends ArrayList implements IAnimation {

   /**     *

    * Initializes a new instance of the {@link SequentialAnimation} class.     *

    */     public SequentialAnimation()     {        // Do nothing

    }

   /**     *

    * Initializes a new instance of the {@link SequentialAnimation} class.     *

    *     * @param animations The animations.     */     public SequentialAnimation(Collection animations)     {        super(animations);     }

   /**     *

    * Gets the duration.     *

    *     * @return the duration.     */    @Override     public final long getDuration()     {        /*UInt32*/        long summDuration = 0;        for (IAnimation animation : this)         {             summDuration = summDuration + animation.getDuration();         }        return summDuration;     }

   /**     *

    * Sets the duration.     *

    *     * @param value the duration.     */    @Override     public final void setDuration(long value)     {         throw new UnsupportedOperationException();     }

   /**     *

    * Updates the animation progress.     *

    *     * @param elapsed The elapsed time, in milliseconds.     */    @Override     public final void update(long elapsed)     {        long totalDuration = 0;        for (IAnimation animation : this)         {            if (totalDuration > elapsed)             {                break;             }             animation.update((elapsed - totalDuration));             totalDuration = totalDuration + animation.getDuration();         }     } }

IMAGINGJAVA-1676 Cannot extract Azure label information from XMP metadata

try (JpegImage image = (JpegImage)Image.load(path)) { XmpPacketWrapper xmpData = image.getXmpData(); if (xmpData != null)  {  for (XmpPackage aPackage : xmpData.getPackages())   {   if (aPackage.getPrefix().equals(“msip”))    {    System.out.println(aPackage.getXmlValue());    break;    }   }  } }

IMAGINGJAVA-1617 The shape collapsed on saving WMF to PNG

try (Image image = Image.load(“image1.wmf”)) {  WmfRasterizationOptions wmfOptions = new WmfRasterizationOptions();  wmfOptions.setTextRenderingHint(TextRenderingHint.SingleBitPerPixel);  wmfOptions.setSmoothingMode(SmoothingMode.None);  wmfOptions.setPageWidth(image.getWidth());  wmfOptions.setPageHeight(image.getHeight());

 PngOptions options = new PngOptions(); options.setVectorRasterizationOptions(wmfOptions);

 image.save(“output.png”, options); }

IMAGINGJAVA-1702 Support batch export to WebP for multi-page images

try (TiffImage tiffImage = (TiffImage)Image.load(“10MB_Tif.tif”)) { // Set batch operation for pages tiffImage.setPageExportingAction(new PageExportingAction()  {   @Override  public void invoke(int pageIndex, Image page)   {   // Fires garbage collection to avoid unnecessary garbage storage from previous pages   System.gc();   ((RasterImage)page).rotate(90);   }  });

tiffImage.save(“rotated.webp”, new WebPOptions());

/* Attention! In batch mode all pages will be released in this line!  If you want to further perform operations on the original image, you should reload it from the source to another instance. */ }