1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.android.renderscript 18 19 import android.graphics.Bitmap 20 import java.lang.IllegalArgumentException 21 22 // This string is used for error messages. 23 private const val externalName = "RenderScript Toolkit" 24 25 /** 26 * A collection of high-performance graphic utility functions like blur and blend. 27 * 28 * This toolkit provides ten image manipulation functions: blend, blur, color matrix, convolve, 29 * histogram, histogramDot, lut, lut3d, resize, and YUV to RGB. These functions execute 30 * multithreaded on the CPU. 31 * 32 * Most of the functions have two variants: one that manipulates Bitmaps, the other ByteArrays. 33 * For ByteArrays, you need to specify the width and height of the data to be processed, as 34 * well as the number of bytes per pixel. For most use cases, this will be 4. 35 * 36 * The Toolkit creates a thread pool that's used for processing the functions. The threads live 37 * for the duration of the application. They can be destroyed by calling the method shutdown(). 38 * 39 * This library is thread safe. You can call methods from different poolThreads. The functions will 40 * execute sequentially. 41 * 42 * A native C++ version of this Toolkit is available. Check the RenderScriptToolkit.h file in the 43 * cpp directory. 44 * 45 * This toolkit can be used as a replacement for most RenderScript Intrinsic functions. Compared 46 * to RenderScript, it's simpler to use and more than twice as fast on the CPU. However RenderScript 47 * Intrinsics allow more flexibility for the type of allocation supported. In particular, this 48 * toolkit does not support allocations of floats. 49 */ 50 object Toolkit { 51 /** 52 * Blends a source buffer with the destination buffer. 53 * 54 * Blends a source buffer and a destination buffer, placing the result in the destination 55 * buffer. The blending is done pairwise between two corresponding RGBA values found in 56 * each buffer. The mode parameter specifies one of fifteen supported blending operations. 57 * See {@link BlendingMode}. 58 * 59 * A variant of this method is also available to blend Bitmaps. 60 * 61 * An optional range parameter can be set to restrict the operation to a rectangular subset 62 * of each buffer. If provided, the range must be wholly contained with the dimensions 63 * described by sizeX and sizeY. 64 * 65 * The source and destination buffer must have the same dimensions. Both arrays should have 66 * a size greater or equal to sizeX * sizeY * 4. The buffers have a row-major layout. 67 * 68 * @param mode The specific blending operation to do. 69 * @param sourceArray The RGBA input buffer. 70 * @param destArray The destination buffer. Used for input and output. 71 * @param sizeX The width of both buffers, as a number of RGBA values. 72 * @param sizeY The height of both buffers, as a number of RGBA values. 73 * @param restriction When not null, restricts the operation to a 2D range of pixels. 74 */ 75 @JvmOverloads blendnull76 fun blend( 77 mode: BlendingMode, 78 sourceArray: ByteArray, 79 destArray: ByteArray, 80 sizeX: Int, 81 sizeY: Int, 82 restriction: Range2d? = null 83 ) { 84 require(sourceArray.size >= sizeX * sizeY * 4) { 85 "$externalName blend. sourceArray is too small for the given dimensions. " + 86 "$sizeX*$sizeY*4 < ${sourceArray.size}." 87 } 88 require(destArray.size >= sizeX * sizeY * 4) { 89 "$externalName blend. sourceArray is too small for the given dimensions. " + 90 "$sizeX*$sizeY*4 < ${sourceArray.size}." 91 } 92 validateRestriction("blend", sizeX, sizeY, restriction) 93 94 nativeBlend(nativeHandle, mode.value, sourceArray, destArray, sizeX, sizeY, restriction) 95 } 96 97 /** 98 * Blends a source bitmap with the destination bitmap. 99 * 100 * Blends a source bitmap and a destination bitmap, placing the result in the destination 101 * bitmap. The blending is done pairwise between two corresponding RGBA values found in 102 * each bitmap. The mode parameter specify one of fifteen supported blending operations. 103 * See {@link BlendingMode}. 104 * 105 * A variant of this method is available to blend ByteArrays. 106 * 107 * The bitmaps should have identical width and height, and have a config of ARGB_8888. 108 * Bitmaps with a stride different than width * vectorSize are not currently supported. 109 * 110 * An optional range parameter can be set to restrict the operation to a rectangular subset 111 * of each bitmap. If provided, the range must be wholly contained with the dimensions 112 * of the bitmap. 113 * 114 * @param mode The specific blending operation to do. 115 * @param sourceBitmap The RGBA input buffer. 116 * @param destBitmap The destination buffer. Used for input and output. 117 * @param restriction When not null, restricts the operation to a 2D range of pixels. 118 */ 119 @JvmOverloads blendnull120 fun blend( 121 mode: BlendingMode, 122 sourceBitmap: Bitmap, 123 destBitmap: Bitmap, 124 restriction: Range2d? = null 125 ) { 126 validateBitmap("blend", sourceBitmap) 127 validateBitmap("blend", destBitmap) 128 require( 129 sourceBitmap.width == destBitmap.width && 130 sourceBitmap.height == destBitmap.height 131 ) { 132 "$externalName blend. Source and destination bitmaps should be the same size. " + 133 "${sourceBitmap.width}x${sourceBitmap.height} and " + 134 "${destBitmap.width}x${destBitmap.height} provided." 135 } 136 require(sourceBitmap.config == destBitmap.config) { 137 "RenderScript Toolkit blend. Source and destination bitmaps should have the same " + 138 "config. ${sourceBitmap.config} and ${destBitmap.config} provided." 139 } 140 validateRestriction("blend", sourceBitmap.width, sourceBitmap.height, restriction) 141 142 nativeBlendBitmap(nativeHandle, mode.value, sourceBitmap, destBitmap, restriction) 143 } 144 145 /** 146 * Blurs an image. 147 * 148 * Performs a Gaussian blur of an image and returns result in a ByteArray buffer. A variant of 149 * this method is available to blur Bitmaps. 150 * 151 * The radius determines which pixels are used to compute each blurred pixels. This Toolkit 152 * accepts values between 1 and 25. Larger values create a more blurred effect but also 153 * take longer to compute. When the radius extends past the edge, the edge pixel will 154 * be used as replacement for the pixel that's out off boundary. 155 * 156 * Each input pixel can either be represented by four bytes (RGBA format) or one byte 157 * for the less common blurring of alpha channel only image. 158 * 159 * An optional range parameter can be set to restrict the operation to a rectangular subset 160 * of each buffer. If provided, the range must be wholly contained with the dimensions 161 * described by sizeX and sizeY. NOTE: The output buffer will still be full size, with the 162 * section that's not blurred all set to 0. This is to stay compatible with RenderScript. 163 * 164 * The source buffer should be large enough for sizeX * sizeY * mVectorSize bytes. It has a 165 * row-major layout. 166 * 167 * @param inputArray The buffer of the image to be blurred. 168 * @param vectorSize Either 1 or 4, the number of bytes in each cell, i.e. A vs. RGBA. 169 * @param sizeX The width of both buffers, as a number of 1 or 4 byte cells. 170 * @param sizeY The height of both buffers, as a number of 1 or 4 byte cells. 171 * @param radius The radius of the pixels used to blur, a value from 1 to 25. 172 * @param restriction When not null, restricts the operation to a 2D range of pixels. 173 * @return The blurred pixels, a ByteArray of size. 174 */ 175 @JvmOverloads blurnull176 fun blur( 177 inputArray: ByteArray, 178 vectorSize: Int, 179 sizeX: Int, 180 sizeY: Int, 181 radius: Int = 5, 182 restriction: Range2d? = null 183 ): ByteArray { 184 require(vectorSize == 1 || vectorSize == 4) { 185 "$externalName blur. The vectorSize should be 1 or 4. $vectorSize provided." 186 } 187 require(inputArray.size >= sizeX * sizeY * vectorSize) { 188 "$externalName blur. inputArray is too small for the given dimensions. " + 189 "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." 190 } 191 require(radius in 1..25) { 192 "$externalName blur. The radius should be between 1 and 25. $radius provided." 193 } 194 validateRestriction("blur", sizeX, sizeY, restriction) 195 196 val outputArray = ByteArray(inputArray.size) 197 nativeBlur( 198 nativeHandle, inputArray, vectorSize, sizeX, sizeY, radius, outputArray, restriction 199 ) 200 return outputArray 201 } 202 203 /** 204 * Blurs an image. 205 * 206 * Performs a Gaussian blur of a Bitmap and returns result as a Bitmap. A variant of 207 * this method is available to blur ByteArrays. 208 * 209 * The radius determines which pixels are used to compute each blurred pixels. This Toolkit 210 * accepts values between 1 and 25. Larger values create a more blurred effect but also 211 * take longer to compute. When the radius extends past the edge, the edge pixel will 212 * be used as replacement for the pixel that's out off boundary. 213 * 214 * This method supports input Bitmap of config ARGB_8888 and ALPHA_8. Bitmaps with a stride 215 * different than width * vectorSize are not currently supported. The returned Bitmap has the 216 * same config. 217 * 218 * An optional range parameter can be set to restrict the operation to a rectangular subset 219 * of each buffer. If provided, the range must be wholly contained with the dimensions 220 * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the 221 * section that's not blurred all set to 0. This is to stay compatible with RenderScript. 222 * 223 * @param inputBitmap The buffer of the image to be blurred. 224 * @param radius The radius of the pixels used to blur, a value from 1 to 25. Default is 5. 225 * @param restriction When not null, restricts the operation to a 2D range of pixels. 226 * @return The blurred Bitmap. 227 */ 228 @JvmOverloads blurnull229 fun blur(inputBitmap: Bitmap, radius: Int = 5, restriction: Range2d? = null): Bitmap { 230 validateBitmap("blur", inputBitmap) 231 require(radius in 1..25) { 232 "$externalName blur. The radius should be between 1 and 25. $radius provided." 233 } 234 validateRestriction("blur", inputBitmap.width, inputBitmap.height, restriction) 235 236 val outputBitmap = createCompatibleBitmap(inputBitmap) 237 nativeBlurBitmap(nativeHandle, inputBitmap, outputBitmap, radius, restriction) 238 return outputBitmap 239 } 240 241 /** 242 * Identity matrix that can be passed to the {@link RenderScriptToolkit::colorMatrix} method. 243 * 244 * Using this matrix will result in no change to the pixel through multiplication although 245 * the pixel value can still be modified by the add vector, or transformed to a different 246 * format. 247 */ 248 val identityMatrix: FloatArray 249 get() = floatArrayOf( 250 1f, 0f, 0f, 0f, 251 0f, 1f, 0f, 0f, 252 0f, 0f, 1f, 0f, 253 0f, 0f, 0f, 1f 254 ) 255 256 /** 257 * Matrix to turn color pixels to a grey scale. 258 * 259 * Use this matrix with the {@link RenderScriptToolkit::colorMatrix} method to convert an 260 * image from color to greyscale. 261 */ 262 val greyScaleColorMatrix: FloatArray 263 get() = floatArrayOf( 264 0.299f, 0.299f, 0.299f, 0f, 265 0.587f, 0.587f, 0.587f, 0f, 266 0.114f, 0.114f, 0.114f, 0f, 267 0f, 0f, 0f, 1f 268 ) 269 270 /** 271 * Matrix to convert RGB to YUV. 272 * 273 * Use this matrix with the {@link RenderScriptToolkit::colorMatrix} method to convert the 274 * first three bytes of each pixel from RGB to YUV. This leaves the last byte (the alpha 275 * channel) untouched. 276 * 277 * This is a simplistic conversion. Most YUV buffers have more complicated format, not supported 278 * by this method. 279 */ 280 val rgbToYuvMatrix: FloatArray 281 get() = floatArrayOf( 282 0.299f, -0.14713f, 0.615f, 0f, 283 0.587f, -0.28886f, -0.51499f, 0f, 284 0.114f, 0.436f, -0.10001f, 0f, 285 0f, 0f, 0f, 1f 286 ) 287 288 /** 289 * Matrix to convert YUV to RGB. 290 * 291 * Use this matrix with the {@link RenderScriptToolkit::colorMatrix} method to convert the 292 * first three bytes of each pixel from YUV to RGB. This leaves the last byte (the alpha 293 * channel) untouched. 294 * 295 * This is a simplistic conversion. Most YUV buffers have more complicated format, not supported 296 * by this method. Use {@link RenderScriptToolkit::yuvToRgb} to convert these buffers. 297 */ 298 val yuvToRgbMatrix: FloatArray 299 get() = floatArrayOf( 300 1f, 1f, 1f, 0f, 301 0f, -0.39465f, 2.03211f, 0f, 302 1.13983f, -0.5806f, 0f, 0f, 303 0f, 0f, 0f, 1f 304 ) 305 306 /** 307 * Transform an image using a color matrix. 308 * 309 * Converts a 2D array of vectors of unsigned bytes, multiplying each vectors by a 4x4 matrix 310 * and adding an optional vector. 311 * 312 * Each input vector is composed of 1-4 unsigned bytes. If less than 4 bytes, it's extended to 313 * 4, padding with zeroes. The unsigned bytes are converted from 0-255 to 0.0-1.0 floats 314 * before the multiplication is done. 315 * 316 * The resulting value is normalized from 0.0-1.0 to a 0-255 value and stored in the output. 317 * If the output vector size is less than four, the unused channels are discarded. 318 * 319 * If addVector is not specified, a vector of zeroes is added, i.e. a noop. 320 * 321 * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. 322 * 323 * Check identityMatrix, greyScaleColorMatrix, rgbToYuvMatrix, and yuvToRgbMatrix for sample 324 * matrices. The YUV conversion may not work for all color spaces. 325 * 326 * @param inputArray The buffer of the image to be converted. 327 * @param inputVectorSize The number of bytes in each input cell, a value from 1 to 4. 328 * @param sizeX The width of both buffers, as a number of 1 to 4 byte cells. 329 * @param sizeY The height of both buffers, as a number of 1 to 4 byte cells. 330 * @param outputVectorSize The number of bytes in each output cell, a value from 1 to 4. 331 * @param matrix The 4x4 matrix to multiply, in row major format. 332 * @param addVector A vector of four floats that's added to the result of the multiplication. 333 * @param restriction When not null, restricts the operation to a 2D range of pixels. 334 * @return The converted buffer. 335 */ 336 @JvmOverloads colorMatrixnull337 fun colorMatrix( 338 inputArray: ByteArray, 339 inputVectorSize: Int, 340 sizeX: Int, 341 sizeY: Int, 342 outputVectorSize: Int, 343 matrix: FloatArray, 344 addVector: FloatArray = floatArrayOf(0f, 0f, 0f, 0f), 345 restriction: Range2d? = null 346 ): ByteArray { 347 require(inputVectorSize in 1..4) { 348 "$externalName colorMatrix. The inputVectorSize should be between 1 and 4. " + 349 "$inputVectorSize provided." 350 } 351 require(outputVectorSize in 1..4) { 352 "$externalName colorMatrix. The outputVectorSize should be between 1 and 4. " + 353 "$outputVectorSize provided." 354 } 355 require(inputArray.size >= sizeX * sizeY * inputVectorSize) { 356 "$externalName colorMatrix. inputArray is too small for the given dimensions. " + 357 "$sizeX*$sizeY*$inputVectorSize < ${inputArray.size}." 358 } 359 require(matrix.size == 16) { 360 "$externalName colorMatrix. matrix should have 16 entries. ${matrix.size} provided." 361 } 362 require(addVector.size == 4) { 363 "$externalName colorMatrix. addVector should have 4 entries. " + 364 "${addVector.size} provided." 365 } 366 validateRestriction("colorMatrix", sizeX, sizeY, restriction) 367 368 val outputArray = ByteArray(sizeX * sizeY * paddedSize(outputVectorSize)) 369 nativeColorMatrix( 370 nativeHandle, inputArray, inputVectorSize, sizeX, sizeY, outputArray, outputVectorSize, 371 matrix, addVector, restriction 372 ) 373 return outputArray 374 } 375 376 /** 377 * Transform an image using a color matrix. 378 * 379 * Converts a bitmap, multiplying each RGBA value by a 4x4 matrix and adding an optional vector. 380 * Each byte of the RGBA is converted from 0-255 to 0.0-1.0 floats before the multiplication 381 * is done. 382 * 383 * Bitmaps with a stride different than width * vectorSize are not currently supported. 384 * 385 * The resulting value is normalized from 0.0-1.0 to a 0-255 value and stored in the output. 386 * 387 * If addVector is not specified, a vector of zeroes is added, i.e. a noop. 388 * 389 * Check identityMatrix, greyScaleColorMatrix, rgbToYuvMatrix, and yuvToRgbMatrix for sample 390 * matrices. The YUV conversion may not work for all color spaces. 391 * 392 * @param inputBitmap The image to be converted. 393 * @param matrix The 4x4 matrix to multiply, in row major format. 394 * @param addVector A vector of four floats that's added to the result of the multiplication. 395 * @param restriction When not null, restricts the operation to a 2D range of pixels. 396 * @return The converted buffer. 397 */ 398 @JvmOverloads colorMatrixnull399 fun colorMatrix( 400 inputBitmap: Bitmap, 401 matrix: FloatArray, 402 addVector: FloatArray = floatArrayOf(0f, 0f, 0f, 0f), 403 restriction: Range2d? = null 404 ): Bitmap { 405 validateBitmap("colorMatrix", inputBitmap) 406 require(matrix.size == 16) { 407 "$externalName colorMatrix. matrix should have 16 entries. ${matrix.size} provided." 408 } 409 require(addVector.size == 4) { 410 "$externalName colorMatrix. addVector should have 4 entries." 411 } 412 validateRestriction("colorMatrix", inputBitmap.width, inputBitmap.height, restriction) 413 414 val outputBitmap = createCompatibleBitmap(inputBitmap) 415 nativeColorMatrixBitmap( 416 nativeHandle, 417 inputBitmap, 418 outputBitmap, 419 matrix, 420 addVector, 421 restriction 422 ) 423 return outputBitmap 424 } 425 426 /** 427 * Convolve a ByteArray. 428 * 429 * Applies a 3x3 or 5x5 convolution to the input array using the provided coefficients. 430 * A variant of this method is available to convolve Bitmaps. 431 * 432 * For 3x3 convolutions, 9 coefficients must be provided. For 5x5, 25 coefficients are needed. 433 * The coefficients should be provided in row-major format. 434 * 435 * When the square extends past the edge, the edge values will be used as replacement for the 436 * values that's are off boundary. 437 * 438 * Each input cell can either be represented by one to four bytes. Each byte is multiplied 439 * and accumulated independently of the other bytes of the cell. 440 * 441 * An optional range parameter can be set to restrict the convolve operation to a rectangular 442 * subset of each buffer. If provided, the range must be wholly contained with the dimensions 443 * described by sizeX and sizeY. NOTE: The output buffer will still be full size, with the 444 * section that's not convolved all set to 0. This is to stay compatible with RenderScript. 445 * 446 * The source array should be large enough for sizeX * sizeY * vectorSize bytes. It has a 447 * row-major layout. The output array will have the same dimensions. 448 * 449 * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. 450 * 451 * @param inputArray The buffer of the image to be blurred. 452 * @param vectorSize The number of bytes in each cell, a value from 1 to 4. 453 * @param sizeX The width of both buffers, as a number of 1 or 4 byte cells. 454 * @param sizeY The height of both buffers, as a number of 1 or 4 byte cells. 455 * @param coefficients A FloatArray of size 9 or 25, containing the multipliers. 456 * @param restriction When not null, restricts the operation to a 2D range of pixels. 457 * @return The convolved array. 458 */ 459 @JvmOverloads convolvenull460 fun convolve( 461 inputArray: ByteArray, 462 vectorSize: Int, 463 sizeX: Int, 464 sizeY: Int, 465 coefficients: FloatArray, 466 restriction: Range2d? = null 467 ): ByteArray { 468 require(vectorSize in 1..4) { 469 "$externalName convolve. The vectorSize should be between 1 and 4. " + 470 "$vectorSize provided." 471 } 472 require(inputArray.size >= sizeX * sizeY * vectorSize) { 473 "$externalName convolve. inputArray is too small for the given dimensions. " + 474 "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." 475 } 476 require(coefficients.size == 9 || coefficients.size == 25) { 477 "$externalName convolve. Only 3x3 or 5x5 convolutions are supported. " + 478 "${coefficients.size} coefficients provided." 479 } 480 validateRestriction("convolve", sizeX, sizeY, restriction) 481 482 val outputArray = ByteArray(inputArray.size) 483 nativeConvolve( 484 nativeHandle, 485 inputArray, 486 vectorSize, 487 sizeX, 488 sizeY, 489 outputArray, 490 coefficients, 491 restriction 492 ) 493 return outputArray 494 } 495 496 /** 497 * Convolve a Bitmap. 498 * 499 * Applies a 3x3 or 5x5 convolution to the input Bitmap using the provided coefficients. 500 * A variant of this method is available to convolve ByteArrays. Bitmaps with a stride different 501 * than width * vectorSize are not currently supported. 502 * 503 * For 3x3 convolutions, 9 coefficients must be provided. For 5x5, 25 coefficients are needed. 504 * The coefficients should be provided in row-major format. 505 * 506 * Each input cell can either be represented by one to four bytes. Each byte is multiplied 507 * and accumulated independently of the other bytes of the cell. 508 * 509 * An optional range parameter can be set to restrict the convolve operation to a rectangular 510 * subset of each buffer. If provided, the range must be wholly contained with the dimensions 511 * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the 512 * section that's not convolved all set to 0. This is to stay compatible with RenderScript. 513 * 514 * @param inputBitmap The image to be blurred. 515 * @param coefficients A FloatArray of size 9 or 25, containing the multipliers. 516 * @param restriction When not null, restricts the operation to a 2D range of pixels. 517 * @return The convolved Bitmap. 518 */ 519 @JvmOverloads convolvenull520 fun convolve( 521 inputBitmap: Bitmap, 522 coefficients: FloatArray, 523 restriction: Range2d? = null 524 ): Bitmap { 525 validateBitmap("convolve", inputBitmap) 526 require(coefficients.size == 9 || coefficients.size == 25) { 527 "$externalName convolve. Only 3x3 or 5x5 convolutions are supported. " + 528 "${coefficients.size} coefficients provided." 529 } 530 validateRestriction("convolve", inputBitmap, restriction) 531 532 val outputBitmap = createCompatibleBitmap(inputBitmap) 533 nativeConvolveBitmap(nativeHandle, inputBitmap, outputBitmap, coefficients, restriction) 534 return outputBitmap 535 } 536 537 /** 538 * Compute the histogram of an image. 539 * 540 * Tallies how many times each of the 256 possible values of a byte is found in the input. 541 * A variant of this method is available to do the histogram of a Bitmap. 542 * 543 * An input cell can be represented by one to four bytes. The tally is done independently 544 * for each of the bytes of the cell. Correspondingly, the returned IntArray will have 545 * 256 * vectorSize entries. The counts for value 0 are consecutive, followed by those for 546 * value 1, etc. 547 * 548 * An optional range parameter can be set to restrict the operation to a rectangular subset 549 * of each buffer. If provided, the range must be wholly contained with the dimensions 550 * described by sizeX and sizeY. 551 * 552 * The source buffer should be large enough for sizeX * sizeY * vectorSize bytes. It has a 553 * row-major layout. 554 * 555 * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. 556 * 557 * @param inputArray The buffer of the image to be analyzed. 558 * @param vectorSize The number of bytes in each cell, a value from 1 to 4. 559 * @param sizeX The width of the input buffers, as a number of 1 to 4 byte cells. 560 * @param sizeY The height of the input buffers, as a number of 1 to 4 byte cells. 561 * @param restriction When not null, restricts the operation to a 2D range of pixels. 562 * @return The resulting array of counts. 563 */ 564 @JvmOverloads histogramnull565 fun histogram( 566 inputArray: ByteArray, 567 vectorSize: Int, 568 sizeX: Int, 569 sizeY: Int, 570 restriction: Range2d? = null 571 ): IntArray { 572 require(vectorSize in 1..4) { 573 "$externalName histogram. The vectorSize should be between 1 and 4. " + 574 "$vectorSize provided." 575 } 576 require(inputArray.size >= sizeX * sizeY * vectorSize) { 577 "$externalName histogram. inputArray is too small for the given dimensions. " + 578 "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." 579 } 580 validateRestriction("histogram", sizeX, sizeY, restriction) 581 582 val outputArray = IntArray(256 * paddedSize(vectorSize)) 583 nativeHistogram( 584 nativeHandle, 585 inputArray, 586 vectorSize, 587 sizeX, 588 sizeY, 589 outputArray, 590 restriction 591 ) 592 return outputArray 593 } 594 595 /** 596 * Compute the histogram of an image. 597 * 598 * Tallies how many times each of the 256 possible values of a byte is found in the bitmap. 599 * This method supports Bitmaps of config ARGB_8888 and ALPHA_8. 600 * 601 * For ARGB_8888, the tally is done independently of the four bytes. Correspondingly, the 602 * returned IntArray will have 4 * 256 entries. The counts for value 0 are consecutive, 603 * followed by those for value 1, etc. 604 * 605 * For ALPHA_8, an IntArray of size 256 is returned. 606 * 607 * Bitmaps with a stride different than width * vectorSize are not currently supported. 608 * 609 * A variant of this method is available to do the histogram of a ByteArray. 610 * 611 * An optional range parameter can be set to restrict the operation to a rectangular subset 612 * of each buffer. If provided, the range must be wholly contained with the dimensions 613 * described by sizeX and sizeY. 614 * 615 * @param inputBitmap The bitmap to be analyzed. 616 * @param restriction When not null, restricts the operation to a 2D range of pixels. 617 * @return The resulting array of counts. 618 */ 619 @JvmOverloads histogramnull620 fun histogram( 621 inputBitmap: Bitmap, 622 restriction: Range2d? = null 623 ): IntArray { 624 validateBitmap("histogram", inputBitmap) 625 validateRestriction("histogram", inputBitmap, restriction) 626 627 val outputArray = IntArray(256 * vectorSize(inputBitmap)) 628 nativeHistogramBitmap(nativeHandle, inputBitmap, outputArray, restriction) 629 return outputArray 630 } 631 632 /** 633 * Compute the histogram of the dot product of an image. 634 * 635 * This method supports cells of 1 to 4 bytes in length. For each cell of the array, 636 * the dot product of its bytes with the provided coefficients is computed. The resulting 637 * floating point value is converted to an unsigned byte and tallied in the histogram. 638 * 639 * If coefficients is null, the coefficients used for RGBA luminosity calculation will be used, 640 * i.e. the values [0.299f, 0.587f, 0.114f, 0.f]. 641 * 642 * Each coefficients must be >= 0 and their sum must be 1.0 or less. There must be the same 643 * number of coefficients as vectorSize. 644 * 645 * A variant of this method is available to do the histogram of a Bitmap. 646 * 647 * An optional range parameter can be set to restrict the operation to a rectangular subset 648 * of each buffer. If provided, the range must be wholly contained with the dimensions 649 * described by sizeX and sizeY. 650 * 651 * The source buffer should be large enough for sizeX * sizeY * vectorSize bytes. The returned 652 * array will have 256 ints. 653 * 654 * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. 655 * 656 * @param inputArray The buffer of the image to be analyzed. 657 * @param vectorSize The number of bytes in each cell, a value from 1 to 4. 658 * @param sizeX The width of the input buffers, as a number of 1 to 4 byte cells. 659 * @param sizeY The height of the input buffers, as a number of 1 to 4 byte cells. 660 * @param coefficients The dot product multipliers. Size should equal vectorSize. Can be null. 661 * @param restriction When not null, restricts the operation to a 2D range of pixels. 662 * @return The resulting vector of counts. 663 */ 664 @JvmOverloads histogramDotnull665 fun histogramDot( 666 inputArray: ByteArray, 667 vectorSize: Int, 668 sizeX: Int, 669 sizeY: Int, 670 coefficients: FloatArray? = null, 671 restriction: Range2d? = null 672 ): IntArray { 673 require(vectorSize in 1..4) { 674 "$externalName histogramDot. The vectorSize should be between 1 and 4. " + 675 "$vectorSize provided." 676 } 677 require(inputArray.size >= sizeX * sizeY * vectorSize) { 678 "$externalName histogramDot. inputArray is too small for the given dimensions. " + 679 "$sizeX*$sizeY*$vectorSize < ${inputArray.size}." 680 } 681 validateHistogramDotCoefficients(coefficients, vectorSize) 682 validateRestriction("histogramDot", sizeX, sizeY, restriction) 683 684 val outputArray = IntArray(256) 685 val actualCoefficients = coefficients ?: floatArrayOf(0.299f, 0.587f, 0.114f, 0f) 686 nativeHistogramDot( 687 nativeHandle, 688 inputArray, 689 vectorSize, 690 sizeX, 691 sizeY, 692 outputArray, 693 actualCoefficients, 694 restriction 695 ) 696 return outputArray 697 } 698 699 /** 700 * Compute the histogram of the dot product of an image. 701 * 702 * This method supports Bitmaps of config ARGB_8888 and ALPHA_8. For each pixel of the bitmap, 703 * the dot product of its bytes with the provided coefficients is computed. The resulting 704 * floating point value is converted to an unsigned byte and tallied in the histogram. 705 * 706 * If coefficients is null, the coefficients used for RGBA luminosity calculation will be used, 707 * i.e. the values [0.299f, 0.587f, 0.114f, 0.f]. 708 * 709 * Each coefficients must be >= 0 and their sum must be 1.0 or less. For ARGB_8888, four values 710 * must be provided; for ALPHA_8, one. 711 * 712 * Bitmaps with a stride different than width * vectorSize are not currently supported. 713 * 714 * A variant of this method is available to do the histogram of a ByteArray. 715 * 716 * An optional range parameter can be set to restrict the operation to a rectangular subset 717 * of each buffer. If provided, the range must be wholly contained with the dimensions 718 * described by sizeX and sizeY. 719 * 720 * The returned array will have 256 ints. 721 * 722 * @param inputBitmap The bitmap to be analyzed. 723 * @param coefficients The one or four values used for the dot product. Can be null. 724 * @param restriction When not null, restricts the operation to a 2D range of pixels. 725 * @return The resulting vector of counts. 726 */ 727 @JvmOverloads histogramDotnull728 fun histogramDot( 729 inputBitmap: Bitmap, 730 coefficients: FloatArray? = null, 731 restriction: Range2d? = null 732 ): IntArray { 733 validateBitmap("histogramDot", inputBitmap) 734 validateHistogramDotCoefficients(coefficients, vectorSize(inputBitmap)) 735 validateRestriction("histogramDot", inputBitmap, restriction) 736 737 val outputArray = IntArray(256) 738 val actualCoefficients = coefficients ?: floatArrayOf(0.299f, 0.587f, 0.114f, 0f) 739 nativeHistogramDotBitmap( 740 nativeHandle, inputBitmap, outputArray, actualCoefficients, restriction 741 ) 742 return outputArray 743 } 744 745 /** 746 * Transform an image using a look up table 747 * 748 * Transforms an image by using a per-channel lookup table. Each channel of the input has an 749 * independent lookup table. The tables are 256 entries in size and can cover the full value 750 * range of a byte. 751 * 752 * The input array should be in RGBA format, where four consecutive bytes form an cell. 753 * A variant of this method is available to transform a Bitmap. 754 * 755 * An optional range parameter can be set to restrict the operation to a rectangular subset 756 * of each buffer. If provided, the range must be wholly contained with the dimensions 757 * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the 758 * section that's not convolved all set to 0. This is to stay compatible with RenderScript. 759 * 760 * The source array should be large enough for sizeX * sizeY * vectorSize bytes. The returned 761 * ray has the same dimensions as the input. The arrays have a row-major layout. 762 * 763 * @param inputArray The buffer of the image to be transformed. 764 * @param sizeX The width of both buffers, as a number of 4 byte cells. 765 * @param sizeY The height of both buffers, as a number of 4 byte cells. 766 * @param table The four arrays of 256 values that's used to convert each channel. 767 * @param restriction When not null, restricts the operation to a 2D range of pixels. 768 * @return The transformed image. 769 */ 770 @JvmOverloads lutnull771 fun lut( 772 inputArray: ByteArray, 773 sizeX: Int, 774 sizeY: Int, 775 table: LookupTable, 776 restriction: Range2d? = null 777 ): ByteArray { 778 require(inputArray.size >= sizeX * sizeY * 4) { 779 "$externalName lut. inputArray is too small for the given dimensions. " + 780 "$sizeX*$sizeY*4 < ${inputArray.size}." 781 } 782 validateRestriction("lut", sizeX, sizeY, restriction) 783 784 val outputArray = ByteArray(inputArray.size) 785 nativeLut( 786 nativeHandle, 787 inputArray, 788 outputArray, 789 sizeX, 790 sizeY, 791 table.red, 792 table.green, 793 table.blue, 794 table.alpha, 795 restriction 796 ) 797 return outputArray 798 } 799 800 /** 801 * Transform an image using a look up table 802 * 803 * Transforms an image by using a per-channel lookup table. Each channel of the input has an 804 * independent lookup table. The tables are 256 entries in size and can cover the full value 805 * range of a byte. 806 * 807 * The input Bitmap should be in config ARGB_8888. A variant of this method is available to 808 * transform a ByteArray. Bitmaps with a stride different than width * vectorSize are not 809 * currently supported. 810 * 811 * An optional range parameter can be set to restrict the operation to a rectangular subset 812 * of each buffer. If provided, the range must be wholly contained with the dimensions 813 * described by sizeX and sizeY. NOTE: The output Bitmap will still be full size, with the 814 * section that's not convolved all set to 0. This is to stay compatible with RenderScript. 815 * 816 * @param inputBitmap The buffer of the image to be transformed. 817 * @param table The four arrays of 256 values that's used to convert each channel. 818 * @param restriction When not null, restricts the operation to a 2D range of pixels. 819 * @return The transformed image. 820 */ 821 @JvmOverloads lutnull822 fun lut( 823 inputBitmap: Bitmap, 824 table: LookupTable, 825 restriction: Range2d? = null 826 ): Bitmap { 827 validateBitmap("lut", inputBitmap) 828 validateRestriction("lut", inputBitmap, restriction) 829 830 val outputBitmap = createCompatibleBitmap(inputBitmap) 831 nativeLutBitmap( 832 nativeHandle, 833 inputBitmap, 834 outputBitmap, 835 table.red, 836 table.green, 837 table.blue, 838 table.alpha, 839 restriction 840 ) 841 return outputBitmap 842 } 843 844 /** 845 * Transform an image using a 3D look up table 846 * 847 * Transforms an image, converting RGB to RGBA by using a 3D lookup table. The incoming R, G, 848 * and B values are normalized to the dimensions of the provided 3D buffer. The eight nearest 849 * values in that 3D buffer are sampled and linearly interpolated. The resulting RGBA entry 850 * is returned in the output array. 851 * 852 * The input array should be in RGBA format, where four consecutive bytes form an cell. 853 * The fourth byte of each input cell is ignored. A variant of this method is also available 854 * to transform Bitmaps. 855 * 856 * An optional range parameter can be set to restrict the operation to a rectangular subset 857 * of each buffer. If provided, the range must be wholly contained with the dimensions 858 * described by sizeX and sizeY. NOTE: The output array will still be full size, with the 859 * section that's not convolved all set to 0. This is to stay compatible with RenderScript. 860 * 861 * The source array should be large enough for sizeX * sizeY * vectorSize bytes. The returned 862 * array will have the same dimensions. The arrays have a row-major layout. 863 * 864 * @param inputArray The buffer of the image to be transformed. 865 * @param sizeX The width of both buffers, as a number of 4 byte cells. 866 * @param sizeY The height of both buffers, as a number of 4 byte cells. 867 * @param cube The translation cube. 868 * @param restriction When not null, restricts the operation to a 2D range of pixels. 869 * @return The transformed image. 870 */ 871 @JvmOverloads lut3dnull872 fun lut3d( 873 inputArray: ByteArray, 874 sizeX: Int, 875 sizeY: Int, 876 cube: Rgba3dArray, 877 restriction: Range2d? = null 878 ): ByteArray { 879 require(inputArray.size >= sizeX * sizeY * 4) { 880 "$externalName lut3d. inputArray is too small for the given dimensions. " + 881 "$sizeX*$sizeY*4 < ${inputArray.size}." 882 } 883 require( 884 cube.sizeX >= 2 && cube.sizeY >= 2 && cube.sizeZ >= 2 && 885 cube.sizeX <= 256 && cube.sizeY <= 256 && cube.sizeZ <= 256 886 ) { 887 "$externalName lut3d. The dimensions of the cube should be between 2 and 256. " + 888 "(${cube.sizeX}, ${cube.sizeY}, ${cube.sizeZ}) provided." 889 } 890 validateRestriction("lut3d", sizeX, sizeY, restriction) 891 892 val outputArray = ByteArray(inputArray.size) 893 nativeLut3d( 894 nativeHandle, inputArray, outputArray, sizeX, sizeY, cube.values, cube.sizeX, 895 cube.sizeY, cube.sizeZ, restriction 896 ) 897 return outputArray 898 } 899 900 /** 901 * Transform an image using a 3D look up table 902 * 903 * Transforms an image, converting RGB to RGBA by using a 3D lookup table. The incoming R, G, 904 * and B values are normalized to the dimensions of the provided 3D buffer. The eight nearest 905 * values in that 3D buffer are sampled and linearly interpolated. The resulting RGBA entry 906 * is returned in the output array. 907 * 908 * The input bitmap should be in RGBA_8888 format. The A channel is preserved. A variant of this 909 * method is also available to transform ByteArray. Bitmaps with a stride different than 910 * width * vectorSize are not currently supported. 911 * 912 * An optional range parameter can be set to restrict the operation to a rectangular subset 913 * of each buffer. If provided, the range must be wholly contained with the dimensions 914 * described by sizeX and sizeY. NOTE: The output array will still be full size, with the 915 * section that's not convolved all set to 0. This is to stay compatible with RenderScript. 916 * 917 * The source array should be large enough for sizeX * sizeY * vectorSize bytes. The returned 918 * array will have the same dimensions. The arrays have a row-major layout. 919 * 920 * @param inputBitmap The image to be transformed. 921 * @param cube The translation cube. 922 * @param restriction When not null, restricts the operation to a 2D range of pixels. 923 * @return The transformed image. 924 */ 925 @JvmOverloads lut3dnull926 fun lut3d( 927 inputBitmap: Bitmap, 928 cube: Rgba3dArray, 929 restriction: Range2d? = null 930 ): Bitmap { 931 validateBitmap("lut3d", inputBitmap) 932 validateRestriction("lut3d", inputBitmap, restriction) 933 934 val outputBitmap = createCompatibleBitmap(inputBitmap) 935 nativeLut3dBitmap( 936 nativeHandle, inputBitmap, outputBitmap, cube.values, cube.sizeX, 937 cube.sizeY, cube.sizeZ, restriction 938 ) 939 return outputBitmap 940 } 941 942 /** 943 * Resize an image. 944 * 945 * Resizes an image using bicubic interpolation. 946 * 947 * This method supports elements of 1 to 4 bytes in length. Each byte of the element is 948 * interpolated independently from the others. 949 * 950 * An optional range parameter can be set to restrict the operation to a rectangular subset 951 * of the output buffer. The corresponding scaled range of the input will be used. If provided, 952 * the range must be wholly contained with the dimensions described by outputSizeX and 953 * outputSizeY. 954 * 955 * The input and output arrays have a row-major layout. The input array should be 956 * large enough for sizeX * sizeY * vectorSize bytes. 957 * 958 * Like the RenderScript Intrinsics, vectorSize of size 3 are padded to occupy 4 bytes. 959 * 960 * @param inputArray The buffer of the image to be resized. 961 * @param vectorSize The number of bytes in each element of both buffers. A value from 1 to 4. 962 * @param inputSizeX The width of the input buffer, as a number of 1-4 byte elements. 963 * @param inputSizeY The height of the input buffer, as a number of 1-4 byte elements. 964 * @param outputSizeX The width of the output buffer, as a number of 1-4 byte elements. 965 * @param outputSizeY The height of the output buffer, as a number of 1-4 byte elements. 966 * @param restriction When not null, restricts the operation to a 2D range of pixels. 967 * @return An array that contains the rescaled image. 968 */ 969 @JvmOverloads resizenull970 fun resize( 971 inputArray: ByteArray, 972 vectorSize: Int, 973 inputSizeX: Int, 974 inputSizeY: Int, 975 outputSizeX: Int, 976 outputSizeY: Int, 977 restriction: Range2d? = null 978 ): ByteArray { 979 require(vectorSize in 1..4) { 980 "$externalName resize. The vectorSize should be between 1 and 4. $vectorSize provided." 981 } 982 require(inputArray.size >= inputSizeX * inputSizeY * vectorSize) { 983 "$externalName resize. inputArray is too small for the given dimensions. " + 984 "$inputSizeX*$inputSizeY*$vectorSize < ${inputArray.size}." 985 } 986 validateRestriction("resize", outputSizeX, outputSizeY, restriction) 987 988 val outputArray = ByteArray(outputSizeX * outputSizeY * paddedSize(vectorSize)) 989 nativeResize( 990 nativeHandle, 991 inputArray, 992 vectorSize, 993 inputSizeX, 994 inputSizeY, 995 outputArray, 996 outputSizeX, 997 outputSizeY, 998 restriction 999 ) 1000 return outputArray 1001 } 1002 1003 /** 1004 * Resize an image. 1005 * 1006 * Resizes an image using bicubic interpolation. 1007 * 1008 * This method supports input Bitmap of config ARGB_8888 and ALPHA_8. The returned Bitmap 1009 * has the same config. Bitmaps with a stride different than width * vectorSize are not 1010 * currently supported. 1011 * 1012 * An optional range parameter can be set to restrict the operation to a rectangular subset 1013 * of the output buffer. The corresponding scaled range of the input will be used. If provided, 1014 * the range must be wholly contained with the dimensions described by outputSizeX and 1015 * outputSizeY. 1016 * 1017 * @param inputBitmap The Bitmap to be resized. 1018 * @param outputSizeX The width of the output buffer, as a number of 1-4 byte elements. 1019 * @param outputSizeY The height of the output buffer, as a number of 1-4 byte elements. 1020 * @param restriction When not null, restricts the operation to a 2D range of pixels. 1021 * @return A Bitmap that contains the rescaled image. 1022 */ 1023 @JvmOverloads resizenull1024 fun resize( 1025 inputBitmap: Bitmap, 1026 outputSizeX: Int, 1027 outputSizeY: Int, 1028 restriction: Range2d? = null 1029 ): Bitmap { 1030 validateBitmap("resize", inputBitmap) 1031 validateRestriction("resize", outputSizeX, outputSizeY, restriction) 1032 1033 val outputBitmap = Bitmap.createBitmap(outputSizeX, outputSizeY, Bitmap.Config.ARGB_8888) 1034 nativeResizeBitmap(nativeHandle, inputBitmap, outputBitmap, restriction) 1035 return outputBitmap 1036 } 1037 1038 /** 1039 * Convert an image from YUV to RGB. 1040 * 1041 * Converts a YUV buffer to RGB. The input array should be supplied in a supported YUV format. 1042 * The output is RGBA; the alpha channel will be set to 255. 1043 * 1044 * Note that for YV12 and a sizeX that's not a multiple of 32, the RenderScript Intrinsic may 1045 * not have converted the image correctly. This Toolkit method should. 1046 * 1047 * @param inputArray The buffer of the image to be converted. 1048 * @param sizeX The width in pixels of the image. 1049 * @param sizeY The height in pixels of the image. 1050 * @param format Either YV12 or NV21. 1051 * @return The converted image as a byte array. 1052 */ yuvToRgbnull1053 fun yuvToRgb(inputArray: ByteArray, sizeX: Int, sizeY: Int, format: YuvFormat): ByteArray { 1054 require(sizeX % 2 == 0 && sizeY % 2 == 0) { 1055 "$externalName yuvToRgb. Non-even dimensions are not supported. " + 1056 "$sizeX and $sizeY were provided." 1057 } 1058 1059 val outputArray = ByteArray(sizeX * sizeY * 4) 1060 nativeYuvToRgb(nativeHandle, inputArray, outputArray, sizeX, sizeY, format.value) 1061 return outputArray 1062 } 1063 1064 /** 1065 * Convert an image from YUV to an RGB Bitmap. 1066 * 1067 * Converts a YUV buffer to an RGB Bitmap. The input array should be supplied in a supported 1068 * YUV format. The output is RGBA; the alpha channel will be set to 255. 1069 * 1070 * Note that for YV12 and a sizeX that's not a multiple of 32, the RenderScript Intrinsic may 1071 * not have converted the image correctly. This Toolkit method should. 1072 * 1073 * @param inputArray The buffer of the image to be converted. 1074 * @param sizeX The width in pixels of the image. 1075 * @param sizeY The height in pixels of the image. 1076 * @param format Either YV12 or NV21. 1077 * @return The converted image. 1078 */ yuvToRgbBitmapnull1079 fun yuvToRgbBitmap(inputArray: ByteArray, sizeX: Int, sizeY: Int, format: YuvFormat): Bitmap { 1080 require(sizeX % 2 == 0 && sizeY % 2 == 0) { 1081 "$externalName yuvToRgbBitmap. Non-even dimensions are not supported. " + 1082 "$sizeX and $sizeY were provided." 1083 } 1084 1085 val outputBitmap = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888) 1086 nativeYuvToRgbBitmap(nativeHandle, inputArray, sizeX, sizeY, outputBitmap, format.value) 1087 return outputBitmap 1088 } 1089 1090 private var nativeHandle: Long = 0 1091 1092 init { 1093 System.loadLibrary("renderscript-toolkit") 1094 nativeHandle = createNative() 1095 } 1096 1097 /** 1098 * Shutdown the thread pool. 1099 * 1100 * Waits for the threads to complete their work and destroys them. 1101 * 1102 * An application should call this method only if it is sure that it won't call the 1103 * toolkit again, as it is irreversible. 1104 */ shutdownnull1105 fun shutdown() { 1106 destroyNative(nativeHandle) 1107 nativeHandle = 0 1108 } 1109 createNativenull1110 private external fun createNative(): Long 1111 1112 private external fun destroyNative(nativeHandle: Long) 1113 1114 private external fun nativeBlend( 1115 nativeHandle: Long, 1116 mode: Int, 1117 sourceArray: ByteArray, 1118 destArray: ByteArray, 1119 sizeX: Int, 1120 sizeY: Int, 1121 restriction: Range2d? 1122 ) 1123 1124 private external fun nativeBlendBitmap( 1125 nativeHandle: Long, 1126 mode: Int, 1127 sourceBitmap: Bitmap, 1128 destBitmap: Bitmap, 1129 restriction: Range2d? 1130 ) 1131 1132 private external fun nativeBlur( 1133 nativeHandle: Long, 1134 inputArray: ByteArray, 1135 vectorSize: Int, 1136 sizeX: Int, 1137 sizeY: Int, 1138 radius: Int, 1139 outputArray: ByteArray, 1140 restriction: Range2d? 1141 ) 1142 1143 private external fun nativeBlurBitmap( 1144 nativeHandle: Long, 1145 inputBitmap: Bitmap, 1146 outputBitmap: Bitmap, 1147 radius: Int, 1148 restriction: Range2d? 1149 ) 1150 1151 private external fun nativeColorMatrix( 1152 nativeHandle: Long, 1153 inputArray: ByteArray, 1154 inputVectorSize: Int, 1155 sizeX: Int, 1156 sizeY: Int, 1157 outputArray: ByteArray, 1158 outputVectorSize: Int, 1159 matrix: FloatArray, 1160 addVector: FloatArray, 1161 restriction: Range2d? 1162 ) 1163 1164 private external fun nativeColorMatrixBitmap( 1165 nativeHandle: Long, 1166 inputBitmap: Bitmap, 1167 outputBitmap: Bitmap, 1168 matrix: FloatArray, 1169 addVector: FloatArray, 1170 restriction: Range2d? 1171 ) 1172 1173 private external fun nativeConvolve( 1174 nativeHandle: Long, 1175 inputArray: ByteArray, 1176 vectorSize: Int, 1177 sizeX: Int, 1178 sizeY: Int, 1179 outputArray: ByteArray, 1180 coefficients: FloatArray, 1181 restriction: Range2d? 1182 ) 1183 1184 private external fun nativeConvolveBitmap( 1185 nativeHandle: Long, 1186 inputBitmap: Bitmap, 1187 outputBitmap: Bitmap, 1188 coefficients: FloatArray, 1189 restriction: Range2d? 1190 ) 1191 1192 private external fun nativeHistogram( 1193 nativeHandle: Long, 1194 inputArray: ByteArray, 1195 vectorSize: Int, 1196 sizeX: Int, 1197 sizeY: Int, 1198 outputArray: IntArray, 1199 restriction: Range2d? 1200 ) 1201 1202 private external fun nativeHistogramBitmap( 1203 nativeHandle: Long, 1204 inputBitmap: Bitmap, 1205 outputArray: IntArray, 1206 restriction: Range2d? 1207 ) 1208 1209 private external fun nativeHistogramDot( 1210 nativeHandle: Long, 1211 inputArray: ByteArray, 1212 vectorSize: Int, 1213 sizeX: Int, 1214 sizeY: Int, 1215 outputArray: IntArray, 1216 coefficients: FloatArray, 1217 restriction: Range2d? 1218 ) 1219 1220 private external fun nativeHistogramDotBitmap( 1221 nativeHandle: Long, 1222 inputBitmap: Bitmap, 1223 outputArray: IntArray, 1224 coefficients: FloatArray, 1225 restriction: Range2d? 1226 ) 1227 1228 private external fun nativeLut( 1229 nativeHandle: Long, 1230 inputArray: ByteArray, 1231 outputArray: ByteArray, 1232 sizeX: Int, 1233 sizeY: Int, 1234 red: ByteArray, 1235 green: ByteArray, 1236 blue: ByteArray, 1237 alpha: ByteArray, 1238 restriction: Range2d? 1239 ) 1240 1241 private external fun nativeLutBitmap( 1242 nativeHandle: Long, 1243 inputBitmap: Bitmap, 1244 outputBitmap: Bitmap, 1245 red: ByteArray, 1246 green: ByteArray, 1247 blue: ByteArray, 1248 alpha: ByteArray, 1249 restriction: Range2d? 1250 ) 1251 1252 private external fun nativeLut3d( 1253 nativeHandle: Long, 1254 inputArray: ByteArray, 1255 outputArray: ByteArray, 1256 sizeX: Int, 1257 sizeY: Int, 1258 cube: ByteArray, 1259 cubeSizeX: Int, 1260 cubeSizeY: Int, 1261 cubeSizeZ: Int, 1262 restriction: Range2d? 1263 ) 1264 1265 private external fun nativeLut3dBitmap( 1266 nativeHandle: Long, 1267 inputBitmap: Bitmap, 1268 outputBitmap: Bitmap, 1269 cube: ByteArray, 1270 cubeSizeX: Int, 1271 cubeSizeY: Int, 1272 cubeSizeZ: Int, 1273 restriction: Range2d? 1274 ) 1275 1276 private external fun nativeResize( 1277 nativeHandle: Long, 1278 inputArray: ByteArray, 1279 vectorSize: Int, 1280 inputSizeX: Int, 1281 inputSizeY: Int, 1282 outputArray: ByteArray, 1283 outputSizeX: Int, 1284 outputSizeY: Int, 1285 restriction: Range2d? 1286 ) 1287 1288 private external fun nativeResizeBitmap( 1289 nativeHandle: Long, 1290 inputBitmap: Bitmap, 1291 outputBitmap: Bitmap, 1292 restriction: Range2d? 1293 ) 1294 1295 private external fun nativeYuvToRgb( 1296 nativeHandle: Long, 1297 inputArray: ByteArray, 1298 outputArray: ByteArray, 1299 sizeX: Int, 1300 sizeY: Int, 1301 format: Int 1302 ) 1303 1304 private external fun nativeYuvToRgbBitmap( 1305 nativeHandle: Long, 1306 inputArray: ByteArray, 1307 sizeX: Int, 1308 sizeY: Int, 1309 outputBitmap: Bitmap, 1310 value: Int 1311 ) 1312 } 1313 1314 /** 1315 * Determines how a source buffer is blended into a destination buffer. 1316 * See {@link RenderScriptToolkit::blend}. 1317 * 1318 * blend only works on 4 byte RGBA data. In the descriptions below, ".a" represents 1319 * the alpha channel. 1320 */ 1321 enum class BlendingMode(val value: Int) { 1322 /** 1323 * dest = 0 1324 * 1325 * The destination is cleared, i.e. each pixel is set to (0, 0, 0, 0) 1326 */ 1327 CLEAR(0), 1328 1329 /** 1330 * dest = src 1331 * 1332 * Sets each pixel of the destination to the corresponding one in the source. 1333 */ 1334 SRC(1), 1335 1336 /** 1337 * dest = dest 1338 * 1339 * Leaves the destination untouched. This is a no-op. 1340 */ 1341 DST(2), 1342 1343 /** 1344 * dest = src + dest * (1.0 - src.a) 1345 */ 1346 SRC_OVER(3), 1347 1348 /** 1349 * dest = dest + src * (1.0 - dest.a) 1350 */ 1351 DST_OVER(4), 1352 1353 /** 1354 * dest = src * dest.a 1355 */ 1356 SRC_IN(5), 1357 1358 /** 1359 * dest = dest * src.a 1360 */ 1361 DST_IN(6), 1362 1363 /** 1364 * dest = src * (1.0 - dest.a) 1365 */ 1366 SRC_OUT(7), 1367 1368 /** 1369 * dest = dest * (1.0 - src.a) 1370 */ 1371 DST_OUT(8), 1372 1373 /** 1374 * dest.rgb = src.rgb * dest.a + (1.0 - src.a) * dest.rgb, dest.a = dest.a 1375 */ 1376 SRC_ATOP(9), 1377 1378 /** 1379 * dest = dest.rgb * src.a + (1.0 - dest.a) * src.rgb, dest.a = src.a 1380 */ 1381 DST_ATOP(10), 1382 1383 /** 1384 * dest = {src.r ^ dest.r, src.g ^ dest.g, src.b ^ dest.b, src.a ^ dest.a} 1385 * 1386 * Note: this is NOT the Porter/Duff XOR mode; this is a bitwise xor. 1387 */ 1388 XOR(11), 1389 1390 /** 1391 * dest = src * dest 1392 */ 1393 MULTIPLY(12), 1394 1395 /** 1396 * dest = min(src + dest, 1.0) 1397 */ 1398 ADD(13), 1399 1400 /** 1401 * dest = max(dest - src, 0.0) 1402 */ 1403 SUBTRACT(14) 1404 } 1405 1406 /** 1407 * A translation table used by the lut method. For each potential red, green, blue, and alpha 1408 * value, specifies it's replacement value. 1409 * 1410 * The fields are initialized to be a no-op operation, i.e. replace 1 by 1, 2 by 2, etc. 1411 * You can modify just the values you're interested in having a translation. 1412 */ 1413 class LookupTable { <lambda>null1414 var red = ByteArray(256) { it.toByte() } <lambda>null1415 var green = ByteArray(256) { it.toByte() } <lambda>null1416 var blue = ByteArray(256) { it.toByte() } <lambda>null1417 var alpha = ByteArray(256) { it.toByte() } 1418 } 1419 1420 /** 1421 * The YUV formats supported by yuvToRgb. 1422 */ 1423 enum class YuvFormat(val value: Int) { 1424 NV21(0x11), 1425 YV12(0x32315659), 1426 } 1427 1428 /** 1429 * Define a range of data to process. 1430 * 1431 * This class is used to restrict a [Toolkit] operation to a rectangular subset of the input 1432 * tensor. 1433 * 1434 * @property startX The index of the first value to be included on the X axis. 1435 * @property endX The index after the last value to be included on the X axis. 1436 * @property startY The index of the first value to be included on the Y axis. 1437 * @property endY The index after the last value to be included on the Y axis. 1438 */ 1439 data class Range2d( 1440 val startX: Int, 1441 val endX: Int, 1442 val startY: Int, 1443 val endY: Int 1444 ) { 1445 constructor() : this(0, 0, 0, 0) 1446 } 1447 1448 class Rgba3dArray(val values: ByteArray, val sizeX: Int, val sizeY: Int, val sizeZ: Int) { 1449 init { 1450 require(values.size >= sizeX * sizeY * sizeZ * 4) 1451 } 1452 getnull1453 operator fun get(x: Int, y: Int, z: Int): ByteArray { 1454 val index = indexOfVector(x, y, z) 1455 return ByteArray(4) { values[index + it] } 1456 } 1457 setnull1458 operator fun set(x: Int, y: Int, z: Int, value: ByteArray) { 1459 require(value.size == 4) 1460 val index = indexOfVector(x, y, z) 1461 for (i in 0..3) { 1462 values[index + i] = value[i] 1463 } 1464 } 1465 indexOfVectornull1466 private fun indexOfVector(x: Int, y: Int, z: Int): Int { 1467 require(x in 0 until sizeX) 1468 require(y in 0 until sizeY) 1469 require(z in 0 until sizeZ) 1470 return ((z * sizeY + y) * sizeX + x) * 4 1471 } 1472 } 1473 validateBitmapnull1474 internal fun validateBitmap( 1475 function: String, 1476 inputBitmap: Bitmap, 1477 alphaAllowed: Boolean = true 1478 ) { 1479 if (alphaAllowed) { 1480 require( 1481 inputBitmap.config == Bitmap.Config.ARGB_8888 || 1482 inputBitmap.config == Bitmap.Config.ALPHA_8 1483 ) { 1484 "$externalName. $function supports only ARGB_8888 and ALPHA_8 bitmaps. " + 1485 "${inputBitmap.config} provided." 1486 } 1487 } else { 1488 require(inputBitmap.config == Bitmap.Config.ARGB_8888) { 1489 "$externalName. $function supports only ARGB_8888. " + 1490 "${inputBitmap.config} provided." 1491 } 1492 } 1493 require(inputBitmap.width * vectorSize(inputBitmap) == inputBitmap.rowBytes) { 1494 "$externalName $function. Only bitmaps with rowSize equal to the width * vectorSize are " + 1495 "currently supported. Provided were rowBytes=${inputBitmap.rowBytes}, " + 1496 "width={${inputBitmap.width}, and vectorSize=${vectorSize(inputBitmap)}." 1497 } 1498 } 1499 createCompatibleBitmapnull1500 internal fun createCompatibleBitmap(inputBitmap: Bitmap) = 1501 Bitmap.createBitmap(inputBitmap.width, inputBitmap.height, inputBitmap.config!!) 1502 1503 internal fun validateHistogramDotCoefficients( 1504 coefficients: FloatArray?, 1505 vectorSize: Int 1506 ) { 1507 require(coefficients == null || coefficients.size == vectorSize) { 1508 "$externalName histogramDot. The coefficients should be null or have $vectorSize values." 1509 } 1510 if (coefficients !== null) { 1511 var sum = 0f 1512 for (i in 0 until vectorSize) { 1513 require(coefficients[i] >= 0.0f) { 1514 "$externalName histogramDot. Coefficients should not be negative. " + 1515 "Coefficient $i was ${coefficients[i]}." 1516 } 1517 sum += coefficients[i] 1518 } 1519 require(sum <= 1.0f) { 1520 "$externalName histogramDot. Coefficients should add to 1 or less. Their sum is $sum." 1521 } 1522 } 1523 } 1524 validateRestrictionnull1525 internal fun validateRestriction(tag: String, bitmap: Bitmap, restriction: Range2d? = null) { 1526 validateRestriction(tag, bitmap.width, bitmap.height, restriction) 1527 } 1528 validateRestrictionnull1529 internal fun validateRestriction( 1530 tag: String, 1531 sizeX: Int, 1532 sizeY: Int, 1533 restriction: Range2d? = null 1534 ) { 1535 if (restriction == null) return 1536 require(restriction.startX < sizeX && restriction.endX <= sizeX) { 1537 "$externalName $tag. sizeX should be greater than restriction.startX and greater " + 1538 "or equal to restriction.endX. $sizeX, ${restriction.startX}, " + 1539 "and ${restriction.endX} were provided respectively." 1540 } 1541 require(restriction.startY < sizeY && restriction.endY <= sizeY) { 1542 "$externalName $tag. sizeY should be greater than restriction.startY and greater " + 1543 "or equal to restriction.endY. $sizeY, ${restriction.startY}, " + 1544 "and ${restriction.endY} were provided respectively." 1545 } 1546 require(restriction.startX < restriction.endX) { 1547 "$externalName $tag. Restriction startX should be less than endX. " + 1548 "${restriction.startX} and ${restriction.endX} were provided respectively." 1549 } 1550 require(restriction.startY < restriction.endY) { 1551 "$externalName $tag. Restriction startY should be less than endY. " + 1552 "${restriction.startY} and ${restriction.endY} were provided respectively." 1553 } 1554 } 1555 vectorSizenull1556 internal fun vectorSize(bitmap: Bitmap): Int { 1557 return when (bitmap.config) { 1558 Bitmap.Config.ARGB_8888 -> 4 1559 Bitmap.Config.ALPHA_8 -> 1 1560 else -> throw IllegalArgumentException( 1561 "$externalName. Only ARGB_8888 and ALPHA_8 Bitmap are supported." 1562 ) 1563 } 1564 } 1565 paddedSizenull1566 internal fun paddedSize(vectorSize: Int) = if (vectorSize == 3) 4 else vectorSize 1567