2017-03-14 4 views
3

나는 안드로이드 스튜디오에서 비트 맵 조작 네이티브 라이브러리를 사용하지만, 우리 모두의 verry 잘 컴파일하지만 런타임 던져 링커 명령은 내가 C 코드를 다음 넣어하고Android Studio에서 종료 코드 1로 링커 명령이 실패합니까?

(호출을보기 위해 사용 -v) 종료 코드 1로 실패하고있다.

#include <jni.h> 
#include <jni.h> 
#include <android/log.h> 
#include <stdio.h> 
#include <android/bitmap.h> 
#include <cstring> 
#include <unistd.h> 

#define LOG_TAG "DEBUG" 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) 
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 

extern "C" 
{ 
//store 
JNIEXPORT jobject JNICALL Java_photoeditor_com_myapplication_MainActivity_jniStoreBitmapData(JNIEnv * env, jobject obj, jobject bitmap); 
//get 
JNIEXPORT jobject JNICALL Java_photoeditor_com_myapplication_MainActivity_jniGetBitmapFromStoredBitmapData(JNIEnv * env, jobject obj, jobject handle); 
//free 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniFreeBitmapData(JNIEnv * env, jobject obj, jobject handle); 
//rotate 90 degrees CCW 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniRotateBitmapCcw90(JNIEnv * env, jobject obj, jobject handle); 
//rotate 90 degrees CW 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniRotateBitmapCw90(JNIEnv * env, jobject obj, jobject handle); 
//crop 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniCropBitmap(JNIEnv * env, jobject obj, jobject handle, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom); 
//scale using nearest neighbor 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniScaleNNBitmap(JNIEnv * env, jobject obj, jobject handle, uint32_t newWidth, uint32_t newHeight); 
} 

class JniBitmap 
{ 
public: 
    uint32_t* _storedBitmapPixels; 
    AndroidBitmapInfo _bitmapInfo; 
    JniBitmap() 
    { 
     _storedBitmapPixels = NULL; 
    } 
}; 

/**crops the bitmap within to be smaller. note that no validations are done*/ // 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniCropBitmap(JNIEnv * env, jobject obj, jobject handle, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom) 
{ 
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); 
    if (jniBitmap->_storedBitmapPixels == NULL) 
     return; 
    uint32_t* previousData = jniBitmap->_storedBitmapPixels; 
    uint32_t oldWidth = jniBitmap->_bitmapInfo.width; 
    uint32_t newWidth = right - left, newHeight = bottom - top; 
    uint32_t* newBitmapPixels = new uint32_t[newWidth * newHeight]; 
    uint32_t* whereToGet = previousData + left + top * oldWidth; 
    uint32_t* whereToPut = newBitmapPixels; 
    for (int y = top; y < bottom; ++y) 
    { 
     memcpy(whereToPut, whereToGet, sizeof(uint32_t) * newWidth); 
     whereToGet += oldWidth; 
     whereToPut += newWidth; 
    } 
    //done copying , so replace old data with new one 
    delete[] previousData; 
    jniBitmap->_storedBitmapPixels = newBitmapPixels; 
    jniBitmap->_bitmapInfo.width = newWidth; 
    jniBitmap->_bitmapInfo.height = newHeight; 
} 

/**rotates the inner bitmap data by 90 degress counter clock wise*/ // 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniRotateBitmapCcw90(JNIEnv * env, jobject obj, jobject handle) 
{ 
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); 
    if (jniBitmap->_storedBitmapPixels == NULL) 
     return; 
    uint32_t* previousData = jniBitmap->_storedBitmapPixels; 
    AndroidBitmapInfo bitmapInfo = jniBitmap->_bitmapInfo; 
    uint32_t* newBitmapPixels = new uint32_t[bitmapInfo.height * bitmapInfo.width]; 
    int whereToGet = 0; 
    // XY. ... ... ..X 
    // ...>Y..>...>..Y 
    // ... X.. .YX ... 
    for (int x = 0; x < bitmapInfo.width; ++x) 
     for (int y = bitmapInfo.height - 1; y >= 0; --y) 
     { 
      //take from each row (up to bottom), from left to right 
      uint32_t pixel = previousData[whereToGet++]; 
      newBitmapPixels[bitmapInfo.width * y + x] = pixel; 
     } 
    delete[] previousData; 
    jniBitmap->_storedBitmapPixels = newBitmapPixels; 
    uint32_t temp = bitmapInfo.width; 
    bitmapInfo.width = bitmapInfo.height; 
    bitmapInfo.height = temp; 
} 

JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniRotateBitmapCw90(JNIEnv * env, jobject obj, jobject handle) 
{ 
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); 
    if (jniBitmap->_storedBitmapPixels == NULL) 
     return; 
    uint32_t* previousData = jniBitmap->_storedBitmapPixels; 
    AndroidBitmapInfo bitmapInfo = jniBitmap->_bitmapInfo; 
    uint32_t* newBitmapPixels = new uint32_t[bitmapInfo.height * bitmapInfo.width]; 
    int whereToGet = 0; 
    // XY. ..X ... ... 
    // ...>..Y>...>Y.. 
    // ... ... .YX X.. 
    for (int x = bitmapInfo.width - 1; x >= 0; --x) 
     for (int y = 0; y < bitmapInfo.height; ++y) 
     { 
      //take from each row (up to bottom), from left to right 
      uint32_t pixel = previousData[whereToGet++]; 
      newBitmapPixels[bitmapInfo.width * y + x] = pixel; 
     } 
    delete[] previousData; 
    jniBitmap->_storedBitmapPixels = newBitmapPixels; 
    uint32_t temp = bitmapInfo.width; 
    bitmapInfo.width = bitmapInfo.height; 
    bitmapInfo.height = temp; 
} 

/**free bitmap*/ // 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniFreeBitmapData(JNIEnv * env, jobject obj, jobject handle) 
{ 
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); 
    if (jniBitmap->_storedBitmapPixels == NULL) 
     return; 
    delete[] jniBitmap->_storedBitmapPixels; 
    jniBitmap->_storedBitmapPixels = NULL; 
    delete jniBitmap; 
} 

/**restore java bitmap (from JNI data)*/ // 
JNIEXPORT jobject JNICALL Java_photoeditor_com_myapplication_MainActivity_jniGetBitmapFromStoredBitmapData(JNIEnv * env, jobject obj, jobject handle) 
{ 
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); 
    if (jniBitmap->_storedBitmapPixels == NULL) 
    { 
     LOGD("no bitmap data was stored. returning null..."); 
     return NULL; 
    } 
    // 
    //creating a new bitmap to put the pixels into it - using Bitmap Bitmap.createBitmap (int width, int height, Bitmap.Config config) : 
    // 
    //LOGD("creating new bitmap..."); 
    jclass bitmapCls = env->FindClass("android/graphics/Bitmap"); 
    jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); 
    jstring configName = env->NewStringUTF("ARGB_8888"); 
    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config"); 
    jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(bitmapConfigClass, "valueOf", "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); 
    jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass, valueOfBitmapConfigFunction, configName); 
    jobject newBitmap = env->CallStaticObjectMethod(bitmapCls, createBitmapFunction, jniBitmap->_bitmapInfo.width, jniBitmap->_bitmapInfo.height, bitmapConfig); 
    // 
    // putting the pixels into the new bitmap: 
    // 
    int ret; 
    void* bitmapPixels; 
    if ((ret = AndroidBitmap_lockPixels(env, newBitmap, &bitmapPixels)) < 0) 
    { 
     LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); 
     return NULL; 
    } 
    uint32_t* newBitmapPixels = (uint32_t*) bitmapPixels; 
    int pixelsCount = jniBitmap->_bitmapInfo.height * jniBitmap->_bitmapInfo.width; 
    memcpy(newBitmapPixels, jniBitmap->_storedBitmapPixels, sizeof(uint32_t) * pixelsCount); 
    AndroidBitmap_unlockPixels(env, newBitmap); 
    //LOGD("returning the new bitmap"); 
    return newBitmap; 
} 

/**store java bitmap as JNI data*/ // 
JNIEXPORT jobject JNICALL Java_photoeditor_com_myapplication_MainActivity_jniStoreBitmapData(JNIEnv * env, jobject obj, jobject bitmap) 
{ 
    AndroidBitmapInfo bitmapInfo; 
    uint32_t* storedBitmapPixels = NULL; 
    //LOGD("reading bitmap info..."); 
    int ret; 
    if ((ret = AndroidBitmap_getInfo(env, bitmap, &bitmapInfo)) < 0) 
    { 
     LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); 
     return NULL; 
    } 
    //LOGD("width:%d height:%d stride:%d", bitmapInfo.width, bitmapInfo.height, bitmapInfo.stride); 
    if (bitmapInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888) 
    { 
     LOGE("Bitmap format is not RGBA_8888!"); 
     return NULL; 
    } 
    // 
    //read pixels of bitmap into native memory : 
    // 
    //LOGD("reading bitmap pixels..."); 
    void* bitmapPixels; 
    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels)) < 0) 
    { 
     LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); 
     return NULL; 
    } 
    uint32_t* src = (uint32_t*) bitmapPixels; 
    storedBitmapPixels = new uint32_t[bitmapInfo.height * bitmapInfo.width]; 
    int pixelsCount = bitmapInfo.height * bitmapInfo.width; 
    memcpy(storedBitmapPixels, src, sizeof(uint32_t) * pixelsCount); 
    AndroidBitmap_unlockPixels(env, bitmap); 
    JniBitmap *jniBitmap = new JniBitmap(); 
    jniBitmap->_bitmapInfo = bitmapInfo; 
    jniBitmap->_storedBitmapPixels = storedBitmapPixels; 
    return env->NewDirectByteBuffer(jniBitmap, 0); 
} 

