mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
android: support writing png/jpg/webp via android.graphics.Bitmap
This commit is contained in:
parent
854d736882
commit
6bd1976892
@ -5100,7 +5100,8 @@ if (not RTDIST and not RUNTIME and PkgSkip("PVIEW")==0 and GetTarget() != 'andro
|
||||
if (not RUNTIME and GetTarget() == 'android'):
|
||||
OPTS=['DIR:panda/src/android']
|
||||
TargetAdd('org/panda3d/android/NativeIStream.class', opts=OPTS, input='NativeIStream.java')
|
||||
TargetAdd('org/panda3d/android/PandaActivity.class', opts=OPTS, input='PandaActivity.java', dep='org/panda3d/android/NativeIStream.class')
|
||||
TargetAdd('org/panda3d/android/NativeOStream.class', opts=OPTS, input='NativeOStream.java')
|
||||
TargetAdd('org/panda3d/android/PandaActivity.class', opts=OPTS, input='PandaActivity.java')
|
||||
|
||||
TargetAdd('p3android_composite1.obj', opts=OPTS, input='p3android_composite1.cxx')
|
||||
TargetAdd('libp3android.dll', input='p3android_composite1.obj')
|
||||
|
52
panda/src/android/NativeOStream.java
Normal file
52
panda/src/android/NativeOStream.java
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file NativeOStream.java
|
||||
* @author rdb
|
||||
* @date 2018-02-10
|
||||
*/
|
||||
|
||||
package org.panda3d.android;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* An implementation of OutputStream that puts its data into a C++ ostream
|
||||
* pointer, passed as long.
|
||||
*/
|
||||
public class NativeOStream extends OutputStream {
|
||||
private long streamPtr = 0;
|
||||
|
||||
public NativeOStream(long ptr) {
|
||||
streamPtr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
nativeFlush(streamPtr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
nativePut(streamPtr, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) {
|
||||
nativeWrite(streamPtr, buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int length) {
|
||||
nativeWrite(streamPtr, buffer, offset, length);
|
||||
}
|
||||
|
||||
private static native void nativeFlush(long ptr);
|
||||
private static native void nativePut(long ptr, int b);
|
||||
private static native void nativeWrite(long ptr, byte[] buffer, int offset, int length);
|
||||
}
|
@ -20,12 +20,29 @@ import android.widget.Toast;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import org.panda3d.android.NativeIStream;
|
||||
import org.panda3d.android.NativeOStream;
|
||||
|
||||
/**
|
||||
* The entry point for a Panda-based activity. Loads the Panda libraries and
|
||||
* also provides some utility functions.
|
||||
*/
|
||||
public class PandaActivity extends NativeActivity {
|
||||
private static final Bitmap.Config sConfigs[] = {
|
||||
null,
|
||||
Bitmap.Config.ALPHA_8,
|
||||
null,
|
||||
Bitmap.Config.RGB_565,
|
||||
Bitmap.Config.ARGB_4444,
|
||||
Bitmap.Config.ARGB_8888,
|
||||
null, //Bitmap.Config.RGBA_F16,
|
||||
null, //Bitmap.Config.HARDWARE,
|
||||
};
|
||||
private static final Bitmap.CompressFormat sFormats[] = {
|
||||
Bitmap.CompressFormat.JPEG,
|
||||
Bitmap.CompressFormat.PNG,
|
||||
Bitmap.CompressFormat.WEBP,
|
||||
};
|
||||
|
||||
protected static BitmapFactory.Options readBitmapSize(long istreamPtr) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
@ -44,6 +61,15 @@ public class PandaActivity extends NativeActivity {
|
||||
return BitmapFactory.decodeStream(stream, null, options);
|
||||
}
|
||||
|
||||
protected static Bitmap createBitmap(int width, int height, int config, boolean hasAlpha) {
|
||||
return Bitmap.createBitmap(width, height, sConfigs[config]);
|
||||
}
|
||||
|
||||
protected static boolean compressBitmap(Bitmap bitmap, int format, int quality, long ostreamPtr) {
|
||||
NativeOStream stream = new NativeOStream(ostreamPtr);
|
||||
return bitmap.compress(sFormats[format], quality, stream);
|
||||
}
|
||||
|
||||
protected static String getCurrentThreadName() {
|
||||
return Thread.currentThread().getName();
|
||||
}
|
||||
|
@ -24,12 +24,24 @@ struct android_app *panda_android_app = NULL;
|
||||
jclass jni_PandaActivity;
|
||||
jmethodID jni_PandaActivity_readBitmapSize;
|
||||
jmethodID jni_PandaActivity_readBitmap;
|
||||
jmethodID jni_PandaActivity_createBitmap;
|
||||
jmethodID jni_PandaActivity_compressBitmap;
|
||||
jmethodID jni_PandaActivity_showToast;
|
||||
|
||||
jclass jni_BitmapFactory_Options;
|
||||
jfieldID jni_BitmapFactory_Options_outWidth;
|
||||
jfieldID jni_BitmapFactory_Options_outHeight;
|
||||
|
||||
#ifndef HAVE_JPEG
|
||||
static PNMFileTypeAndroid file_type_jpeg(PNMFileTypeAndroid::CF_jpeg);
|
||||
#endif
|
||||
#ifndef HAVE_PNG
|
||||
static PNMFileTypeAndroid file_type_png(PNMFileTypeAndroid::CF_png);
|
||||
#endif
|
||||
#if __ANDROID_API__ >= 14
|
||||
static PNMFileTypeAndroid file_type_webp(PNMFileTypeAndroid::CF_webp);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes the library. This must be called at least once before any of
|
||||
* the functions or classes in this library can be used. Normally, this is
|
||||
@ -37,10 +49,6 @@ jfieldID jni_BitmapFactory_Options_outHeight;
|
||||
*/
|
||||
void
|
||||
init_libandroid() {
|
||||
PNMFileTypeRegistry *tr = PNMFileTypeRegistry::get_global_ptr();
|
||||
PNMFileTypeAndroid::init_type();
|
||||
PNMFileTypeAndroid::register_with_read_factory();
|
||||
tr->register_type(new PNMFileTypeAndroid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +56,7 @@ init_libandroid() {
|
||||
* references and the method IDs.
|
||||
*/
|
||||
jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||
init_libandroid();
|
||||
//init_libandroid();
|
||||
|
||||
Thread *thread = Thread::get_current_thread();
|
||||
JNIEnv *env = thread->get_jni_env();
|
||||
@ -63,6 +71,12 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||
jni_PandaActivity_readBitmap = env->GetStaticMethodID(jni_PandaActivity,
|
||||
"readBitmap", "(JI)Landroid/graphics/Bitmap;");
|
||||
|
||||
jni_PandaActivity_createBitmap = env->GetStaticMethodID(jni_PandaActivity,
|
||||
"createBitmap", "(IIIZ)Landroid/graphics/Bitmap;");
|
||||
|
||||
jni_PandaActivity_compressBitmap = env->GetStaticMethodID(jni_PandaActivity,
|
||||
"compressBitmap", "(Landroid/graphics/Bitmap;IIJ)Z");
|
||||
|
||||
jni_PandaActivity_showToast = env->GetMethodID(jni_PandaActivity,
|
||||
"showToast", "(Ljava/lang/String;I)V");
|
||||
|
||||
@ -72,6 +86,25 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||
jni_BitmapFactory_Options_outWidth = env->GetFieldID(jni_BitmapFactory_Options, "outWidth", "I");
|
||||
jni_BitmapFactory_Options_outHeight = env->GetFieldID(jni_BitmapFactory_Options, "outHeight", "I");
|
||||
|
||||
nassertr(jni_PandaActivity_readBitmapSize, -1);
|
||||
nassertr(jni_PandaActivity_readBitmap, -1);
|
||||
nassertr(jni_PandaActivity_createBitmap, -1);
|
||||
nassertr(jni_PandaActivity_compressBitmap, -1);
|
||||
nassertr(jni_PandaActivity_showToast, -1);
|
||||
|
||||
// We put this in JNI_OnLoad because it relies on Java classes, which
|
||||
// are only available when launched from the Java VM.
|
||||
PNMFileTypeRegistry *tr = PNMFileTypeRegistry::get_global_ptr();
|
||||
#ifndef HAVE_JPEG
|
||||
tr->register_type(&file_type_jpeg);
|
||||
#endif
|
||||
#ifndef HAVE_PNG
|
||||
tr->register_type(&file_type_png);
|
||||
#endif
|
||||
#if __ANDROID_API__ >= 14
|
||||
tr->register_type(&file_type_webp);
|
||||
#endif
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
@ -86,6 +119,20 @@ void JNI_OnUnload(JavaVM *jvm, void *reserved) {
|
||||
|
||||
env->DeleteGlobalRef(jni_PandaActivity);
|
||||
env->DeleteGlobalRef(jni_BitmapFactory_Options);
|
||||
|
||||
// These will no longer work without JNI, so unregister them.
|
||||
PNMFileTypeRegistry *tr = PNMFileTypeRegistry::get_global_ptr();
|
||||
if (tr != nullptr) {
|
||||
#ifndef HAVE_JPEG
|
||||
tr->unregister_type(&file_type_jpeg);
|
||||
#endif
|
||||
#ifndef HAVE_PNG
|
||||
tr->unregister_type(&file_type_png);
|
||||
#endif
|
||||
#if __ANDROID_API__ >= 14
|
||||
tr->unregister_type(&file_type_webp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,8 @@ extern EXPORT_CLASS struct android_app* panda_android_app;
|
||||
extern jclass jni_PandaActivity;
|
||||
extern jmethodID jni_PandaActivity_readBitmapHeader;
|
||||
extern jmethodID jni_PandaActivity_readBitmap;
|
||||
extern jmethodID jni_PandaActivity_createBitmap;
|
||||
extern jmethodID jni_PandaActivity_compressBitmap;
|
||||
extern jmethodID jni_PandaActivity_showToast;
|
||||
|
||||
extern jclass jni_BitmapFactory_Options;
|
||||
|
54
panda/src/android/jni_NativeOStream.cxx
Normal file
54
panda/src/android/jni_NativeOStream.cxx
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file jni_NativeOStream.cxx
|
||||
* @author rdb
|
||||
* @date 2018-02-10
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#if __GNUC__ >= 4
|
||||
#define EXPORT_JNI extern "C" __attribute__((visibility("default")))
|
||||
#else
|
||||
#define EXPORT_JNI extern "C"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flushes the stream.
|
||||
*/
|
||||
EXPORT_JNI void
|
||||
Java_org_panda3d_android_NativeOStream_nativeFlush(JNIEnv *env, jclass clazz, jlong ptr) {
|
||||
std::ostream *stream = (std::ostream *)ptr;
|
||||
|
||||
stream->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a single character to the ostream.
|
||||
*/
|
||||
EXPORT_JNI void
|
||||
Java_org_panda3d_android_NativeOStream_nativePut(JNIEnv *env, jclass clazz, jlong ptr, int b) {
|
||||
std::ostream *stream = (std::ostream *)ptr;
|
||||
|
||||
stream->put((char)(b & 0xff));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes to the ostream.
|
||||
*/
|
||||
EXPORT_JNI void
|
||||
Java_org_panda3d_android_NativeOStream_nativeWrite(JNIEnv *env, jclass clazz, jlong ptr, jbyteArray byte_array, jint offset, jint length) {
|
||||
std::ostream *stream = (std::ostream *)ptr;
|
||||
|
||||
jbyte *buffer = (jbyte *)alloca(length);
|
||||
env->GetByteArrayRegion(byte_array, offset, length, buffer);
|
||||
stream->write((char *)buffer, length);
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
#include "config_android.cxx"
|
||||
#include "jni_NativeIStream.cxx"
|
||||
#include "jni_NativeOStream.cxx"
|
||||
#include "pnmFileTypeAndroid.cxx"
|
||||
#include "pnmFileTypeAndroidReader.cxx"
|
||||
#include "pnmFileTypeAndroidReader.cxx"
|
||||
#include "pnmFileTypeAndroidWriter.cxx"
|
||||
|
@ -17,24 +17,11 @@
|
||||
|
||||
#include "config_pnmimagetypes.h"
|
||||
|
||||
#include "pnmFileTypeRegistry.h"
|
||||
#include "bamReader.h"
|
||||
|
||||
static const char * const extensions_android[] = {
|
||||
"jpg", "jpeg", "gif", "png",
|
||||
#if __ANDROID_API__ >= 14
|
||||
"webp"
|
||||
#endif
|
||||
};
|
||||
static const int num_extensions_android = sizeof(extensions_android) / sizeof(const char *);
|
||||
|
||||
TypeHandle PNMFileTypeAndroid::_type_handle;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PNMFileTypeAndroid::
|
||||
PNMFileTypeAndroid() {
|
||||
PNMFileTypeAndroid(CompressFormat format) : _format(format) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,7 +38,16 @@ get_name() const {
|
||||
*/
|
||||
int PNMFileTypeAndroid::
|
||||
get_num_extensions() const {
|
||||
return num_extensions_android;
|
||||
switch (_format) {
|
||||
case CF_jpeg:
|
||||
return 3;
|
||||
case CF_png:
|
||||
return 1;
|
||||
case CF_webp:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,8 +56,17 @@ get_num_extensions() const {
|
||||
*/
|
||||
string PNMFileTypeAndroid::
|
||||
get_extension(int n) const {
|
||||
nassertr(n >= 0 && n < num_extensions_android, string());
|
||||
return extensions_android[n];
|
||||
static const char *const jpeg_extensions[] = {"jpg", "jpeg", "jpe"};
|
||||
switch (_format) {
|
||||
case CF_jpeg:
|
||||
return jpeg_extensions[n];
|
||||
case CF_png:
|
||||
return "png";
|
||||
case CF_webp:
|
||||
return "webp";
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,30 +85,17 @@ has_magic_number() const {
|
||||
*/
|
||||
PNMReader *PNMFileTypeAndroid::
|
||||
make_reader(istream *file, bool owns_file, const string &magic_number) {
|
||||
init_pnm();
|
||||
return new Reader(this, file, owns_file, magic_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the current object as something that can be read from a Bam file.
|
||||
* Allocates and returns a new PNMWriter suitable for reading from this file
|
||||
* type, if possible. If writing files of this type is not supported, returns
|
||||
* NULL.
|
||||
*/
|
||||
void PNMFileTypeAndroid::
|
||||
register_with_read_factory() {
|
||||
BamReader::get_factory()->
|
||||
register_factory(get_class_type(), make_PNMFileTypeAndroid);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by the BamReader when an object of this type is
|
||||
* encountered in a Bam file; it should allocate and return a new object with
|
||||
* all the data read.
|
||||
*
|
||||
* In the case of the PNMFileType objects, since these objects are all shared,
|
||||
* we just pull the object from the registry.
|
||||
*/
|
||||
TypedWritable *PNMFileTypeAndroid::
|
||||
make_PNMFileTypeAndroid(const FactoryParams ¶ms) {
|
||||
return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
|
||||
PNMWriter *PNMFileTypeAndroid::
|
||||
make_writer(ostream *file, bool owns_file) {
|
||||
return new Writer(this, file, owns_file, _format);
|
||||
}
|
||||
|
||||
#endif // ANDROID
|
||||
|
@ -30,7 +30,13 @@
|
||||
*/
|
||||
class EXPCL_PANDA_PNMIMAGETYPES PNMFileTypeAndroid : public PNMFileType {
|
||||
public:
|
||||
PNMFileTypeAndroid();
|
||||
enum CompressFormat : jint {
|
||||
CF_jpeg = 0,
|
||||
CF_png = 1,
|
||||
CF_webp = 2,
|
||||
};
|
||||
|
||||
PNMFileTypeAndroid(CompressFormat format);
|
||||
|
||||
virtual string get_name() const;
|
||||
|
||||
@ -41,6 +47,7 @@ public:
|
||||
|
||||
virtual PNMReader *make_reader(istream *file, bool owns_file = true,
|
||||
const string &magic_number = string());
|
||||
virtual PNMWriter *make_writer(ostream *file, bool owns_file = true);
|
||||
|
||||
public:
|
||||
class Reader : public PNMReader {
|
||||
@ -60,29 +67,20 @@ public:
|
||||
int32_t _format;
|
||||
};
|
||||
|
||||
// The TypedWritable interface follows.
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
class Writer : public PNMWriter {
|
||||
public:
|
||||
Writer(PNMFileType *type, ostream *file, bool owns_file,
|
||||
CompressFormat format);
|
||||
|
||||
protected:
|
||||
static TypedWritable *make_PNMFileTypeAndroid(const FactoryParams ¶ms);
|
||||
virtual int write_data(xel *array, xelval *alpha);
|
||||
virtual bool supports_grayscale() const;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
PNMFileType::init_type();
|
||||
register_type(_type_handle, "PNMFileTypeAndroid",
|
||||
PNMFileType::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
private:
|
||||
CompressFormat _format;
|
||||
};
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
CompressFormat _format;
|
||||
};
|
||||
|
||||
#endif // ANDROID
|
||||
|
146
panda/src/android/pnmFileTypeAndroidWriter.cxx
Normal file
146
panda/src/android/pnmFileTypeAndroidWriter.cxx
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file pnmFileTypeAndroidWriter.cxx
|
||||
* @author rdb
|
||||
* @date 2018-02-10
|
||||
*/
|
||||
|
||||
#include "pnmFileTypeAndroid.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
#include "config_pnmimagetypes.h"
|
||||
|
||||
#include <android/bitmap.h>
|
||||
#include <jni.h>
|
||||
|
||||
// See android/graphics/Bitmap.java
|
||||
enum class BitmapConfig : jint {
|
||||
ALPHA_8 = 1,
|
||||
RGB_565 = 3,
|
||||
ARGB_4444 = 4,
|
||||
ARGB_8888 = 5,
|
||||
RGBA_F16 = 6,
|
||||
HARDWARE = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PNMFileTypeAndroid::Writer::
|
||||
Writer(PNMFileType *type, ostream *file, bool owns_file,
|
||||
CompressFormat format) :
|
||||
PNMWriter(type, file, owns_file),
|
||||
_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out an entire image all at once, including the header, based on the
|
||||
* image data stored in the given _x_size * _y_size array and alpha pointers.
|
||||
* (If the image type has no alpha channel, alpha is ignored.) Returns the
|
||||
* number of rows correctly written.
|
||||
*
|
||||
* It is the user's responsibility to fill in the header data via calls to
|
||||
* set_x_size(), set_num_channels(), etc., or copy_header_from(), before
|
||||
* calling write_data().
|
||||
*
|
||||
* It is important to delete the PNMWriter class after successfully writing
|
||||
* the data. Failing to do this may result in some data not getting flushed!
|
||||
*
|
||||
* Derived classes need not override this if they instead provide
|
||||
* supports_streaming() and write_row(), below.
|
||||
*/
|
||||
int PNMFileTypeAndroid::Writer::
|
||||
write_data(xel *array, xelval *alpha) {
|
||||
size_t num_pixels = (size_t)_x_size * (size_t)_y_size;
|
||||
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
JNIEnv *env = current_thread->get_jni_env();
|
||||
nassertr(env != nullptr, 0);
|
||||
|
||||
// Create a Bitmap object.
|
||||
jobject bitmap =
|
||||
env->CallStaticObjectMethod(jni_PandaActivity,
|
||||
jni_PandaActivity_createBitmap,
|
||||
(jint)_x_size, (jint)_y_size,
|
||||
BitmapConfig::ARGB_8888,
|
||||
(jboolean)has_alpha());
|
||||
nassertr(bitmap != nullptr, 0);
|
||||
|
||||
// Get a writable pointer to write our pixel data to.
|
||||
uint32_t *out;
|
||||
int rc = AndroidBitmap_lockPixels(env, bitmap, (void **)&out);
|
||||
if (rc != 0) {
|
||||
android_cat.error()
|
||||
<< "Could not lock bitmap pixels (result code " << rc << ")\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_maxval == 255) {
|
||||
if (has_alpha() && alpha != nullptr) {
|
||||
for (size_t i = 0; i < num_pixels; ++i) {
|
||||
out[i] = (array[i].r)
|
||||
| (array[i].g << 8u)
|
||||
| (array[i].b << 16u)
|
||||
| (alpha[i] << 24u);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < num_pixels; ++i) {
|
||||
out[i] = (array[i].r)
|
||||
| (array[i].g << 8u)
|
||||
| (array[i].b << 16u)
|
||||
| 0xff000000u;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double ratio = 255.0 / _maxval;
|
||||
if (has_alpha() && alpha != nullptr) {
|
||||
for (size_t i = 0; i < num_pixels; ++i) {
|
||||
out[i] = ((uint32_t)(array[i].r * ratio))
|
||||
| ((uint32_t)(array[i].g * ratio) << 8u)
|
||||
| ((uint32_t)(array[i].b * ratio) << 16u)
|
||||
| ((uint32_t)(alpha[i] * ratio) << 24u);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < num_pixels; ++i) {
|
||||
out[i] = ((uint32_t)(array[i].r * ratio))
|
||||
| ((uint32_t)(array[i].g * ratio) << 8u)
|
||||
| ((uint32_t)(array[i].b * ratio) << 16u)
|
||||
| 0xff000000u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, unlock the pixel data and compress it to the ostream.
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
jboolean res =
|
||||
env->CallStaticBooleanMethod(jni_PandaActivity,
|
||||
jni_PandaActivity_compressBitmap,
|
||||
bitmap, _format, 85, (jlong)_file);
|
||||
if (!res) {
|
||||
android_cat.error()
|
||||
<< "Failed to compress bitmap.\n";
|
||||
return 0;
|
||||
}
|
||||
return _y_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this particular PNMWriter understands grayscale images. If
|
||||
* this is false, then the rgb values of the xel array will be pre-filled with
|
||||
* the same value across all three channels, to allow the writer to simply
|
||||
* write out RGB data for a grayscale image.
|
||||
*/
|
||||
bool PNMFileTypeAndroid::Writer::
|
||||
supports_grayscale() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // ANDROID
|
@ -6,6 +6,7 @@
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-sdk android:minSdkVersion="21" />
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
|
||||
|
@ -49,16 +49,19 @@ register_type(PNMFileType *type) {
|
||||
}
|
||||
|
||||
// Make sure we haven't already registered this type.
|
||||
Handles::iterator hi = _handles.find(type->get_type());
|
||||
if (hi != _handles.end()) {
|
||||
pnmimage_cat->warning()
|
||||
<< "Attempt to register PNMFileType " << type->get_name()
|
||||
<< " (" << type->get_type() << ") more than once.\n";
|
||||
return;
|
||||
TypeHandle handle = type->get_type();
|
||||
if (handle != PNMFileType::get_class_type()) {
|
||||
Handles::iterator hi = _handles.find(handle);
|
||||
if (hi != _handles.end()) {
|
||||
pnmimage_cat->warning()
|
||||
<< "Attempt to register PNMFileType " << type->get_name()
|
||||
<< " (" << type->get_type() << ") more than once.\n";
|
||||
return;
|
||||
}
|
||||
_handles.insert(Handles::value_type(handle, type));
|
||||
}
|
||||
|
||||
_types.push_back(type);
|
||||
_handles.insert(Handles::value_type(type->get_type(), type));
|
||||
|
||||
// Collect the unique extensions associated with the type.
|
||||
pset<string> unique_extensions;
|
||||
@ -82,6 +85,37 @@ register_type(PNMFileType *type) {
|
||||
_requires_sort = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a PNMFileType previously passed to register_type.
|
||||
*/
|
||||
void PNMFileTypeRegistry::
|
||||
unregister_type(PNMFileType *type) {
|
||||
if (pnmimage_cat->is_debug()) {
|
||||
pnmimage_cat->debug()
|
||||
<< "Unregistering image type " << type->get_name() << "\n";
|
||||
}
|
||||
|
||||
TypeHandle handle = type->get_type();
|
||||
if (handle != PNMFileType::get_class_type()) {
|
||||
Handles::iterator hi = _handles.find(handle);
|
||||
if (hi != _handles.end()) {
|
||||
_handles.erase(hi);
|
||||
}
|
||||
}
|
||||
|
||||
_types.erase(std::remove(_types.begin(), _types.end(), type),
|
||||
_types.end());
|
||||
|
||||
Extensions::iterator ei;
|
||||
for (ei = _extensions.begin(); ei != _extensions.end(); ++ei) {
|
||||
Types &types = ei->second;
|
||||
types.erase(std::remove(types.begin(), types.end(), type),
|
||||
types.end());
|
||||
}
|
||||
|
||||
_requires_sort = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of types registered.
|
||||
*/
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
~PNMFileTypeRegistry();
|
||||
|
||||
void register_type(PNMFileType *type);
|
||||
void unregister_type(PNMFileType *type);
|
||||
|
||||
PUBLISHED:
|
||||
int get_num_types() const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user