pnmFileTypeAndroidWriter.cxx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file pnmFileTypeAndroidWriter.cxx
  10. * @author rdb
  11. * @date 2018-02-10
  12. */
  13. #include "pnmFileTypeAndroid.h"
  14. #ifdef ANDROID
  15. #include "config_pnmimagetypes.h"
  16. #include <android/bitmap.h>
  17. #include <jni.h>
  18. // See android/graphics/Bitmap.java
  19. enum class BitmapConfig : jint {
  20. ALPHA_8 = 1,
  21. RGB_565 = 3,
  22. ARGB_4444 = 4,
  23. ARGB_8888 = 5,
  24. RGBA_F16 = 6,
  25. HARDWARE = 7,
  26. };
  27. /**
  28. *
  29. */
  30. PNMFileTypeAndroid::Writer::
  31. Writer(PNMFileType *type, std::ostream *file, bool owns_file,
  32. CompressFormat format) :
  33. PNMWriter(type, file, owns_file),
  34. _format(format)
  35. {
  36. }
  37. /**
  38. * Writes out an entire image all at once, including the header, based on the
  39. * image data stored in the given _x_size * _y_size array and alpha pointers.
  40. * (If the image type has no alpha channel, alpha is ignored.) Returns the
  41. * number of rows correctly written.
  42. *
  43. * It is the user's responsibility to fill in the header data via calls to
  44. * set_x_size(), set_num_channels(), etc., or copy_header_from(), before
  45. * calling write_data().
  46. *
  47. * It is important to delete the PNMWriter class after successfully writing
  48. * the data. Failing to do this may result in some data not getting flushed!
  49. *
  50. * Derived classes need not override this if they instead provide
  51. * supports_streaming() and write_row(), below.
  52. */
  53. int PNMFileTypeAndroid::Writer::
  54. write_data(xel *array, xelval *alpha) {
  55. size_t num_pixels = (size_t)_x_size * (size_t)_y_size;
  56. Thread *current_thread = Thread::get_current_thread();
  57. JNIEnv *env = current_thread->get_jni_env();
  58. nassertr(env != nullptr, 0);
  59. // Create a Bitmap object.
  60. jobject bitmap =
  61. env->CallStaticObjectMethod(jni_PandaActivity,
  62. jni_PandaActivity_createBitmap,
  63. (jint)_x_size, (jint)_y_size,
  64. BitmapConfig::ARGB_8888,
  65. (jboolean)has_alpha());
  66. nassertr(bitmap != nullptr, 0);
  67. // Get a writable pointer to write our pixel data to.
  68. uint32_t *out;
  69. int rc = AndroidBitmap_lockPixels(env, bitmap, (void **)&out);
  70. if (rc != 0) {
  71. android_cat.error()
  72. << "Could not lock bitmap pixels (result code " << rc << ")\n";
  73. return 0;
  74. }
  75. if (_maxval == 255) {
  76. if (has_alpha() && alpha != nullptr) {
  77. for (size_t i = 0; i < num_pixels; ++i) {
  78. out[i] = (array[i].r)
  79. | (array[i].g << 8u)
  80. | (array[i].b << 16u)
  81. | (alpha[i] << 24u);
  82. }
  83. } else {
  84. for (size_t i = 0; i < num_pixels; ++i) {
  85. out[i] = (array[i].r)
  86. | (array[i].g << 8u)
  87. | (array[i].b << 16u)
  88. | 0xff000000u;
  89. }
  90. }
  91. } else {
  92. double ratio = 255.0 / _maxval;
  93. if (has_alpha() && alpha != nullptr) {
  94. for (size_t i = 0; i < num_pixels; ++i) {
  95. out[i] = ((uint32_t)(array[i].r * ratio))
  96. | ((uint32_t)(array[i].g * ratio) << 8u)
  97. | ((uint32_t)(array[i].b * ratio) << 16u)
  98. | ((uint32_t)(alpha[i] * ratio) << 24u);
  99. }
  100. } else {
  101. for (size_t i = 0; i < num_pixels; ++i) {
  102. out[i] = ((uint32_t)(array[i].r * ratio))
  103. | ((uint32_t)(array[i].g * ratio) << 8u)
  104. | ((uint32_t)(array[i].b * ratio) << 16u)
  105. | 0xff000000u;
  106. }
  107. }
  108. }
  109. // Finally, unlock the pixel data and compress it to the ostream.
  110. AndroidBitmap_unlockPixels(env, bitmap);
  111. jboolean res =
  112. env->CallStaticBooleanMethod(jni_PandaActivity,
  113. jni_PandaActivity_compressBitmap,
  114. bitmap, _format, 85, (jlong)_file);
  115. if (!res) {
  116. android_cat.error()
  117. << "Failed to compress bitmap.\n";
  118. return 0;
  119. }
  120. return _y_size;
  121. }
  122. /**
  123. * Returns true if this particular PNMWriter understands grayscale images. If
  124. * this is false, then the rgb values of the xel array will be pre-filled with
  125. * the same value across all three channels, to allow the writer to simply
  126. * write out RGB data for a grayscale image.
  127. */
  128. bool PNMFileTypeAndroid::Writer::
  129. supports_grayscale() const {
  130. return false;
  131. }
  132. #endif // ANDROID