/**scales the image using the fastest, simplest algorithm called "nearest neighbor" */ // 
JNIEXPORT void JNICALL Java_photoeditor_com_myapplication_MainActivity_jniScaleNNBitmap(JNIEnv * env, jobject obj, jobject handle, uint32_t newWidth, uint32_t newHeight) 
{ 
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle); 
    if (jniBitmap->_storedBitmapPixels == NULL) 
     return; 
    uint32_t oldWidth = jniBitmap->_bitmapInfo.width; 
    uint32_t oldHeight = jniBitmap->_bitmapInfo.height; 
    uint32_t* previousData = jniBitmap->_storedBitmapPixels; 
    uint32_t* newBitmapPixels = new uint32_t[newWidth * newHeight]; 
    int x2, y2; 
    int whereToPut = 0; 
    for (int y = 0; y < newHeight; ++y) 
    { 
     for (int x = 0; x < newWidth; ++x) 
     { 
      x2 = x * oldWidth/newWidth; 
      if (x2 < 0) 
       x2 = 0; 
      else if (x2 >= oldWidth) 
       x2 = oldWidth - 1; 
      y2 = y * oldHeight/newHeight; 
      if (y2 < 0) 
       y2 = 0; 
      else if (y2 >= oldHeight) 
       y2 = oldHeight - 1; 
      newBitmapPixels[whereToPut++] = previousData[(y2 * oldWidth) + x2]; 
      //same as : newBitmapPixels[(y * newWidth) + x] = previousData[(y2 * oldWidth) + x2]; 
     } 
    } 

    delete[] previousData; 
    jniBitmap->_storedBitmapPixels = newBitmapPixels; 
    jniBitmap->_bitmapInfo.width = newWidth; 
    jniBitmap->_bitmapInfo.height = newHeight; 
} 

내가 사용하는 내가 configration 내부에 그것을

enter image description here

Cmakelists.txt을 넣어하고 그 시간 표시 다음과 같은 예외 스택 트레이스입니다

cmake_minimum_required(VERSION 3.4.1) 

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") 

add_library(# Sets the name of the library. 
      JniBitmapOperations 

      # Sets the library as a shared library. 
      SHARED 

      # Provides a relative path to your source file(s). 
      # Associated headers in the same location as their source 
      # file are automatically included. 
      src/main/cpp/JniBitmapOperations.cpp) 

find_library(# Sets the name of the path variable. 
       log-lib 
        JniBitmapOperations 
       # Specifies the name of the NDK library that 
       # you want CMake to locate. 
       log 
      ) 
target_link_libraries(# Specifies the target library. 

         JniBitmapOperations 

         # Links the target library to the log library 
         # included in the NDK. 
         ) 

Android.mk fi 제작 내용

LOCAL_PATH := $(call my-dir) 

#bitmap operations module 
include $(CLEAR_VARS) 

LOCAL_MODULE := JniBitmapOperations 
LOCAL_SRC_FILES := JniBitmapOperations.cpp 
LOCAL_LDLIBS := -llog 
LOCAL_LDFLAGS += -ljnigraphics 

include $(BUILD_SHARED_LIBRARY) 
APP_OPTIM := debug 
LOCAL_CFLAGS := -g 

#if you need to add more module, do the same as the one we started with (the one with the CLEAR_VARS) 

추가 자바 jniBitmapHolder.java 파일을 호출하고 더 이상 처리 컴파일 만이 예외를 던져 내 프로젝트를 빌드합니다.

import android.graphics.Bitmap; 
import android.util.Log; 

import java.nio.ByteBuffer; 

