| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * 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. |
| */ |
| |
| package com.google.android.renderscript |
| |
| import android.graphics.Bitmap |
| import java.lang.IllegalArgumentException |
| |
| // This string is used for error messages. |
| private const val externalName = "RenderScript Toolkit" |
| |
| /** |
| * A collection of high-performance graphic utility functions like blur and blend. |
| * |
| * This toolkit provides ten image manipulation functions: blend, blur, color matrix, convolve, |
| * histogram, histogramDot, lut, lut3d, resize, and YUV to RGB. These functions execute |
| * multithreaded on the CPU. |
| * |
| * Most of the functions have two variants: one that manipulates Bitmaps, the other ByteArrays. |
| * For ByteArrays, you need to specify the width and height of the data to be processed, as |
| * well as the number of bytes per pixel. For most use cases, this will be 4. |
| * |
| * The Toolkit creates a thread pool that's used for processing the functions. The threads live |
| * for the duration of the application. They can be destroyed by calling the method shutdown(). |
| * |
| * This library is thread safe. You can call methods from different poolThreads. The functions will |
| * execute sequentially. |
| * |
| * A native C++ version of this Toolkit is available. Check the RenderScriptToolkit.h file in the |
| * cpp directory. |
| * |
| * This toolkit can be used as a replacement for most RenderScript Intrinsic functions. Compared |
| * to RenderScript, it's simpler to use and more than twice as fast on the CPU. However RenderScript |
| * Intrinsics allow more flexibility for the type of allocation supported. In particular, this |
| * toolkit does not support allocations of floats. |
| */ |
| object Toolkit { |
| /** |
| * Blends a source buffer with the destination buffer. |
| * |
| * Blends a source buffer and a destination buffer, placing the result in the destination |
| * buffer. The blending is done pairwise between two corresponding RGBA values found in |
| * each buffer. The mode parameter specifies one of fifteen supported blending operations. |
| * See {@link BlendingMode}. |
| * |
| * A variant of this method is also available to blend Bitmaps. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. |
| * |
| * The source and destination buffer must have the same dimensions. Both arrays should have |
| * a size greater or equal to sizeX * sizeY * 4. The buffers have a row-major layout. |
| * |
| * @param mode The specific blending operation to do. |
| * @param sourceArray The RGBA input buffer. |
| * @param destArray The destination buffer. Used for input and output. |
| * @param sizeX The width of both buffers, as a number of RGBA values. |
| * @param sizeY The height of both buffers, as a number of RGBA values. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| */ |
| @JvmOverloads |
| fun blend( |
| mode: BlendingMode, |
| sourceArray: ByteArray, |
| destArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| restriction: Range2d? = null |
| ) { |
| require(sourceArray.size >= sizeX * sizeY * 4) { |
| "$externalName blend. sourceArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*4 < ${sourceArray.size}." |
| } |
| require(destArray.size >= sizeX * sizeY * 4) { |
| "$externalName blend. sourceArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*4 < ${sourceArray.size}." |
| } |
| validateRestriction("blend", sizeX, sizeY, restriction) |
| |
| nativeBlend(nativeHandle, mode.value, sourceArray, destArray, sizeX, sizeY, restriction) |
| } |
| |
| /** |
| * Blends a source bitmap with the destination bitmap. |
| * |
| * Blends a source bitmap and a destination bitmap, placing the result in the destination |
| * bitmap. The blending is done pairwise between two corresponding RGBA values found in |
| * each bitmap. The mode parameter specify one of fifteen supported blending operations. |
| * See {@link BlendingMode}. |
| * |
| * A variant of this method is available to blend ByteArrays. |
| * |
| * The bitmaps should have identical width and height, and have a config of ARGB_8888. |
| * Bitmaps with a stride different than width * vectorSize are not currently supported. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each bitmap. If provided, the range must be wholly contained with the dimensions |
| * of the bitmap. |
| * |
| * @param mode The specific blending operation to do. |
| * @param sourceBitmap The RGBA input buffer. |
| * @param destBitmap The destination buffer. Used for input and output. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| */ |
| @JvmOverloads |
| fun blend( |
| mode: BlendingMode, |
| sourceBitmap: Bitmap, |
| destBitmap: Bitmap, |
| restriction: Range2d? = null |
| ) { |
| validateBitmap("blend", sourceBitmap) |
| validateBitmap("blend", destBitmap) |
| require( |
| sourceBitmap.width == destBitmap.width && |
| sourceBitmap.height == destBitmap.height |
| ) { |
| "$externalName blend. Source and destination bitmaps should be the same size. " + |
| "${sourceBitmap.width}x${sourceBitmap.height} and " + |
| "${destBitmap.width}x${destBitmap.height} provided." |
| } |
| require(sourceBitmap.config == destBitmap.config) { |
| "RenderScript Toolkit blend. Source and destination bitmaps should have the same " + |
| "config. ${sourceBitmap.config} and ${destBitmap.config} provided." |
| } |
| validateRestriction("blend", sourceBitmap.width, sourceBitmap.height, restriction) |
| |
| nativeBlendBitmap(nativeHandle, mode.value, sourceBitmap, destBitmap, restriction) |
| } |
| |
| /** |
| * Blurs an image. |
| * |
| * Performs a Gaussian blur of an image and returns result in a ByteArray buffer. A variant of |
| * this method is available to blur Bitmaps. |
| * |
| * The radius determines which pixels are used to compute each blurred pixels. This Toolkit |
| * accepts values between 1 and 25. Larger values create a more blurred effect but also |
| * take longer to compute. When the radius extends past the edge, the edge pixel will |
| * be used as replacement for the pixel that's out off boundary. |
| * |
| * Each input pixel can either be represented by four bytes (RGBA format) or one byte |
| * for the less common blurring of alpha channel only image. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output buffer will still be full size, with the |
| * section that's not blurred all set to 0. This is to stay compatible with RenderScript. |
| * |
| * The source buffer should be large enough for sizeX * sizeY * mVectorSize bytes. It has a |
| * row-major layout. |
| * |
| * @param inputArray The buffer of the image to be blurred. |
| * @param vectorSize Either 1 or 4, the number of bytes in each cell, i.e. A vs. RGBA. |
| * @param sizeX The width of both buffers, as a number of 1 or 4 byte cells. |
| * @param sizeY The height of both buffers, as a number of 1 or 4 byte cells. |
| * @param radius The radius of the pixels used to blur, a value from 1 to 25. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The blurred pixels, a ByteArray of size. |
| */ |
| @JvmOverloads |
| fun blur( |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| radius: Int = 5, |
| restriction: Range2d? = null |
| ): ByteArray { |
| require(vectorSize == 1 || vectorSize == 4) { |
| "$externalName blur. The vectorSize should be 1 or 4. $vectorSize provided." |
| } |
| require(inputArray.size >= sizeX * sizeY * vectorSize) { |
| "$externalName blur. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." |
| } |
| require(radius in 1..25) { |
| "$externalName blur. The radius should be between 1 and 25. $radius provided." |
| } |
| validateRestriction("blur", sizeX, sizeY, restriction) |
| |
| val outputArray = ByteArray(inputArray.size) |
| nativeBlur( |
| nativeHandle, inputArray, vectorSize, sizeX, sizeY, radius, outputArray, restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Blurs an image. |
| * |
| * Performs a Gaussian blur of a Bitmap and returns result as a Bitmap. A variant of |
| * this method is available to blur ByteArrays. |
| * |
| * The radius determines which pixels are used to compute each blurred pixels. This Toolkit |
| * accepts values between 1 and 25. Larger values create a more blurred effect but also |
| * take longer to compute. When the radius extends past the edge, the edge pixel will |
| * be used as replacement for the pixel that's out off boundary. |
| * |
| * This method supports input Bitmap of config ARGB_8888 and ALPHA_8. Bitmaps with a stride |
| * different than width * vectorSize are not currently supported. The returned Bitmap has the |
| * same config. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the |
| * section that's not blurred all set to 0. This is to stay compatible with RenderScript. |
| * |
| * @param inputBitmap The buffer of the image to be blurred. |
| * @param radius The radius of the pixels used to blur, a value from 1 to 25. Default is 5. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The blurred Bitmap. |
| */ |
| @JvmOverloads |
| fun blur(inputBitmap: Bitmap, radius: Int = 5, restriction: Range2d? = null): Bitmap { |
| validateBitmap("blur", inputBitmap) |
| require(radius in 1..25) { |
| "$externalName blur. The radius should be between 1 and 25. $radius provided." |
| } |
| validateRestriction("blur", inputBitmap.width, inputBitmap.height, restriction) |
| |
| val outputBitmap = createCompatibleBitmap(inputBitmap) |
| nativeBlurBitmap(nativeHandle, inputBitmap, outputBitmap, radius, restriction) |
| return outputBitmap |
| } |
| |
| /** |
| * Identity matrix that can be passed to the {@link RenderScriptToolkit::colorMatrix} method. |
| * |
| * Using this matrix will result in no change to the pixel through multiplication although |
| * the pixel value can still be modified by the add vector, or transformed to a different |
| * format. |
| */ |
| val identityMatrix: FloatArray |
| get() = floatArrayOf( |
| 1f, 0f, 0f, 0f, |
| 0f, 1f, 0f, 0f, |
| 0f, 0f, 1f, 0f, |
| 0f, 0f, 0f, 1f |
| ) |
| |
| /** |
| * Matrix to turn color pixels to a grey scale. |
| * |
| * Use this matrix with the {@link RenderScriptToolkit::colorMatrix} method to convert an |
| * image from color to greyscale. |
| */ |
| val greyScaleColorMatrix: FloatArray |
| get() = floatArrayOf( |
| 0.299f, 0.299f, 0.299f, 0f, |
| 0.587f, 0.587f, 0.587f, 0f, |
| 0.114f, 0.114f, 0.114f, 0f, |
| 0f, 0f, 0f, 1f |
| ) |
| |
| /** |
| * Matrix to convert RGB to YUV. |
| * |
| * Use this matrix with the {@link RenderScriptToolkit::colorMatrix} method to convert the |
| * first three bytes of each pixel from RGB to YUV. This leaves the last byte (the alpha |
| * channel) untouched. |
| * |
| * This is a simplistic conversion. Most YUV buffers have more complicated format, not supported |
| * by this method. |
| */ |
| val rgbToYuvMatrix: FloatArray |
| get() = floatArrayOf( |
| 0.299f, -0.14713f, 0.615f, 0f, |
| 0.587f, -0.28886f, -0.51499f, 0f, |
| 0.114f, 0.436f, -0.10001f, 0f, |
| 0f, 0f, 0f, 1f |
| ) |
| |
| /** |
| * Matrix to convert YUV to RGB. |
| * |
| * Use this matrix with the {@link RenderScriptToolkit::colorMatrix} method to convert the |
| * first three bytes of each pixel from YUV to RGB. This leaves the last byte (the alpha |
| * channel) untouched. |
| * |
| * This is a simplistic conversion. Most YUV buffers have more complicated format, not supported |
| * by this method. Use {@link RenderScriptToolkit::yuvToRgb} to convert these buffers. |
| */ |
| val yuvToRgbMatrix: FloatArray |
| get() = floatArrayOf( |
| 1f, 1f, 1f, 0f, |
| 0f, -0.39465f, 2.03211f, 0f, |
| 1.13983f, -0.5806f, 0f, 0f, |
| 0f, 0f, 0f, 1f |
| ) |
| |
| /** |
| * Transform an image using a color matrix. |
| * |
| * Converts a 2D array of vectors of unsigned bytes, multiplying each vectors by a 4x4 matrix |
| * and adding an optional vector. |
| * |
| * Each input vector is composed of 1-4 unsigned bytes. If less than 4 bytes, it's extended to |
| * 4, padding with zeroes. The unsigned bytes are converted from 0-255 to 0.0-1.0 floats |
| * before the multiplication is done. |
| * |
| * The resulting value is normalized from 0.0-1.0 to a 0-255 value and stored in the output. |
| * If the output vector size is less than four, the unused channels are discarded. |
| * |
| * If addVector is not specified, a vector of zeroes is added, i.e. a noop. |
| * |
| * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. |
| * |
| * Check identityMatrix, greyScaleColorMatrix, rgbToYuvMatrix, and yuvToRgbMatrix for sample |
| * matrices. The YUV conversion may not work for all color spaces. |
| * |
| * @param inputArray The buffer of the image to be converted. |
| * @param inputVectorSize The number of bytes in each input cell, a value from 1 to 4. |
| * @param sizeX The width of both buffers, as a number of 1 to 4 byte cells. |
| * @param sizeY The height of both buffers, as a number of 1 to 4 byte cells. |
| * @param outputVectorSize The number of bytes in each output cell, a value from 1 to 4. |
| * @param matrix The 4x4 matrix to multiply, in row major format. |
| * @param addVector A vector of four floats that's added to the result of the multiplication. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The converted buffer. |
| */ |
| @JvmOverloads |
| fun colorMatrix( |
| inputArray: ByteArray, |
| inputVectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| outputVectorSize: Int, |
| matrix: FloatArray, |
| addVector: FloatArray = floatArrayOf(0f, 0f, 0f, 0f), |
| restriction: Range2d? = null |
| ): ByteArray { |
| require(inputVectorSize in 1..4) { |
| "$externalName colorMatrix. The inputVectorSize should be between 1 and 4. " + |
| "$inputVectorSize provided." |
| } |
| require(outputVectorSize in 1..4) { |
| "$externalName colorMatrix. The outputVectorSize should be between 1 and 4. " + |
| "$outputVectorSize provided." |
| } |
| require(inputArray.size >= sizeX * sizeY * inputVectorSize) { |
| "$externalName colorMatrix. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*$inputVectorSize < ${inputArray.size}." |
| } |
| require(matrix.size == 16) { |
| "$externalName colorMatrix. matrix should have 16 entries. ${matrix.size} provided." |
| } |
| require(addVector.size == 4) { |
| "$externalName colorMatrix. addVector should have 4 entries. " + |
| "${addVector.size} provided." |
| } |
| validateRestriction("colorMatrix", sizeX, sizeY, restriction) |
| |
| val outputArray = ByteArray(sizeX * sizeY * paddedSize(outputVectorSize)) |
| nativeColorMatrix( |
| nativeHandle, inputArray, inputVectorSize, sizeX, sizeY, outputArray, outputVectorSize, |
| matrix, addVector, restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Transform an image using a color matrix. |
| * |
| * Converts a bitmap, multiplying each RGBA value by a 4x4 matrix and adding an optional vector. |
| * Each byte of the RGBA is converted from 0-255 to 0.0-1.0 floats before the multiplication |
| * is done. |
| * |
| * Bitmaps with a stride different than width * vectorSize are not currently supported. |
| * |
| * The resulting value is normalized from 0.0-1.0 to a 0-255 value and stored in the output. |
| * |
| * If addVector is not specified, a vector of zeroes is added, i.e. a noop. |
| * |
| * Check identityMatrix, greyScaleColorMatrix, rgbToYuvMatrix, and yuvToRgbMatrix for sample |
| * matrices. The YUV conversion may not work for all color spaces. |
| * |
| * @param inputBitmap The image to be converted. |
| * @param matrix The 4x4 matrix to multiply, in row major format. |
| * @param addVector A vector of four floats that's added to the result of the multiplication. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The converted buffer. |
| */ |
| @JvmOverloads |
| fun colorMatrix( |
| inputBitmap: Bitmap, |
| matrix: FloatArray, |
| addVector: FloatArray = floatArrayOf(0f, 0f, 0f, 0f), |
| restriction: Range2d? = null |
| ): Bitmap { |
| validateBitmap("colorMatrix", inputBitmap) |
| require(matrix.size == 16) { |
| "$externalName colorMatrix. matrix should have 16 entries. ${matrix.size} provided." |
| } |
| require(addVector.size == 4) { |
| "$externalName colorMatrix. addVector should have 4 entries." |
| } |
| validateRestriction("colorMatrix", inputBitmap.width, inputBitmap.height, restriction) |
| |
| val outputBitmap = createCompatibleBitmap(inputBitmap) |
| nativeColorMatrixBitmap( |
| nativeHandle, |
| inputBitmap, |
| outputBitmap, |
| matrix, |
| addVector, |
| restriction |
| ) |
| return outputBitmap |
| } |
| |
| /** |
| * Convolve a ByteArray. |
| * |
| * Applies a 3x3 or 5x5 convolution to the input array using the provided coefficients. |
| * A variant of this method is available to convolve Bitmaps. |
| * |
| * For 3x3 convolutions, 9 coefficients must be provided. For 5x5, 25 coefficients are needed. |
| * The coefficients should be provided in row-major format. |
| * |
| * When the square extends past the edge, the edge values will be used as replacement for the |
| * values that's are off boundary. |
| * |
| * Each input cell can either be represented by one to four bytes. Each byte is multiplied |
| * and accumulated independently of the other bytes of the cell. |
| * |
| * An optional range parameter can be set to restrict the convolve operation to a rectangular |
| * subset of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output buffer will still be full size, with the |
| * section that's not convolved all set to 0. This is to stay compatible with RenderScript. |
| * |
| * The source array should be large enough for sizeX * sizeY * vectorSize bytes. It has a |
| * row-major layout. The output array will have the same dimensions. |
| * |
| * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. |
| * |
| * @param inputArray The buffer of the image to be blurred. |
| * @param vectorSize The number of bytes in each cell, a value from 1 to 4. |
| * @param sizeX The width of both buffers, as a number of 1 or 4 byte cells. |
| * @param sizeY The height of both buffers, as a number of 1 or 4 byte cells. |
| * @param coefficients A FloatArray of size 9 or 25, containing the multipliers. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The convolved array. |
| */ |
| @JvmOverloads |
| fun convolve( |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| coefficients: FloatArray, |
| restriction: Range2d? = null |
| ): ByteArray { |
| require(vectorSize in 1..4) { |
| "$externalName convolve. The vectorSize should be between 1 and 4. " + |
| "$vectorSize provided." |
| } |
| require(inputArray.size >= sizeX * sizeY * vectorSize) { |
| "$externalName convolve. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." |
| } |
| require(coefficients.size == 9 || coefficients.size == 25) { |
| "$externalName convolve. Only 3x3 or 5x5 convolutions are supported. " + |
| "${coefficients.size} coefficients provided." |
| } |
| validateRestriction("convolve", sizeX, sizeY, restriction) |
| |
| val outputArray = ByteArray(inputArray.size) |
| nativeConvolve( |
| nativeHandle, |
| inputArray, |
| vectorSize, |
| sizeX, |
| sizeY, |
| outputArray, |
| coefficients, |
| restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Convolve a Bitmap. |
| * |
| * Applies a 3x3 or 5x5 convolution to the input Bitmap using the provided coefficients. |
| * A variant of this method is available to convolve ByteArrays. Bitmaps with a stride different |
| * than width * vectorSize are not currently supported. |
| * |
| * For 3x3 convolutions, 9 coefficients must be provided. For 5x5, 25 coefficients are needed. |
| * The coefficients should be provided in row-major format. |
| * |
| * Each input cell can either be represented by one to four bytes. Each byte is multiplied |
| * and accumulated independently of the other bytes of the cell. |
| * |
| * An optional range parameter can be set to restrict the convolve operation to a rectangular |
| * subset of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the |
| * section that's not convolved all set to 0. This is to stay compatible with RenderScript. |
| * |
| * @param inputBitmap The image to be blurred. |
| * @param coefficients A FloatArray of size 9 or 25, containing the multipliers. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The convolved Bitmap. |
| */ |
| @JvmOverloads |
| fun convolve( |
| inputBitmap: Bitmap, |
| coefficients: FloatArray, |
| restriction: Range2d? = null |
| ): Bitmap { |
| validateBitmap("convolve", inputBitmap) |
| require(coefficients.size == 9 || coefficients.size == 25) { |
| "$externalName convolve. Only 3x3 or 5x5 convolutions are supported. " + |
| "${coefficients.size} coefficients provided." |
| } |
| validateRestriction("convolve", inputBitmap, restriction) |
| |
| val outputBitmap = createCompatibleBitmap(inputBitmap) |
| nativeConvolveBitmap(nativeHandle, inputBitmap, outputBitmap, coefficients, restriction) |
| return outputBitmap |
| } |
| |
| /** |
| * Compute the histogram of an image. |
| * |
| * Tallies how many times each of the 256 possible values of a byte is found in the input. |
| * A variant of this method is available to do the histogram of a Bitmap. |
| * |
| * An input cell can be represented by one to four bytes. The tally is done independently |
| * for each of the bytes of the cell. Correspondingly, the returned IntArray will have |
| * 256 * vectorSize entries. The counts for value 0 are consecutive, followed by those for |
| * value 1, etc. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. |
| * |
| * The source buffer should be large enough for sizeX * sizeY * vectorSize bytes. It has a |
| * row-major layout. |
| * |
| * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. |
| * |
| * @param inputArray The buffer of the image to be analyzed. |
| * @param vectorSize The number of bytes in each cell, a value from 1 to 4. |
| * @param sizeX The width of the input buffers, as a number of 1 to 4 byte cells. |
| * @param sizeY The height of the input buffers, as a number of 1 to 4 byte cells. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The resulting array of counts. |
| */ |
| @JvmOverloads |
| fun histogram( |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| restriction: Range2d? = null |
| ): IntArray { |
| require(vectorSize in 1..4) { |
| "$externalName histogram. The vectorSize should be between 1 and 4. " + |
| "$vectorSize provided." |
| } |
| require(inputArray.size >= sizeX * sizeY * vectorSize) { |
| "$externalName histogram. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." |
| } |
| validateRestriction("histogram", sizeX, sizeY, restriction) |
| |
| val outputArray = IntArray(256 * paddedSize(vectorSize)) |
| nativeHistogram( |
| nativeHandle, |
| inputArray, |
| vectorSize, |
| sizeX, |
| sizeY, |
| outputArray, |
| restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Compute the histogram of an image. |
| * |
| * Tallies how many times each of the 256 possible values of a byte is found in the bitmap. |
| * This method supports Bitmaps of config ARGB_8888 and ALPHA_8. |
| * |
| * For ARGB_8888, the tally is done independently of the four bytes. Correspondingly, the |
| * returned IntArray will have 4 * 256 entries. The counts for value 0 are consecutive, |
| * followed by those for value 1, etc. |
| * |
| * For ALPHA_8, an IntArray of size 256 is returned. |
| * |
| * Bitmaps with a stride different than width * vectorSize are not currently supported. |
| * |
| * A variant of this method is available to do the histogram of a ByteArray. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. |
| * |
| * @param inputBitmap The bitmap to be analyzed. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The resulting array of counts. |
| */ |
| @JvmOverloads |
| fun histogram( |
| inputBitmap: Bitmap, |
| restriction: Range2d? = null |
| ): IntArray { |
| validateBitmap("histogram", inputBitmap) |
| validateRestriction("histogram", inputBitmap, restriction) |
| |
| val outputArray = IntArray(256 * vectorSize(inputBitmap)) |
| nativeHistogramBitmap(nativeHandle, inputBitmap, outputArray, restriction) |
| return outputArray |
| } |
| |
| /** |
| * Compute the histogram of the dot product of an image. |
| * |
| * This method supports cells of 1 to 4 bytes in length. For each cell of the array, |
| * the dot product of its bytes with the provided coefficients is computed. The resulting |
| * floating point value is converted to an unsigned byte and tallied in the histogram. |
| * |
| * If coefficients is null, the coefficients used for RGBA luminosity calculation will be used, |
| * i.e. the values [0.299f, 0.587f, 0.114f, 0.f]. |
| * |
| * Each coefficients must be >= 0 and their sum must be 1.0 or less. There must be the same |
| * number of coefficients as vectorSize. |
| * |
| * A variant of this method is available to do the histogram of a Bitmap. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. |
| * |
| * The source buffer should be large enough for sizeX * sizeY * vectorSize bytes. The returned |
| * array will have 256 ints. |
| * |
| * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. |
| * |
| * @param inputArray The buffer of the image to be analyzed. |
| * @param vectorSize The number of bytes in each cell, a value from 1 to 4. |
| * @param sizeX The width of the input buffers, as a number of 1 to 4 byte cells. |
| * @param sizeY The height of the input buffers, as a number of 1 to 4 byte cells. |
| * @param coefficients The dot product multipliers. Size should equal vectorSize. Can be null. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The resulting vector of counts. |
| */ |
| @JvmOverloads |
| fun histogramDot( |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| coefficients: FloatArray? = null, |
| restriction: Range2d? = null |
| ): IntArray { |
| require(vectorSize in 1..4) { |
| "$externalName histogramDot. The vectorSize should be between 1 and 4. " + |
| "$vectorSize provided." |
| } |
| require(inputArray.size >= sizeX * sizeY * vectorSize) { |
| "$externalName histogramDot. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." |
| } |
| validateHistogramDotCoefficients(coefficients, vectorSize) |
| validateRestriction("histogramDot", sizeX, sizeY, restriction) |
| |
| val outputArray = IntArray(256) |
| val actualCoefficients = coefficients ?: floatArrayOf(0.299f, 0.587f, 0.114f, 0f) |
| nativeHistogramDot( |
| nativeHandle, |
| inputArray, |
| vectorSize, |
| sizeX, |
| sizeY, |
| outputArray, |
| actualCoefficients, |
| restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Compute the histogram of the dot product of an image. |
| * |
| * This method supports Bitmaps of config ARGB_8888 and ALPHA_8. For each pixel of the bitmap, |
| * the dot product of its bytes with the provided coefficients is computed. The resulting |
| * floating point value is converted to an unsigned byte and tallied in the histogram. |
| * |
| * If coefficients is null, the coefficients used for RGBA luminosity calculation will be used, |
| * i.e. the values [0.299f, 0.587f, 0.114f, 0.f]. |
| * |
| * Each coefficients must be >= 0 and their sum must be 1.0 or less. For ARGB_8888, four values |
| * must be provided; for ALPHA_8, one. |
| * |
| * Bitmaps with a stride different than width * vectorSize are not currently supported. |
| * |
| * A variant of this method is available to do the histogram of a ByteArray. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. |
| * |
| * The returned array will have 256 ints. |
| * |
| * @param inputBitmap The bitmap to be analyzed. |
| * @param coefficients The one or four values used for the dot product. Can be null. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The resulting vector of counts. |
| */ |
| @JvmOverloads |
| fun histogramDot( |
| inputBitmap: Bitmap, |
| coefficients: FloatArray? = null, |
| restriction: Range2d? = null |
| ): IntArray { |
| validateBitmap("histogramDot", inputBitmap) |
| validateHistogramDotCoefficients(coefficients, vectorSize(inputBitmap)) |
| validateRestriction("histogramDot", inputBitmap, restriction) |
| |
| val outputArray = IntArray(256) |
| val actualCoefficients = coefficients ?: floatArrayOf(0.299f, 0.587f, 0.114f, 0f) |
| nativeHistogramDotBitmap( |
| nativeHandle, inputBitmap, outputArray, actualCoefficients, restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Transform an image using a look up table |
| * |
| * Transforms an image by using a per-channel lookup table. Each channel of the input has an |
| * independent lookup table. The tables are 256 entries in size and can cover the full value |
| * range of a byte. |
| * |
| * The input array should be in RGBA format, where four consecutive bytes form an cell. |
| * A variant of this method is available to transform a Bitmap. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the |
| * section that's not convolved all set to 0. This is to stay compatible with RenderScript. |
| * |
| * The source array should be large enough for sizeX * sizeY * vectorSize bytes. The returned |
| * ray has the same dimensions as the input. The arrays have a row-major layout. |
| * |
| * @param inputArray The buffer of the image to be transformed. |
| * @param sizeX The width of both buffers, as a number of 4 byte cells. |
| * @param sizeY The height of both buffers, as a number of 4 byte cells. |
| * @param table The four arrays of 256 values that's used to convert each channel. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The transformed image. |
| */ |
| @JvmOverloads |
| fun lut( |
| inputArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| table: LookupTable, |
| restriction: Range2d? = null |
| ): ByteArray { |
| require(inputArray.size >= sizeX * sizeY * 4) { |
| "$externalName lut. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*4 < ${inputArray.size}." |
| } |
| validateRestriction("lut", sizeX, sizeY, restriction) |
| |
| val outputArray = ByteArray(inputArray.size) |
| nativeLut( |
| nativeHandle, |
| inputArray, |
| outputArray, |
| sizeX, |
| sizeY, |
| table.red, |
| table.green, |
| table.blue, |
| table.alpha, |
| restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Transform an image using a look up table |
| * |
| * Transforms an image by using a per-channel lookup table. Each channel of the input has an |
| * independent lookup table. The tables are 256 entries in size and can cover the full value |
| * range of a byte. |
| * |
| * The input Bitmap should be in config ARGB_8888. A variant of this method is available to |
| * transform a ByteArray. Bitmaps with a stride different than width * vectorSize are not |
| * currently supported. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the |
| * section that's not convolved all set to 0. This is to stay compatible with RenderScript. |
| * |
| * @param inputBitmap The buffer of the image to be transformed. |
| * @param table The four arrays of 256 values that's used to convert each channel. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The transformed image. |
| */ |
| @JvmOverloads |
| fun lut( |
| inputBitmap: Bitmap, |
| table: LookupTable, |
| restriction: Range2d? = null |
| ): Bitmap { |
| validateBitmap("lut", inputBitmap) |
| validateRestriction("lut", inputBitmap, restriction) |
| |
| val outputBitmap = createCompatibleBitmap(inputBitmap) |
| nativeLutBitmap( |
| nativeHandle, |
| inputBitmap, |
| outputBitmap, |
| table.red, |
| table.green, |
| table.blue, |
| table.alpha, |
| restriction |
| ) |
| return outputBitmap |
| } |
| |
| /** |
| * Transform an image using a 3D look up table |
| * |
| * Transforms an image, converting RGB to RGBA by using a 3D lookup table. The incoming R, G, |
| * and B values are normalized to the dimensions of the provided 3D buffer. The eight nearest |
| * values in that 3D buffer are sampled and linearly interpolated. The resulting RGBA entry |
| * is returned in the output array. |
| * |
| * The input array should be in RGBA format, where four consecutive bytes form an cell. |
| * The fourth byte of each input cell is ignored. A variant of this method is also available |
| * to transform Bitmaps. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output array will still be full size, with the |
| * section that's not convolved all set to 0. This is to stay compatible with RenderScript. |
| * |
| * The source array should be large enough for sizeX * sizeY * vectorSize bytes. The returned |
| * array will have the same dimensions. The arrays have a row-major layout. |
| * |
| * @param inputArray The buffer of the image to be transformed. |
| * @param sizeX The width of both buffers, as a number of 4 byte cells. |
| * @param sizeY The height of both buffers, as a number of 4 byte cells. |
| * @param cube The translation cube. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The transformed image. |
| */ |
| @JvmOverloads |
| fun lut3d( |
| inputArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| cube: Rgba3dArray, |
| restriction: Range2d? = null |
| ): ByteArray { |
| require(inputArray.size >= sizeX * sizeY * 4) { |
| "$externalName lut3d. inputArray is too small for the given dimensions. " + |
| "$sizeX*$sizeY*4 < ${inputArray.size}." |
| } |
| require( |
| cube.sizeX >= 2 && cube.sizeY >= 2 && cube.sizeZ >= 2 && |
| cube.sizeX <= 256 && cube.sizeY <= 256 && cube.sizeZ <= 256 |
| ) { |
| "$externalName lut3d. The dimensions of the cube should be between 2 and 256. " + |
| "(${cube.sizeX}, ${cube.sizeY}, ${cube.sizeZ}) provided." |
| } |
| validateRestriction("lut3d", sizeX, sizeY, restriction) |
| |
| val outputArray = ByteArray(inputArray.size) |
| nativeLut3d( |
| nativeHandle, inputArray, outputArray, sizeX, sizeY, cube.values, cube.sizeX, |
| cube.sizeY, cube.sizeZ, restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Transform an image using a 3D look up table |
| * |
| * Transforms an image, converting RGB to RGBA by using a 3D lookup table. The incoming R, G, |
| * and B values are normalized to the dimensions of the provided 3D buffer. The eight nearest |
| * values in that 3D buffer are sampled and linearly interpolated. The resulting RGBA entry |
| * is returned in the output array. |
| * |
| * The input bitmap should be in RGBA_8888 format. The A channel is preserved. A variant of this |
| * method is also available to transform ByteArray. Bitmaps with a stride different than |
| * width * vectorSize are not currently supported. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of each buffer. If provided, the range must be wholly contained with the dimensions |
| * described by sizeX and sizeY. NOTE: The output array will still be full size, with the |
| * section that's not convolved all set to 0. This is to stay compatible with RenderScript. |
| * |
| * The source array should be large enough for sizeX * sizeY * vectorSize bytes. The returned |
| * array will have the same dimensions. The arrays have a row-major layout. |
| * |
| * @param inputBitmap The image to be transformed. |
| * @param cube The translation cube. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return The transformed image. |
| */ |
| @JvmOverloads |
| fun lut3d( |
| inputBitmap: Bitmap, |
| cube: Rgba3dArray, |
| restriction: Range2d? = null |
| ): Bitmap { |
| validateBitmap("lut3d", inputBitmap) |
| validateRestriction("lut3d", inputBitmap, restriction) |
| |
| val outputBitmap = createCompatibleBitmap(inputBitmap) |
| nativeLut3dBitmap( |
| nativeHandle, inputBitmap, outputBitmap, cube.values, cube.sizeX, |
| cube.sizeY, cube.sizeZ, restriction |
| ) |
| return outputBitmap |
| } |
| |
| /** |
| * Resize an image. |
| * |
| * Resizes an image using bicubic interpolation. |
| * |
| * This method supports elements of 1 to 4 bytes in length. Each byte of the element is |
| * interpolated independently from the others. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of the output buffer. The corresponding scaled range of the input will be used. If provided, |
| * the range must be wholly contained with the dimensions described by outputSizeX and |
| * outputSizeY. |
| * |
| * The input and output arrays have a row-major layout. The input array should be |
| * large enough for sizeX * sizeY * vectorSize bytes. |
| * |
| * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. |
| * |
| * @param inputArray The buffer of the image to be resized. |
| * @param vectorSize The number of bytes in each element of both buffers. A value from 1 to 4. |
| * @param inputSizeX The width of the input buffer, as a number of 1-4 byte elements. |
| * @param inputSizeY The height of the input buffer, as a number of 1-4 byte elements. |
| * @param outputSizeX The width of the output buffer, as a number of 1-4 byte elements. |
| * @param outputSizeY The height of the output buffer, as a number of 1-4 byte elements. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return An array that contains the rescaled image. |
| */ |
| @JvmOverloads |
| fun resize( |
| inputArray: ByteArray, |
| vectorSize: Int, |
| inputSizeX: Int, |
| inputSizeY: Int, |
| outputSizeX: Int, |
| outputSizeY: Int, |
| restriction: Range2d? = null |
| ): ByteArray { |
| require(vectorSize in 1..4) { |
| "$externalName resize. The vectorSize should be between 1 and 4. $vectorSize provided." |
| } |
| require(inputArray.size >= inputSizeX * inputSizeY * vectorSize) { |
| "$externalName resize. inputArray is too small for the given dimensions. " + |
| "$inputSizeX*$inputSizeY*$vectorSize < ${inputArray.size}." |
| } |
| validateRestriction("resize", outputSizeX, outputSizeY, restriction) |
| |
| val outputArray = ByteArray(outputSizeX * outputSizeY * paddedSize(vectorSize)) |
| nativeResize( |
| nativeHandle, |
| inputArray, |
| vectorSize, |
| inputSizeX, |
| inputSizeY, |
| outputArray, |
| outputSizeX, |
| outputSizeY, |
| restriction |
| ) |
| return outputArray |
| } |
| |
| /** |
| * Resize an image. |
| * |
| * Resizes an image using bicubic interpolation. |
| * |
| * This method supports input Bitmap of config ARGB_8888 and ALPHA_8. The returned Bitmap |
| * has the same config. Bitmaps with a stride different than width * vectorSize are not |
| * currently supported. |
| * |
| * An optional range parameter can be set to restrict the operation to a rectangular subset |
| * of the output buffer. The corresponding scaled range of the input will be used. If provided, |
| * the range must be wholly contained with the dimensions described by outputSizeX and |
| * outputSizeY. |
| * |
| * @param inputBitmap The Bitmap to be resized. |
| * @param outputSizeX The width of the output buffer, as a number of 1-4 byte elements. |
| * @param outputSizeY The height of the output buffer, as a number of 1-4 byte elements. |
| * @param restriction When not null, restricts the operation to a 2D range of pixels. |
| * @return A Bitmap that contains the rescaled image. |
| */ |
| @JvmOverloads |
| fun resize( |
| inputBitmap: Bitmap, |
| outputSizeX: Int, |
| outputSizeY: Int, |
| restriction: Range2d? = null |
| ): Bitmap { |
| validateBitmap("resize", inputBitmap) |
| validateRestriction("resize", outputSizeX, outputSizeY, restriction) |
| |
| val outputBitmap = Bitmap.createBitmap(outputSizeX, outputSizeY, Bitmap.Config.ARGB_8888) |
| nativeResizeBitmap(nativeHandle, inputBitmap, outputBitmap, restriction) |
| return outputBitmap |
| } |
| |
| /** |
| * Convert an image from YUV to RGB. |
| * |
| * Converts a YUV buffer to RGB. The input array should be supplied in a supported YUV format. |
| * The output is RGBA; the alpha channel will be set to 255. |
| * |
| * Note that for YV12 and a sizeX that's not a multiple of 32, the RenderScript Intrinsic may |
| * not have converted the image correctly. This Toolkit method should. |
| * |
| * @param inputArray The buffer of the image to be converted. |
| * @param sizeX The width in pixels of the image. |
| * @param sizeY The height in pixels of the image. |
| * @param format Either YV12 or NV21. |
| * @return The converted image as a byte array. |
| */ |
| fun yuvToRgb(inputArray: ByteArray, sizeX: Int, sizeY: Int, format: YuvFormat): ByteArray { |
| require(sizeX % 2 == 0 && sizeY % 2 == 0) { |
| "$externalName yuvToRgb. Non-even dimensions are not supported. " + |
| "$sizeX and $sizeY were provided." |
| } |
| |
| val outputArray = ByteArray(sizeX * sizeY * 4) |
| nativeYuvToRgb(nativeHandle, inputArray, outputArray, sizeX, sizeY, format.value) |
| return outputArray |
| } |
| |
| /** |
| * Convert an image from YUV to an RGB Bitmap. |
| * |
| * Converts a YUV buffer to an RGB Bitmap. The input array should be supplied in a supported |
| * YUV format. The output is RGBA; the alpha channel will be set to 255. |
| * |
| * Note that for YV12 and a sizeX that's not a multiple of 32, the RenderScript Intrinsic may |
| * not have converted the image correctly. This Toolkit method should. |
| * |
| * @param inputArray The buffer of the image to be converted. |
| * @param sizeX The width in pixels of the image. |
| * @param sizeY The height in pixels of the image. |
| * @param format Either YV12 or NV21. |
| * @return The converted image. |
| */ |
| fun yuvToRgbBitmap(inputArray: ByteArray, sizeX: Int, sizeY: Int, format: YuvFormat): Bitmap { |
| require(sizeX % 2 == 0 && sizeY % 2 == 0) { |
| "$externalName yuvToRgbBitmap. Non-even dimensions are not supported. " + |
| "$sizeX and $sizeY were provided." |
| } |
| |
| val outputBitmap = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888) |
| nativeYuvToRgbBitmap(nativeHandle, inputArray, sizeX, sizeY, outputBitmap, format.value) |
| return outputBitmap |
| } |
| |
| init { |
| System.loadLibrary("renderscript-toolkit") |
| nativeHandle = createNative() |
| } |
| |
| /** |
| * Shutdown the thread pool. |
| * |
| * Waits for the threads to complete their work and destroys them. |
| * |
| * An application should call this method only if it is sure that it won't call the |
| * toolkit again, as it is irreversible. |
| */ |
| fun shutdown() { |
| destroyNative(nativeHandle) |
| nativeHandle = 0 |
| } |
| |
| private var nativeHandle: Long = 0 |
| |
| private external fun createNative(): Long |
| |
| private external fun destroyNative(nativeHandle: Long) |
| |
| private external fun nativeBlend( |
| nativeHandle: Long, |
| mode: Int, |
| sourceArray: ByteArray, |
| destArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeBlendBitmap( |
| nativeHandle: Long, |
| mode: Int, |
| sourceBitmap: Bitmap, |
| destBitmap: Bitmap, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeBlur( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| radius: Int, |
| outputArray: ByteArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeBlurBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputBitmap: Bitmap, |
| radius: Int, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeColorMatrix( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| inputVectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| outputArray: ByteArray, |
| outputVectorSize: Int, |
| matrix: FloatArray, |
| addVector: FloatArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeColorMatrixBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputBitmap: Bitmap, |
| matrix: FloatArray, |
| addVector: FloatArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeConvolve( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| outputArray: ByteArray, |
| coefficients: FloatArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeConvolveBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputBitmap: Bitmap, |
| coefficients: FloatArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeHistogram( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| outputArray: IntArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeHistogramBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputArray: IntArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeHistogramDot( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| vectorSize: Int, |
| sizeX: Int, |
| sizeY: Int, |
| outputArray: IntArray, |
| coefficients: FloatArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeHistogramDotBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputArray: IntArray, |
| coefficients: FloatArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeLut( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| outputArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| red: ByteArray, |
| green: ByteArray, |
| blue: ByteArray, |
| alpha: ByteArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeLutBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputBitmap: Bitmap, |
| red: ByteArray, |
| green: ByteArray, |
| blue: ByteArray, |
| alpha: ByteArray, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeLut3d( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| outputArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| cube: ByteArray, |
| cubeSizeX: Int, |
| cubeSizeY: Int, |
| cubeSizeZ: Int, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeLut3dBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputBitmap: Bitmap, |
| cube: ByteArray, |
| cubeSizeX: Int, |
| cubeSizeY: Int, |
| cubeSizeZ: Int, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeResize( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| vectorSize: Int, |
| inputSizeX: Int, |
| inputSizeY: Int, |
| outputArray: ByteArray, |
| outputSizeX: Int, |
| outputSizeY: Int, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeResizeBitmap( |
| nativeHandle: Long, |
| inputBitmap: Bitmap, |
| outputBitmap: Bitmap, |
| restriction: Range2d? |
| ) |
| |
| private external fun nativeYuvToRgb( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| outputArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| format: Int |
| ) |
| |
| private external fun nativeYuvToRgbBitmap( |
| nativeHandle: Long, |
| inputArray: ByteArray, |
| sizeX: Int, |
| sizeY: Int, |
| outputBitmap: Bitmap, |
| value: Int |
| ) |
| } |
| |
| /** |
| * Determines how a source buffer is blended into a destination buffer. |
| * See {@link RenderScriptToolkit::blend}. |
| * |
| * blend only works on 4 byte RGBA data. In the descriptions below, ".a" represents |
| * the alpha channel. |
| */ |
| enum class BlendingMode(val value: Int) { |
| /** |
| * dest = 0 |
| * |
| * The destination is cleared, i.e. each pixel is set to (0, 0, 0, 0) |
| */ |
| CLEAR(0), |
| |
| /** |
| * dest = src |
| * |
| * Sets each pixel of the destination to the corresponding one in the source. |
| */ |
| SRC(1), |
| |
| /** |
| * dest = dest |
| * |
| * Leaves the destination untouched. This is a no-op. |
| */ |
| DST(2), |
| |
| /** |
| * dest = src + dest * (1.0 - src.a) |
| */ |
| SRC_OVER(3), |
| |
| /** |
| * dest = dest + src * (1.0 - dest.a) |
| */ |
| DST_OVER(4), |
| |
| /** |
| * dest = src * dest.a |
| */ |
| SRC_IN(5), |
| |
| /** |
| * dest = dest * src.a |
| */ |
| DST_IN(6), |
| |
| /** |
| * dest = src * (1.0 - dest.a) |
| */ |
| SRC_OUT(7), |
| |
| /** |
| * dest = dest * (1.0 - src.a) |
| */ |
| DST_OUT(8), |
| |
| /** |
| * dest.rgb = src.rgb * dest.a + (1.0 - src.a) * dest.rgb, dest.a = dest.a |
| */ |
| SRC_ATOP(9), |
| |
| /** |
| * dest = dest.rgb * src.a + (1.0 - dest.a) * src.rgb, dest.a = src.a |
| */ |
| DST_ATOP(10), |
| |
| /** |
| * dest = {src.r ^ dest.r, src.g ^ dest.g, src.b ^ dest.b, src.a ^ dest.a} |
| * |
| * Note: this is NOT the Porter/Duff XOR mode; this is a bitwise xor. |
| */ |
| XOR(11), |
| |
| /** |
| * dest = src * dest |
| */ |
| MULTIPLY(12), |
| |
| /** |
| * dest = min(src + dest, 1.0) |
| */ |
| ADD(13), |
| |
| /** |
| * dest = max(dest - src, 0.0) |
| */ |
| SUBTRACT(14) |
| } |
| |
| /** |
| * A translation table used by the lut method. For each potential red, green, blue, and alpha |
| * value, specifies it's replacement value. |
| * |
| * The fields are initialized to be a no-op operation, i.e. replace 1 by 1, 2 by 2, etc. |
| * You can modify just the values you're interested in having a translation. |
| */ |
| class LookupTable { |
| var red = ByteArray(256) { it.toByte() } |
| var green = ByteArray(256) { it.toByte() } |
| var blue = ByteArray(256) { it.toByte() } |
| var alpha = ByteArray(256) { it.toByte() } |
| } |
| |
| /** |
| * The YUV formats supported by yuvToRgb. |
| */ |
| enum class YuvFormat(val value: Int) { |
| NV21(0x11), |
| YV12(0x32315659), |
| } |
| |
| /** |
| * Define a range of data to process. |
| * |
| * This class is used to restrict a [Toolkit] operation to a rectangular subset of the input |
| * tensor. |
| * |
| * @property startX The index of the first value to be included on the X axis. |
| * @property endX The index after the last value to be included on the X axis. |
| * @property startY The index of the first value to be included on the Y axis. |
| * @property endY The index after the last value to be included on the Y axis. |
| */ |
| data class Range2d( |
| val startX: Int, |
| val endX: Int, |
| val startY: Int, |
| val endY: Int |
| ) { |
| constructor() : this(0, 0, 0, 0) |
| } |
| |
| class Rgba3dArray(val values: ByteArray, val sizeX: Int, val sizeY: Int, val sizeZ: Int) { |
| init { |
| require(values.size >= sizeX * sizeY * sizeZ * 4) |
| } |
| |
| operator fun get(x: Int, y: Int, z: Int): ByteArray { |
| val index = indexOfVector(x, y, z) |
| return ByteArray(4) { values[index + it] } |
| } |
| |
| operator fun set(x: Int, y: Int, z: Int, value: ByteArray) { |
| require(value.size == 4) |
| val index = indexOfVector(x, y, z) |
| for (i in 0..3) { |
| values[index + i] = value[i] |
| } |
| } |
| |
| private fun indexOfVector(x: Int, y: Int, z: Int): Int { |
| require(x in 0 until sizeX) |
| require(y in 0 until sizeY) |
| require(z in 0 until sizeZ) |
| return ((z * sizeY + y) * sizeX + x) * 4 |
| } |
| } |
| |
| internal fun validateBitmap( |
| function: String, |
| inputBitmap: Bitmap, |
| alphaAllowed: Boolean = true |
| ) { |
| if (alphaAllowed) { |
| require( |
| inputBitmap.config == Bitmap.Config.ARGB_8888 || |
| inputBitmap.config == Bitmap.Config.ALPHA_8 |
| ) { |
| "$externalName. $function supports only ARGB_8888 and ALPHA_8 bitmaps. " + |
| "${inputBitmap.config} provided." |
| } |
| } else { |
| require(inputBitmap.config == Bitmap.Config.ARGB_8888) { |
| "$externalName. $function supports only ARGB_8888. " + |
| "${inputBitmap.config} provided." |
| } |
| } |
| require(inputBitmap.width * vectorSize(inputBitmap) == inputBitmap.rowBytes) { |
| "$externalName $function. Only bitmaps with rowSize equal to the width * vectorSize are " + |
| "currently supported. Provided were rowBytes=${inputBitmap.rowBytes}, " + |
| "width={${inputBitmap.width}, and vectorSize=${vectorSize(inputBitmap)}." |
| } |
| } |
| |
| internal fun createCompatibleBitmap(inputBitmap: Bitmap) = |
| Bitmap.createBitmap(inputBitmap.width, inputBitmap.height, inputBitmap.config) |
| |
| internal fun validateHistogramDotCoefficients( |
| coefficients: FloatArray?, |
| vectorSize: Int |
| ) { |
| require(coefficients == null || coefficients.size == vectorSize) { |
| "$externalName histogramDot. The coefficients should be null or have $vectorSize values." |
| } |
| if (coefficients !== null) { |
| var sum = 0f |
| for (i in 0 until vectorSize) { |
| require(coefficients[i] >= 0.0f) { |
| "$externalName histogramDot. Coefficients should not be negative. " + |
| "Coefficient $i was ${coefficients[i]}." |
| } |
| sum += coefficients[i] |
| } |
| require(sum <= 1.0f) { |
| "$externalName histogramDot. Coefficients should add to 1 or less. Their sum is $sum." |
| } |
| } |
| } |
| |
| internal fun validateRestriction(tag: String, bitmap: Bitmap, restriction: Range2d? = null) { |
| validateRestriction(tag, bitmap.width, bitmap.height, restriction) |
| } |
| |
| internal fun validateRestriction( |
| tag: String, |
| sizeX: Int, |
| sizeY: Int, |
| restriction: Range2d? = null |
| ) { |
| if (restriction == null) return |
| require(restriction.startX < sizeX && restriction.endX <= sizeX) { |
| "$externalName $tag. sizeX should be greater than restriction.startX and greater " + |
| "or equal to restriction.endX. $sizeX, ${restriction.startX}, " + |
| "and ${restriction.endX} were provided respectively." |
| } |
| require(restriction.startY < sizeY && restriction.endY <= sizeY) { |
| "$externalName $tag. sizeY should be greater than restriction.startY and greater " + |
| "or equal to restriction.endY. $sizeY, ${restriction.startY}, " + |
| "and ${restriction.endY} were provided respectively." |
| } |
| require(restriction.startX < restriction.endX) { |
| "$externalName $tag. Restriction startX should be less than endX. " + |
| "${restriction.startX} and ${restriction.endX} were provided respectively." |
| } |
| require(restriction.startY < restriction.endY) { |
| "$externalName $tag. Restriction startY should be less than endY. " + |
| "${restriction.startY} and ${restriction.endY} were provided respectively." |
| } |
| } |
| |
| internal fun vectorSize(bitmap: Bitmap): Int { |
| return when (bitmap.config) { |
| Bitmap.Config.ARGB_8888 -> 4 |
| Bitmap.Config.ALPHA_8 -> 1 |
| else -> throw IllegalArgumentException( |
| "$externalName. Only ARGB_8888 and ALPHA_8 Bitmap are supported." |
| ) |
| } |
| } |
| |
| internal fun paddedSize(vectorSize: Int) = if (vectorSize == 3) 4 else vectorSize |