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