public class JniBitmapHolder 
    { 
    ByteBuffer _handler =null; 
    static 
    { 
    System.loadLibrary("JniBitmapOperations"); 
    } 

    private native ByteBuffer jniStoreBitmapData(Bitmap bitmap); 

    private native Bitmap jniGetBitmapFromStoredBitmapData(ByteBuffer handler); 

    private native void jniFreeBitmapData(ByteBuffer handler); 

    private native void jniRotateBitmapCcw90(ByteBuffer handler); 

    private native void jniRotateBitmapCw90(ByteBuffer handler); 

    private native void jniCropBitmap(ByteBuffer handler,final int left,final int top,final int right,final int bottom); 

    private native void jniScaleNNBitmap(ByteBuffer handler,final int newWidth,final int newHeight); 

    public JniBitmapHolder() 
    {} 

    public JniBitmapHolder(final Bitmap bitmap) 
    { 
    storeBitmap(bitmap); 
    } 

    public void storeBitmap(final Bitmap bitmap) 
    { 
    if(_handler!=null) 
     freeBitmap(); 
    _handler=jniStoreBitmapData(bitmap); 
    } 

    public void rotateBitmapCcw90() 
    { 
    if(_handler==null) 
     return; 
    jniRotateBitmapCcw90(_handler); 
    } 

    public void rotateBitmapCw90() 
    { 
    if(_handler==null) 
     return; 
    jniRotateBitmapCw90(_handler); 
    } 

    public void cropBitmap(final int left,final int top,final int right,final int bottom) 
    { 
    if(_handler==null) 
     return; 
    jniCropBitmap(_handler,left,top,right,bottom); 
    } 

    public Bitmap getBitmap() 
    { 
    if(_handler==null) 
     return null; 
    return jniGetBitmapFromStoredBitmapData(_handler); 
    } 

    public Bitmap getBitmapAndFree() 
    { 
    final Bitmap bitmap=getBitmap(); 
    freeBitmap(); 
    return bitmap; 
    } 

    public void scaleBitmap(final int newWidth,final int newHeight) 
    { 
    if(_handler==null) 
     return; 
    jniScaleNNBitmap(_handler,newWidth,newHeight); 
    } 

    public void freeBitmap() 
    { 
    if(_handler==null) 
     return; 
    jniFreeBitmapData(_handler); 
    _handler=null; 
    } 

    @Override 
    protected void finalize() throws Throwable 
    { 
    super.finalize(); 
    if(_handler==null) 
     return; 
    Log.w("DEBUG","JNI bitmap wasn't freed nicely.please rememeber to free the bitmap as soon as you can"); 
    freeBitmap(); 
    } 
    } 

빌드 Gradle을 파일 configration.

android { 
    compileSdkVersion 25 
    buildToolsVersion "25.0.2" 
    useLibrary 'org.apache.http.legacy' 
    defaultConfig { 
     applicationId "com.itflash.whatsappstickers" 
     minSdkVersion 18 
     targetSdkVersion 25 
     versionCode 1 
     versionName "1.0" 
     multiDexEnabled true 

     ndk { 
      moduleName "JniBitmapOperations" 
      ldLibs "log", "jnigraphics" 
      //abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86' 
     } 

     testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 
     externalNativeBuild { 
      cmake { 
       cmake { 
        cppFlags "-frtti -fexceptions" 
        arguments '-DANDROID_PLATFORM=android-19', '-DANDROID_TOOLCHAIN=clang' 
       } 
      } 
     } 
    } 
    packagingOptions { 
     exclude 'META-INF/NOTICE' // will not include NOTICE file 
     exclude 'META-INF/LICENSE' // will not include LICENSE file 
     exclude 'META-INF/DEPENDENCIES' 
    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 
    } 
    externalNativeBuild { 
     cmake { 
      path "CMakeLists.txt" 
     } 
    } 
    dexOptions { 
     incremental true 
     javaMaxHeapSize "1536m" 
    } 
} 

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 
     exclude group: 'com.android.support', module: 'support-annotations' 
    }) 
    compile 'com.google.android.gms:play-services:10.2.0' 
    compile 'com.android.support:appcompat-v7:25.2.0' 
    testCompile 'junit:junit:4.12' 
} 

답변

1

링커가 사용하는 기능을 찾을 수없는, 즉 수동으로 라이브러리를 지정해야합니다. 그게 libjnigraphics 인 것처럼 나에게 보인다.

Android.mkLOCAL_LDFLAGS += -ljnigraphics을 지정 했습니까? this answer과 같이 나타 납니까?

+0

친구 고맙습니다. 이미 android.mk 파일에 추가되었습니다. – Kuldeep

+0

확인. 문제는 동일하게 유지됩니다. 즉, 행이 사용되지 않았거나 lib를 찾을 수 없습니다. 추가로 도움을주기 위해 호출을 게시 할 수 있습니까 (종료 코드 1을 발생시키는 전체 명령)? – grasbueschel

+0

죄송합니다. 친구가 당신에게 전체 코드를 보내지는 않았지만 좀 더 자세한 내용을 보내주십시오. – Kuldeep

관련 문제