/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/* $Id: DitherUtil.java 1785982 2017-03-08 15:15:06Z ssteiner $ */

package org.apache.fop.util.bitmap;

import java.awt.Color;

Utility methods for dithering.
/** * Utility methods for dithering. */
public final class DitherUtil { private DitherUtil() { }
Selects a 2x2 Bayer dither matrix (5 grayscales)
/** Selects a 2x2 Bayer dither matrix (5 grayscales) */
public static final int DITHER_MATRIX_2X2 = 2;
Selects a 4x4 Bayer dither matrix (17 grayscales)
/** Selects a 4x4 Bayer dither matrix (17 grayscales) */
public static final int DITHER_MATRIX_4X4 = 4;
Selects a 8x8 Bayer dither matrix (65 grayscales)
/** Selects a 8x8 Bayer dither matrix (65 grayscales) */
public static final int DITHER_MATRIX_8X8 = 8; //Bayer dither matrices (4x4 and 8x8 are derived from the 2x2 matrix) private static final int[] BAYER_D2 = new int[] {0, 2, 3, 1}; private static final int[] BAYER_D4; private static final int[] BAYER_D8; static { BAYER_D4 = deriveBayerMatrix(BAYER_D2); BAYER_D8 = deriveBayerMatrix(BAYER_D4); } private static int[] deriveBayerMatrix(int[] d) { int[] dn = new int[d.length * 4]; int half = (int)Math.sqrt(d.length); for (int part = 0; part < 4; part++) { for (int i = 0, c = d.length; i < c; i++) { setValueInMatrix(dn, half, part, i, d[i] * 4 + BAYER_D2[part]); } } return dn; } private static void setValueInMatrix(int[] dn, int half, int part, int idx, int value) { int xoff = (part & 1) * half; int yoff = (part & 2) * half * half; int matrixIndex = yoff + ((idx / half) * half * 2) + (idx % half) + xoff; dn[matrixIndex] = value; }
Returns the Bayer dither base pattern for a particular matrix size.
Params:
Returns:the base pattern for the given size
/** * Returns the Bayer dither base pattern for a particular matrix size. * @param matrix the matrix size ({@link #DITHER_MATRIX_2X2}, {@link #DITHER_MATRIX_4X4} * or {@link #DITHER_MATRIX_8X8}) * @return the base pattern for the given size */
public static int[] getBayerBasePattern(int matrix) { int[] result = new int[matrix * matrix]; switch (matrix) { case DITHER_MATRIX_2X2: System.arraycopy(BAYER_D2, 0, result, 0, BAYER_D2.length); break; case DITHER_MATRIX_4X4: System.arraycopy(BAYER_D4, 0, result, 0, BAYER_D4.length); break; case DITHER_MATRIX_8X8: System.arraycopy(BAYER_D8, 0, result, 0, BAYER_D8.length); break; default: throw new IllegalArgumentException("Unsupported dither matrix: " + matrix); } return result; }
Returns a byte array containing the dither pattern for the given 8-bit gray value.
Params:
Returns:the dither pattern
/** * Returns a byte array containing the dither pattern for the given 8-bit gray value. * @param matrix the matrix size ({@link #DITHER_MATRIX_2X2}, {@link #DITHER_MATRIX_4X4} * or {@link #DITHER_MATRIX_8X8}) * @param gray255 the gray value (0-255) * @param doubleMatrix true if the 4x4 matrix shall be doubled to a 8x8 * @return the dither pattern */
public static byte[] getBayerDither(int matrix, int gray255, boolean doubleMatrix) { int ditherIndex; byte[] dither; int[] bayer; switch (matrix) { case DITHER_MATRIX_4X4: ditherIndex = gray255 * 17 / 255; bayer = BAYER_D4; break; case DITHER_MATRIX_8X8: ditherIndex = gray255 * 65 / 255; bayer = BAYER_D8; break; default: throw new IllegalArgumentException("Unsupported dither matrix: " + matrix); } if (doubleMatrix) { if (matrix != DITHER_MATRIX_4X4) { throw new IllegalArgumentException("doubleMatrix=true is only allowed for 4x4"); } dither = new byte[bayer.length / 8 * 4]; for (int i = 0, c = bayer.length; i < c; i++) { boolean dot = !(bayer[i] < ditherIndex - 1); if (dot) { int byteIdx = i / 4; dither[byteIdx] |= 1 << (i % 4); dither[byteIdx] |= 1 << ((i % 4) + 4); dither[byteIdx + 4] |= 1 << (i % 4); dither[byteIdx + 4] |= 1 << ((i % 4) + 4); } } } else { dither = new byte[bayer.length / 8]; for (int i = 0, c = bayer.length; i < c; i++) { boolean dot = !(bayer[i] < ditherIndex - 1); if (dot) { int byteIdx = i / 8; dither[byteIdx] |= 1 << (i % 8); } } } return dither; }
Returns a byte array containing the dither pattern for the given 8-bit gray value.
Params:
Returns:the dither pattern
/** * Returns a byte array containing the dither pattern for the given 8-bit gray value. * @param matrix the matrix size ({@link #DITHER_MATRIX_2X2}, {@link #DITHER_MATRIX_4X4} * or {@link #DITHER_MATRIX_8X8}) * @param col the color * @param doubleMatrix true if the 4x4 matrix shall be doubled to a 8x8 * @return the dither pattern */
public static byte[] getBayerDither(int matrix, Color col, boolean doubleMatrix) { float black = BitmapImageUtil.convertToGray(col.getRGB()) / 256f; return getBayerDither(matrix, Math.round(black * 256), doubleMatrix); } }