Content of file Java2DUtils.java.html
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>Java2DUtils.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Mistral Examples CustomOperation</a> > <a href="../index.html" class="el_bundle">image-core</a> > <a href="index.source.html" class="el_package">it.tidalwave.image.java2d</a> > <span class="el_source">Java2DUtils.java</span></div><h1>Java2DUtils.java</h1><pre class="source lang-java linenums">/*
* *********************************************************************************************************************
*
* Mistral: open source imaging engine
* http://tidalwave.it/projects/mistral
*
* Copyright (C) 2003 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
*
* *********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* *********************************************************************************************************************
*
* git clone https://bitbucket.org/tidalwave/mistral-src
* git clone https://github.com/tidalwave-it/mistral-src
*
* *********************************************************************************************************************
*/
package it.tidalwave.image.java2d;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.Kernel;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import org.slf4j.Logger;
import it.tidalwave.image.ImageUtils;
import it.tidalwave.image.Kernel2;
import it.tidalwave.image.Quality;
import lombok.extern.slf4j.Slf4j;
/***********************************************************************************************************************
*
* @author Fabrizio Giudici
*
**********************************************************************************************************************/
<span class="pc bpc" id="L64" title="1 of 2 branches missed.">@Slf4j</span>
<span class="nc" id="L65">public class Java2DUtils</span>
{
<span class="fc" id="L67"> public static final Float ZERO = (float)0;</span>
<span class="fc" id="L68"> private static final Map<Quality, Object> renderingHintsQualityMap =</span>
<span class="fc" id="L69"> Map.of(Quality.FASTEST,</span>
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
Quality.INTERMEDIATE,
RenderingHints.VALUE_INTERPOLATION_BILINEAR,
Quality.BEST,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
<span class="fc" id="L76"> private static final Map<Quality, Integer> affineTransformQualityMap =</span>
<span class="fc" id="L77"> Map.of(Quality.FASTEST,</span>
<span class="fc" id="L78"> AffineTransformOp.TYPE_NEAREST_NEIGHBOR,</span>
Quality.INTERMEDIATE,
<span class="fc" id="L80"> AffineTransformOp.TYPE_BILINEAR,</span>
Quality.BEST,
<span class="fc" id="L82"> AffineTransformOp.TYPE_BICUBIC);</span>
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static Properties getProperties (final BufferedImage image)
{
<span class="fc" id="L90"> final var properties = new Properties();</span>
<span class="fc" id="L91"> final var propertyNames = image.getPropertyNames();</span>
<span class="pc bpc" id="L93" title="1 of 2 branches missed."> if (propertyNames != null)</span>
{
<span class="nc bnc" id="L95" title="All 2 branches missed."> for (final var propertyName : propertyNames)</span>
{
<span class="nc" id="L97"> final var propertyValue = image.getProperty(propertyName);</span>
<span class="nc" id="L98"> properties.setProperty(propertyName, propertyValue.toString());</span>
}
}
<span class="fc" id="L102"> return properties;</span>
}
/*******************************************************************************************************************
*
* @param width
* @param height
* @return
*
******************************************************************************************************************/
public static BufferedImage createOptimizedImage (final int width, final int height)
{
<span class="fc" id="L114"> final var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();</span>
<span class="nc" id="L115"> final var gs = ge.getDefaultScreenDevice();</span>
<span class="nc" id="L116"> final var gc = gs.getDefaultConfiguration();</span>
<span class="nc" id="L118"> return gc.createCompatibleImage(width, height);</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static GraphicsConfiguration getGraphicsConfiguration()
{
<span class="nc" id="L127"> final var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();</span>
<span class="nc" id="L128"> final var gs = ge.getScreenDevices();</span>
<span class="nc" id="L129"> final var gd = gs[0]; // FIXME</span>
<span class="nc" id="L131"> return gd.getDefaultConfiguration();</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static BufferedImage createSimilarImage (final BufferedImage bufferedImage,
final int newWidth,
final int newHeight)
{
<span class="nc" id="L142"> final var sampleModel = bufferedImage.getSampleModel().createCompatibleSampleModel(newWidth, newHeight);</span>
<span class="nc" id="L143"> final var newRaster = Raster.createWritableRaster(sampleModel, null);</span>
<span class="nc" id="L144"> final var colorModel = bufferedImage.getColorModel();</span>
<span class="nc" id="L146"> return new BufferedImage(colorModel, newRaster, false, Java2DUtils.getProperties(bufferedImage));</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static String getICCProfileName (final RenderedImage image)
{
<span class="fc" id="L155"> final var iccProfile = ImageUtils.getICCProfile(image);</span>
<span class="pc bpc" id="L157" title="1 of 2 branches missed."> if (iccProfile != null)</span>
{
<span class="fc" id="L159"> return ImageUtils.getICCProfileName(iccProfile);</span>
}
else
{
<span class="nc" id="L164"> return null;</span>
}
}
/*******************************************************************************************************************
*
* It seems that SinglePixelPackedSampleModel is the only fast mode when a
* color profile is converted. This is probably a bug (that has nothing to do
* with bugs 4886071 and 4705399).
* Note that grayscale images (TYPE_GRAY) are not converted.
*
******************************************************************************************************************/
public static BufferedImage convertToSinglePixelPackedSampleModel (BufferedImage image)
{
<span class="fc" id="L178"> log.debug("convertToSinglePixelPackedSampleModel(image: " + image + ")");</span>
<span class="fc" id="L179"> Java2DUtils.logImage(log, ">>>> source bufferedImage", image);</span>
<span class="fc" id="L181"> var time = System.currentTimeMillis();</span>
<span class="fc" id="L183"> final var sourceRaster = image.getRaster();</span>
<span class="fc" id="L184"> var colorModel = image.getColorModel();</span>
<span class="fc" id="L185"> var colorSpace = (ICC_ColorSpace)colorModel.getColorSpace();</span>
<span class="fc" id="L186"> final var ssmd = sourceRaster.getSampleModel();</span>
<span class="pc bpc" id="L188" title="1 of 2 branches missed."> if (colorSpace.getType() == ColorSpace.TYPE_GRAY)</span>
{
<span class="nc" id="L190"> log.debug(">>>> TYPE_GRAY, not converting");</span>
}
<span class="pc bpc" id="L193" title="1 of 2 branches missed."> else if (!(ssmd instanceof PixelInterleavedSampleModel))</span>
{
<span class="nc" id="L195"> log.debug(">>>> sourceSampleModel is " + ssmd.getClass() + ", not converting");</span>
}
else
{
<span class="fc" id="L200"> final var sourceSampleModel = (PixelInterleavedSampleModel)ssmd;</span>
<span class="fc" id="L201"> final var bitMasks = new int[]{0x00ff0000, 0x0000ff00, 0x000000ff};</span>
<span class="fc" id="L203"> final var sampleModel =</span>
<span class="fc" id="L204"> new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, image.getWidth(),</span>
<span class="fc" id="L205"> image.getHeight(), bitMasks);</span>
<span class="fc" id="L207"> final var destRaster = Raster.createWritableRaster(sampleModel, null);</span>
<span class="fc" id="L208"> final var destDataBuffer = (DataBufferInt)destRaster.getDataBuffer();</span>
<span class="fc" id="L209"> final var destBuffer = destDataBuffer.getData();</span>
<span class="fc" id="L210"> final var bandOffsets = sourceSampleModel.getBandOffsets();</span>
<span class="fc bfc" id="L212" title="All 2 branches covered."> for (var i = 0; i < bandOffsets.length; i++)</span>
{
<span class="fc" id="L214"> bandOffsets[i] += ((-sourceRaster.getSampleModelTranslateX() * sourceSampleModel.getPixelStride()) -</span>
<span class="fc" id="L215"> (sourceRaster.getSampleModelTranslateY() * sourceSampleModel.getScanlineStride()));</span>
}
<span class="fc" id="L218"> final var sourceDataBuffer = sourceRaster.getDataBuffer();</span>
<span class="pc bpc" id="L220" title="1 of 2 branches missed."> if (sourceDataBuffer instanceof DataBufferUShort)</span>
{
<span class="nc" id="L222"> convertUShortDataBuffer(image,</span>
(DataBufferUShort)sourceDataBuffer,
sourceSampleModel,
bandOffsets,
destBuffer);
}
<span class="pc bpc" id="L229" title="1 of 2 branches missed."> else if (sourceDataBuffer instanceof DataBufferByte)</span>
{
<span class="fc" id="L231"> convertByteDataBuffer(image,</span>
(DataBufferByte)sourceDataBuffer,
sourceSampleModel,
bandOffsets,
destBuffer);
}
else
{
<span class="nc" id="L240"> throw new IllegalArgumentException("Cannot deal with " + sourceDataBuffer.getClass());</span>
}
<span class="fc" id="L243"> final var sourceProfileName = ImageUtils.getICCProfileName(colorSpace.getProfile());</span>
<span class="pc bpc" id="L245" title="1 of 2 branches missed."> if (sourceProfileName.equals("Nikon sRGB 4.0.0.3001"))</span>
{
<span class="nc" id="L247"> log.warn(">>>> Workaround #1094403: using sRGB instead of " + sourceProfileName);</span>
<span class="nc" id="L248"> colorSpace = new ICC_ColorSpace(ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB));</span>
}
<span class="fc" id="L251"> colorModel = new DirectColorModel(colorSpace,</span>
24,
bitMasks[0],
bitMasks[1],
bitMasks[2],
0,
false,
DataBuffer.TYPE_INT);
<span class="fc" id="L259"> image = new BufferedImage(colorModel, destRaster, false, null);</span>
}
<span class="fc" id="L262"> time = System.currentTimeMillis() - time;</span>
<span class="fc" id="L263"> Java2DUtils.logImage(log, ">>>> convertToSinglePixelPackedSampleModel() returning", image);</span>
<span class="fc" id="L264"> log.debug(">>>> convertToSinglePixelPackedSampleModel() completed ok in " + time + " msec");</span>
<span class="fc" id="L266"> return image;</span>
}
/*******************************************************************************************************************
*
* Scales a <code>BufferedImage</code> by filtering with an
* <code>AffineTransform</code>.
*
* @param bufferedImage the image to scale
* @param xScale the horizontal scale
* @param yScale the vertical scale
* @param quality the quality
*
******************************************************************************************************************/
public static BufferedImage scaleWithAffineTransform (final BufferedImage bufferedImage,
final double xScale,
final double yScale,
final Quality quality)
throws IllegalArgumentException
{
<span class="nc" id="L286"> log.debug("scaleWithAffineTransform(" + xScale + ", " + yScale + ", " + quality);</span>
<span class="nc" id="L288"> final var transform = AffineTransform.getScaleInstance(xScale, yScale);</span>
<span class="nc" id="L289"> final var interpolation = findAffineTransformInterpolation(quality);</span>
<span class="nc" id="L290"> log.debug(">>>> AffineTransformOp(" + transform + ", " + interpolation + ")");</span>
<span class="nc" id="L292"> final var op = new AffineTransformOp(transform, interpolation);</span>
<span class="nc" id="L294"> return op.filter(bufferedImage, null);</span>
}
/*******************************************************************************************************************
*
* Scales a <code>BufferedImage</code> by redrawing it on a new bitmap.
*
* @param bufferedImage the image to scale
* @param xScale the horizontal scale
* @param yScale the vertical scale
* @param quality the quality
*
******************************************************************************************************************/
public static BufferedImage scaleWithDrawImage (final BufferedImage bufferedImage,
final double xScale,
final double yScale,
final Quality quality)
throws IllegalArgumentException
{
<span class="nc" id="L313"> log.debug("scaleWithDrawImage(" + xScale + ", " + yScale + ", " + quality);</span>
<span class="nc" id="L315"> final var newWidth = (int)Math.round(bufferedImage.getWidth() * xScale);</span>
<span class="nc" id="L316"> final var newHeight = (int)Math.round(bufferedImage.getHeight() * yScale);</span>
<span class="nc" id="L317"> final var result = createSimilarImage(bufferedImage, newWidth, newHeight);</span>
<span class="nc" id="L319"> final var g2d = (Graphics2D)result.getGraphics();</span>
<span class="nc" id="L320"> final var interpolation = findRenderingHintsInterpolation(quality);</span>
<span class="nc" id="L321"> g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation);</span>
try
{
<span class="nc" id="L325"> g2d.drawImage(bufferedImage, 0, 0, newWidth, newHeight, null);</span>
}
finally
{
<span class="nc" id="L329"> g2d.dispose();</span>
}
<span class="nc" id="L332"> return result;</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static BufferedImage rotateWithDrawImage (final BufferedImage bufferedImage,
final double degrees,
final Quality quality)
{
<span class="nc" id="L343"> final var radians = Math.toRadians(degrees);</span>
<span class="nc" id="L344"> final var cos = Math.cos(radians);</span>
<span class="nc" id="L345"> final var sin = Math.sin(radians);</span>
<span class="nc" id="L346"> final var width = bufferedImage.getWidth();</span>
<span class="nc" id="L347"> final var height = bufferedImage.getHeight();</span>
<span class="nc" id="L348"> final var newWidth = (int)Math.round(Math.abs(width * cos) + Math.abs(height * sin));</span>
<span class="nc" id="L349"> final var newHeight = (int)Math.round(Math.abs(width * sin) + Math.abs(height * cos));</span>
<span class="nc" id="L350"> final var result = createSimilarImage(bufferedImage, newWidth, newHeight);</span>
<span class="nc" id="L351"> final var g2d = (Graphics2D)result.getGraphics();</span>
<span class="nc" id="L352"> final var interpolation = findRenderingHintsInterpolation(quality);</span>
<span class="nc" id="L353"> g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation);</span>
try
{
<span class="nc" id="L357"> g2d.transform(AffineTransform.getTranslateInstance((newWidth - width) / 2, (newHeight - height) / 2));</span>
<span class="nc" id="L358"> g2d.transform(AffineTransform.getRotateInstance(-radians, width / 2, height / 2));</span>
<span class="nc" id="L359"> g2d.drawImage(bufferedImage, 0, 0, null);</span>
}
finally
{
<span class="nc" id="L364"> g2d.dispose();</span>
}
<span class="nc" id="L367"> return result;</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
protected static String toString (final int[] array, final int radix)
{
<span class="fc" id="L376"> final var buffer = new StringBuilder();</span>
<span class="fc bfc" id="L378" title="All 2 branches covered."> for (var i = 0; i < array.length; i++)</span>
{
<span class="fc" id="L380"> buffer.append(Integer.toString(array[i], radix));</span>
<span class="fc bfc" id="L382" title="All 2 branches covered."> if (i < (array.length - 1))</span>
{
<span class="fc" id="L384"> buffer.append(",");</span>
}
}
<span class="fc" id="L388"> return buffer.toString();</span>
}
/**
* @param image
*/
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static void logImage (final Logger log, final String prefix, final RenderedImage image)
{
<span class="pc bpc" id="L401" title="1 of 2 branches missed."> if (Java2DUtils.log.isDebugEnabled())</span>
{
<span class="fc bfc" id="L403" title="All 2 branches covered."> if (image == null)</span>
{
<span class="fc" id="L405"> Java2DUtils.log.debug(prefix + "null image");</span>
}
else
{
// image.getData(); THIS IS SLOW SLOW SLOW!!
<span class="fc" id="L411"> final var colorModel = image.getColorModel();</span>
<span class="fc" id="L412"> Java2DUtils.log.debug(prefix + ".size: " + image.getWidth() + ", " + image.getHeight());</span>
<span class="fc" id="L413"> Java2DUtils.log.debug(prefix + ".tiles: " + image.getNumXTiles() + " " + image.getNumYTiles());</span>
<span class="fc" id="L414"> Java2DUtils.log.debug(prefix + ".class: " + image.getClass().getName());</span>
<span class="fc" id="L415"> Java2DUtils.log.debug(prefix + ".sampleModel: " + toString(image.getSampleModel()));</span>
<span class="pc bpc" id="L417" title="1 of 2 branches missed."> if (colorModel != null)</span>
{
<span class="fc" id="L419"> Java2DUtils.log.debug(</span>
<span class="fc" id="L420"> prefix + ".colorModel: " + colorModel.getClass().getName() + " : " + colorModel);</span>
<span class="fc" id="L421"> Java2DUtils.log.debug(prefix + ".colorSpace: " + toString(colorModel.getColorSpace()));</span>
}
}
// log.debug(">>>> iccProfile is now: " + getICCProfileName(bufferedImage));
}
<span class="fc" id="L427"> }</span>
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private static String toString (final SampleModel sampleModel)
{
<span class="fc bfc" id="L435" title="All 2 branches covered."> if (sampleModel instanceof SinglePixelPackedSampleModel)</span>
{
<span class="fc" id="L437"> return toString((SinglePixelPackedSampleModel)sampleModel);</span>
}
<span class="pc bpc" id="L440" title="1 of 2 branches missed."> else if (sampleModel instanceof PixelInterleavedSampleModel)</span>
{
<span class="fc" id="L442"> return toString((PixelInterleavedSampleModel)sampleModel);</span>
}
else
{
<span class="nc" id="L447"> return sampleModel.toString();</span>
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private static String toString (final ColorSpace colorSpace)
{
<span class="pc bpc" id="L457" title="1 of 2 branches missed."> if (colorSpace instanceof ICC_ColorSpace)</span>
{
<span class="fc" id="L459"> return toString((ICC_ColorSpace)colorSpace);</span>
}
else
{
<span class="nc" id="L464"> return colorSpace.toString();</span>
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private static String toString (final ICC_ColorSpace colorSpace)
{
<span class="fc" id="L474"> final var buffer = new StringBuilder();</span>
<span class="fc" id="L475"> buffer.append(colorSpace.getClass().getName());</span>
<span class="fc" id="L476"> buffer.append("[type: ");</span>
<span class="fc" id="L477"> buffer.append(colorSpace.getType());</span>
<span class="fc" id="L478"> buffer.append(", profile name: ");</span>
<span class="fc" id="L479"> buffer.append(ImageUtils.getICCProfileName(colorSpace.getProfile()));</span>
<span class="fc" id="L480"> buffer.append("]");</span>
<span class="fc" id="L482"> return buffer.toString();</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private static String toString (final SinglePixelPackedSampleModel sampleModel)
{
<span class="fc" id="L491"> final var buffer = new StringBuilder();</span>
<span class="fc" id="L492"> buffer.append(sampleModel.getClass().getName());</span>
<span class="fc" id="L493"> buffer.append("[width: ");</span>
<span class="fc" id="L494"> buffer.append(sampleModel.getWidth());</span>
<span class="fc" id="L495"> buffer.append(", height: ");</span>
<span class="fc" id="L496"> buffer.append(sampleModel.getHeight());</span>
<span class="fc" id="L497"> buffer.append(", numBands: ");</span>
<span class="fc" id="L498"> buffer.append(sampleModel.getNumBands());</span>
<span class="fc" id="L499"> buffer.append(", dataType: ");</span>
<span class="fc" id="L500"> buffer.append(sampleModel.getDataType());</span>
<span class="fc" id="L501"> buffer.append(", scanlineStride: ");</span>
<span class="fc" id="L502"> buffer.append(sampleModel.getScanlineStride());</span>
<span class="fc" id="L503"> buffer.append(", transferType: ");</span>
<span class="fc" id="L504"> buffer.append(sampleModel.getTransferType());</span>
<span class="fc" id="L505"> buffer.append(", numDataElements: ");</span>
<span class="fc" id="L506"> buffer.append(sampleModel.getNumDataElements());</span>
<span class="fc" id="L507"> buffer.append(", bitMasks: ");</span>
<span class="fc" id="L508"> buffer.append(toString(sampleModel.getBitMasks(), 16));</span>
<span class="fc" id="L509"> buffer.append(", bitOffsets: ");</span>
<span class="fc" id="L510"> buffer.append(toString(sampleModel.getBitOffsets(), 10));</span>
<span class="fc" id="L511"> buffer.append("]");</span>
<span class="fc" id="L513"> return buffer.toString();</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private static String toString (final PixelInterleavedSampleModel sampleModel)
{
<span class="fc" id="L522"> final var buffer = new StringBuilder();</span>
<span class="fc" id="L523"> buffer.append(sampleModel.getClass().getName());</span>
<span class="fc" id="L524"> buffer.append("[width: ");</span>
<span class="fc" id="L525"> buffer.append(sampleModel.getWidth());</span>
<span class="fc" id="L526"> buffer.append(", height: ");</span>
<span class="fc" id="L527"> buffer.append(sampleModel.getHeight());</span>
<span class="fc" id="L528"> buffer.append(", numBands: ");</span>
<span class="fc" id="L529"> buffer.append(sampleModel.getNumBands());</span>
<span class="fc" id="L530"> buffer.append(", dataType: ");</span>
<span class="fc" id="L531"> buffer.append(sampleModel.getDataType());</span>
<span class="fc" id="L532"> buffer.append(", scanlineStride: ");</span>
<span class="fc" id="L533"> buffer.append(sampleModel.getScanlineStride());</span>
<span class="fc" id="L534"> buffer.append(", transferType: ");</span>
<span class="fc" id="L535"> buffer.append(sampleModel.getTransferType());</span>
<span class="fc" id="L536"> buffer.append(", numDataElements: ");</span>
<span class="fc" id="L537"> buffer.append(sampleModel.getNumDataElements());</span>
<span class="fc" id="L538"> buffer.append(", bandOffsets: ");</span>
<span class="fc" id="L539"> buffer.append(toString(sampleModel.getBandOffsets(), 10));</span>
<span class="fc" id="L540"> buffer.append(", bankIndices: ");</span>
<span class="fc" id="L541"> buffer.append(toString(sampleModel.getBankIndices(), 10));</span>
<span class="fc" id="L542"> buffer.append("]");</span>
<span class="fc" id="L544"> return buffer.toString();</span>
}
/*******************************************************************************************************************
*
* @param image
* @param sourceDataBuffer
* @param sourceSampleModel
* @param bandOffsets
* @param destBuffer
*
******************************************************************************************************************/
private static void convertUShortDataBuffer (final BufferedImage image,
final DataBufferUShort sourceDataBuffer,
final PixelInterleavedSampleModel sourceSampleModel,
final int[] bandOffsets,
final int[] destBuffer)
{
<span class="nc" id="L562"> var base = 0;</span>
<span class="nc" id="L563"> var i = 0;</span>
<span class="nc" id="L564"> final var sourceBuffer = sourceDataBuffer.getData();</span>
<span class="nc bnc" id="L566" title="All 2 branches missed."> for (var y = 0; y < image.getHeight(); y++)</span>
{
<span class="nc" id="L568"> var j = base;</span>
<span class="nc bnc" id="L570" title="All 2 branches missed."> for (var x = 0; x < image.getWidth(); x++)</span>
{
<span class="nc" id="L572"> final var r = (sourceBuffer[j + bandOffsets[0]] & 0xffff) >> 8;</span>
<span class="nc" id="L573"> final var g = (sourceBuffer[j + bandOffsets[1]] & 0xffff) >> 8;</span>
<span class="nc" id="L574"> final var b = (sourceBuffer[j + bandOffsets[2]] & 0xffff) >> 8;</span>
<span class="nc" id="L576"> destBuffer[i++] = (r << 16) | (g << 8) | b;</span>
<span class="nc" id="L577"> j += 3;</span>
}
<span class="nc" id="L580"> base += sourceSampleModel.getScanlineStride();</span>
}
<span class="nc" id="L582"> }</span>
/**
* @param image
* @param sourceDataBuffer
* @param sourceSampleModel
* @param bandOffsets
* @param destBuffer
*/
private static void convertByteDataBuffer (final BufferedImage image,
final DataBufferByte sourceDataBuffer,
final PixelInterleavedSampleModel sourceSampleModel,
final int[] bandOffsets,
final int[] destBuffer)
{
<span class="fc" id="L597"> var base = 0;</span>
<span class="fc" id="L598"> var i = 0;</span>
<span class="fc" id="L599"> final var sourceBuffer = sourceDataBuffer.getData();</span>
<span class="fc" id="L600"> final var pixelStride = sourceSampleModel.getPixelStride();</span>
<span class="fc bfc" id="L602" title="All 2 branches covered."> for (var y = 0; y < image.getHeight(); y++)</span>
{
<span class="fc" id="L604"> var j = base;</span>
<span class="fc bfc" id="L606" title="All 2 branches covered."> for (var x = 0; x < image.getWidth(); x++)</span>
{
<span class="fc" id="L608"> final var r = (sourceBuffer[j + bandOffsets[0]] & 0xff);</span>
<span class="fc" id="L609"> final var g = (sourceBuffer[j + bandOffsets[1]] & 0xff);</span>
<span class="fc" id="L610"> final var b = (sourceBuffer[j + bandOffsets[2]] & 0xff);</span>
<span class="fc" id="L612"> destBuffer[i++] = (r << 16) | (g << 8) | b;</span>
<span class="fc" id="L613"> j += pixelStride;</span>
}
<span class="fc" id="L616"> base += sourceSampleModel.getScanlineStride();</span>
}
<span class="fc" id="L618"> }</span>
/*******************************************************************************************************************
*
* @param xScale
* @param yScale
* @param quality
* @return
*
******************************************************************************************************************/
public static BufferedImage createOptimizedImage (final BufferedImage bufferedImage,
final double xScale,
final double yScale,
final Quality quality)
{
<span class="fc" id="L633"> log.debug("createOptimizedImage(" + xScale + ", " + yScale + ", " + quality + ")");</span>
<span class="fc" id="L635"> final var iw = (int)Math.round(xScale * bufferedImage.getWidth());</span>
<span class="fc" id="L636"> final var ih = (int)Math.round(yScale * bufferedImage.getHeight());</span>
<span class="nc" id="L637"> final var image2 = createOptimizedImage(iw, ih);</span>
<span class="nc" id="L638"> final var g = (Graphics2D)image2.getGraphics();</span>
try
{
<span class="nc" id="L642"> final var interpolation = findRenderingHintsInterpolation(quality);</span>
// Workaround for bugs #4886071 and #4705399
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4886071
// and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4705399
/*
* FIXME: looks like we can avoid this now.
| looks like we can avoid this now. | |
if (!bufferedImage.getColorModel().getColorSpace().isCS_sRGB())
{
ICC_Profile iccProfile = ImageUtils.getICCProfile(bufferedImage);
String iccProfileName = ImageUtils.getICCProfileName(iccProfile);
if (ICC_PROFILES_WORKAROUND.contains(iccProfileName))
{
logger.info(">>>> applying workaround for bugs #4886071 and #4705399 - profile " + iccProfileName);
BufferedImage tempImage = createOptimizedImage(bufferedImage.getWidth(), bufferedImage.getHeight());
long time = System.currentTimeMillis();
//BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage
* .TYPE_INT_RGB);
Graphics g3 = tempImage.getGraphics();
g3.drawImage(bufferedImage, 0, 0, null);
g3.dispose();
bufferedImage = tempImage;
logger.info(">>>> workaround applied in " + (System.currentTimeMillis() - time) + " msec.");
}
}
*/
<span class="nc" id="L670"> log.debug(">>>> applying AffineTransform.getScaleInstance() with RenderingHint: " + interpolation);</span>
<span class="nc" id="L672"> final var renderingHintSave = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION);</span>
<span class="nc" id="L673"> g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation);</span>
final var transform =
<span class="nc bnc" id="L676" title="All 4 branches missed."> ((xScale == 1.0) && (yScale == 1.0)) ? null : AffineTransform.getScaleInstance(xScale, yScale);</span>
<span class="nc" id="L677"> g.drawRenderedImage(bufferedImage, transform);</span>
<span class="nc bnc" id="L679" title="All 2 branches missed."> if (renderingHintSave != null)</span>
{
<span class="nc" id="L681"> g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, renderingHintSave);</span>
}
<span class="nc" id="L684"> log.debug(">>>>>>>> iccProfile is now: " + Java2DUtils.getICCProfileName(image2));</span>
}
finally
{
<span class="nc" id="L689"> g.dispose();</span>
}
<span class="nc" id="L692"> return image2;</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static Object findRenderingHintsInterpolation (final Quality quality)
throws IllegalArgumentException
{
<span class="nc bnc" id="L702" title="All 2 branches missed."> if (!renderingHintsQualityMap.containsKey(quality))</span>
{
<span class="nc" id="L704"> throw new IllegalArgumentException(quality.toString());</span>
}
<span class="nc" id="L707"> return renderingHintsQualityMap.get(quality);</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public static int findAffineTransformInterpolation (final Quality quality)
throws IllegalArgumentException
{
<span class="nc bnc" id="L717" title="All 2 branches missed."> if (!affineTransformQualityMap.containsKey(quality))</span>
{
<span class="nc" id="L719"> throw new IllegalArgumentException(quality.toString());</span>
}
<span class="nc" id="L722"> return affineTransformQualityMap.get(quality);</span>
}
/*******************************************************************************************************************
*
* @param n
* @return
*
******************************************************************************************************************/
public static Kernel getAveragingKernel (final int n)
{
<span class="nc" id="L733"> Kernel kernel = null;</span>
<span class="nc bnc" id="L735" title="All 2 branches missed."> if ((n & 1) == 1)</span>
{
<span class="nc" id="L737"> kernel = getOddAveragingKernel(n);</span>
}
else
{
<span class="nc" id="L742"> kernel = getEvenAveragingKernel(n);</span>
}
// log.debug(">>>>>>>> Kernel: " + kernel);
<span class="nc" id="L746"> return kernel;</span>
}
/*******************************************************************************************************************
*
* @param n
* @return
*
******************************************************************************************************************/
private static Kernel getEvenAveragingKernel (final int n)
{
<span class="nc" id="L757"> final var r = n + 1;</span>
<span class="nc" id="L758"> final var totalCount = r * r;</span>
<span class="nc" id="L759"> final var coreCount = (r - 2) * (r - 2);</span>
<span class="nc" id="L760"> final var extCount = totalCount - coreCount;</span>
<span class="nc" id="L761"> final var a = 1.0f / ((coreCount * 2) + extCount); // core count double</span>
<span class="nc" id="L762"> final var coreValue = a * 2;</span>
<span class="nc" id="L763"> final var result = new float[totalCount];</span>
<span class="nc" id="L765"> var j = 0;</span>
<span class="nc bnc" id="L767" title="All 2 branches missed."> for (var i = 0; i < r; i++)</span>
{
<span class="nc" id="L769"> result[j++] = a;</span>
}
<span class="nc bnc" id="L772" title="All 2 branches missed."> for (var k = 0; k < (r - 2); k++)</span>
{
<span class="nc" id="L774"> result[j++] = a;</span>
<span class="nc bnc" id="L776" title="All 2 branches missed."> for (var h = 0; h < (r - 2); h++)</span>
{
<span class="nc" id="L778"> result[j++] = coreValue;</span>
}
<span class="nc" id="L781"> result[j++] = a;</span>
}
<span class="nc bnc" id="L784" title="All 2 branches missed."> for (var i = 0; i < r; i++)</span>
{
<span class="nc" id="L786"> result[j++] = a;</span>
}
<span class="nc bnc" id="L788" title="All 4 branches missed."> assert j == totalCount;</span>
<span class="nc" id="L790"> return new Kernel2(r, r, result);</span>
}
/*******************************************************************************************************************
*
* @param n
* @return
*
******************************************************************************************************************/
private static Kernel getOddAveragingKernel (final int n)
{
<span class="nc" id="L801"> final var totalCount = n * n;</span>
<span class="nc" id="L802"> final var v = 1.0f / (totalCount);</span>
<span class="nc" id="L803"> final var result = new float[totalCount];</span>
<span class="nc" id="L804"> Arrays.fill(result, v);</span>
<span class="nc" id="L806"> return new Kernel2(n, n, result);</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html>