2013-08-22 5 views
4

Во-первых, что я (хочу) сделать: сжимать и уменьшать партию изображений (jpg). Предположим, что исходное изображение имеет размеры 1600w x 1200h. Теперь я хочу иметь одну сжатую копию 1600x1200 и еще 800x600 и 400x300.Странные результаты при сжатии партии изображений с libjpegturbo

Что я использую: Я использую libJpegTurob для достижения этого. Если у LibJpegTurob есть некоторые проблемы, я пытаюсь использовать андроидные данные.

Уже пробовал: Во-первых, я использовал Java Wrapper портирован из Tom Gall (https://github.com/jberkel/libjpeg-turbo).

Это было довольно хорошо (на nexus 4), пока я не начну использовать фотографии размером более 4 мб. Что в основном произошло, было андроидным выбросом исключений OutOfMemory. Это произошло, когда я использовал меньшие снимки (~ 1-2 МБ), но сжимал один за другим.

Это стало даже худшим после того, как оно запущено на бюджетных устройствах с более низкой памятью, например nexus s. Проблема, вызванная низкой кучей, вот что я думаю.

Хорошо, тогда я подумал, что я должен сделать это в c. Проблемы с памятью, по-видимому, решены, так как я использовал изображения меньшие, чем 3mb на бюджетном устройстве. В nexus 4 я мог даже сжать изображение> 15mb.

Это фотография src. enter image description here

Но теперь ... проблема. Первый сжатый картина выглядит хорошо enter image description here

, но все остальные выглядит так enter image description here или этого enter image description here

Это произошло до тех пор, пока я выберите фотографии и сжимать их.

Теперь код.

Это где масштабирование и сжатие произошло

#include "_HelloJNI.h" 

#include <errno.h> 
#include <jni.h> 
#include <sys/time.h> 
#include <time.h> 
#include <android/log.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <android/bitmap.h> 
#include <unistd.h> 
#include <setjmp.h> 
#include "jpeglib.h" 
#include "turbojpeg.h" 


#define LOG_TAG "DEBUG" 
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__) 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) 
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 


int IMAGE_COMPRESS_QUALITY = 80; 

typedef struct { 
    int width; 
    int height; 
}tSize; 


JNIEXPORT jint JNICALL Java_com_example_LibJpegTurboTest_NdkCall_nativeCompress 
(JNIEnv * env, jobject onj, jstring jniSrcImgPath, jstring jniDestDir, jstring jniDestImgName, jint jniSrcWidth, jint jniSrcHeight) { 

    int pyramidRet = 0; 

    tSize fileSize; 
    fileSize.width = (int)jniSrcWidth; 
    fileSize.height = (int)jniSrcHeight; 

    const char* srcImgPath = (*env)->GetStringUTFChars(env, jniSrcImgPath, 0); 
    const char* destDir = (*env)->GetStringUTFChars(env, jniDestDir, 0); 
    const char* destFileName = (*env)->GetStringUTFChars(env, jniDestImgName, 0); 

    pyramidRet = createPreviewPyramidUsingCustomScaling(srcImgPath, destDir, destFileName, fileSize, 4); 

    return 0; 
} 

static tSize imageSizeForStep(int step, tSize *originalSize) { 
    float factor = 1/pow(2, step); 

    return (tSize) { 
     round(originalSize->width * factor), 
     round(originalSize->height * factor) }; 
} 

int saveBitmapBufferImage(unsigned char *data, tSize *imageSize, char *destFileName, int quality) { 

    int retValue = 1; 
    int res = 0; 
    unsigned long destinationJpegBufferSize = 0; 
    tjhandle tjCompressHandle = NULL; 
    unsigned char *destinationJpegBuffer = NULL; 
    FILE *file = NULL; 

    // jpgeg compress 
    tjCompressHandle = tjInitCompress(); 
    if(tjCompressHandle == NULL) { 
     retValue = -1; 
     goto cleanup; 
    } 

    res = tjCompress2(tjCompressHandle, data, imageSize->width, imageSize->width * tjPixelSize[TJPF_RGBX], imageSize->height, TJPF_RGBX, &destinationJpegBuffer, &destinationJpegBufferSize, 1, 
    quality, TJFLAG_FASTUPSAMPLE); 
    if(res < 0) { 
     retValue = -1; 
     goto cleanup; 
    } 

    file = fopen(destFileName, "wb"); 
    if(file == NULL) { 
     retValue = -1; 
     goto cleanup; 
    } 

    long written = fwrite(destinationJpegBuffer, destinationJpegBufferSize, 1, file); 
    retValue = (written == 1); 

    cleanup: 
    if(tjCompressHandle) { 
     tjDestroy(tjCompressHandle); 
    } 
    if(destinationJpegBuffer) { 
     tjFree(destinationJpegBuffer); 
    } 
    if(file) { 
     fclose(file); 
    } 

    return retValue; 
} 


int createBitmapBufferFromFile(char *srcFileName, tSize imageDimensions, long *bytesPerRow, long *dataBufferSize, unsigned char **dataBuffer) { 
    int retValue = 1; 
    int res = 0; 

    FILE *file = NULL; 

    unsigned char* sourceJpegBuffer = NULL; 
    long sourceJpegBufferSize = 0; 

    tjhandle tjDecompressHandle = NULL; 
    int fileWidth = 0, fileHeight = 0, jpegSubsamp = 0; 

    unsigned char* temp = NULL; 

    unsigned char* rotatedSourceJpegBuffer = NULL; 
    tjhandle tjTransformHandle = NULL; 

    file = fopen(srcFileName, "rb"); 
    if (file == NULL) { 
     retValue = -1; 
     goto cleanup; 
    } 


    res = fseek(file, 0, SEEK_END); 
    if(res < 0) { 
     retValue = -1; 
     goto cleanup; 
    } 


    sourceJpegBufferSize = ftell(file); 
    if(sourceJpegBufferSize <= 0) { 
     retValue = -1; 
     goto cleanup; 
    } 

    sourceJpegBuffer = tjAlloc(sourceJpegBufferSize); 
    if(sourceJpegBuffer == NULL) { 
     retValue = -1; 
     goto cleanup; 
    } 


    res = fseek(file, 0, SEEK_SET); 
    if(res < 0) { 
     retValue = -1; 
     goto cleanup; 
    } 


    res = fread(sourceJpegBuffer, (long)sourceJpegBufferSize, 1, file); 
    if(res != 1) {  
     retValue = -1; 
     goto cleanup; 
    } 


    tjDecompressHandle = tjInitDecompress(); 
    if(tjDecompressHandle == NULL) {   
     retValue = -1; 
     goto cleanup; 
    } 

    // decompress header to get image dimensions 
    res = tjDecompressHeader2(tjDecompressHandle, sourceJpegBuffer, sourceJpegBufferSize, &fileWidth, &fileHeight, &jpegSubsamp); 
    if(res < 0) { 
     retValue = -1; 
     goto cleanup; 
    } 

    float destWidth = (float)imageDimensions.width; 
    float destHeight = (float)imageDimensions.height; 

    *bytesPerRow = destWidth * tjPixelSize[TJPF_RGBX]; 

    // buffer for uncompressed image-data 
    *dataBufferSize = *bytesPerRow * destHeight; 

    temp = tjAlloc(*dataBufferSize); 
    if(temp == NULL) { 
     retValue = -1; 
     goto cleanup; 
    } 


    res = tjDecompress2(tjDecompressHandle, 
           sourceJpegBuffer, 
           sourceJpegBufferSize, 
           temp, 
           destWidth, 
           *bytesPerRow, 
           destHeight, 
           TJPF_RGBX, 
           TJ_FASTUPSAMPLE); 
    if(res < 0) { 
     retValue = -1; 
     goto cleanup; 
    } 

    *dataBuffer = temp; 
    temp = NULL; 

    cleanup: 
    if(file) { 
     fclose(file); 
    } 
    if(sourceJpegBuffer) { 
     tjFree(sourceJpegBuffer); 
    } 
    if(tjDecompressHandle) { 
     tjDestroy(tjDecompressHandle); 
    } 
    if(temp) {  
     tjFree(temp); 
    } 

    return retValue; 
} 



int createPreviewPyramidUsingCustomScaling(char* srcImgPath, char* destDir, char* destFileName, tSize orginalImgSize, int maxStep) { 
    int retValue = 1; 
    int res = 1; 
    int success = 0; 
    int loopStep = 0; 
    tSize previewSize; 

    long bytesPerRow; 
    long oldBytesPerRow = 0; 

    unsigned char* sourceDataBuffer = NULL; 
    long sourceDataBufferSize = 0; 

    unsigned char* destinationDataBuffer = NULL; 
    long destinationDataBufferSize = 0; 

    unsigned char* buf1 = NULL; 
    unsigned char* buf2 = NULL; 
    long workBufSize = 0; 

    void* sourceRow = NULL; 
    void* targetRow = NULL; 

    char* destFilePrefix = "sample_"; 
    char* fooDestName; 
    char* fooStrBuilder; 


    tSize orginSizeTmp; 
    orginSizeTmp.width = orginalImgSize.width; 
    orginSizeTmp.height = orginalImgSize.height; 

    previewSize = imageSizeForStep(1, &orginSizeTmp); 
    long width = (long)previewSize.width; 
    long height = (long)previewSize.height; 


    int errorCode = 0; 
    errorCode = createBitmapBufferFromFile(srcImgPath, previewSize, &bytesPerRow, &sourceDataBufferSize, &buf1); 
    if(errorCode != 1) {  
     retValue = errorCode; 
     goto cleanup; 
    } 

    workBufSize = sourceDataBufferSize; 
    buf2 = tjAlloc(workBufSize); 
    if(buf2 == NULL) {  
     retValue = -1; 
     goto cleanup; 
    } else { 
     memset(buf2,0,workBufSize); 
    } 

    sourceDataBuffer = buf1; 

    fooDestName = strcat(destDir, destFilePrefix); 
    fooStrBuilder = strcat(fooDestName, "1_"); 
    fooDestName = strcat(fooStrBuilder, destFileName);  


    success = saveBitmapBufferImage(sourceDataBuffer, &previewSize, fooDestName, IMAGE_COMPRESS_QUALITY); 
    if(success <= 0) { 
     retValue = -1; 
     goto cleanup; 
    } 


    cleanup: 
    if(sourceDataBuffer) {  
     tjFree(sourceDataBuffer); 
    } 
    if(destinationDataBuffer) {  
     tjFree(destinationDataBuffer); 
    } 

    return retValue; 
} 

Java-часть, чтобы начать сжатие ..

private void invokeCompress(ArrayList<PictureItem> picturesToCompress) { 
    if(picturesToCompress != null && picturesToCompress.size() > 0) { 
     for(int i=0; i<picturesToCompress.size(); i++) { 
      String srcPicturePath = picturesToCompress.get(i).getSrcImg(); 
      String destDir = "/storage/emulated/0/1_TEST_FOLDER/"; 
      String destFileName = getRandomString(4)+".jpg"; 

      BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inJustDecodeBounds = true; 
      BitmapFactory.decodeFile(srcPicturePath, options); 

      try { 
       ndkCall.compress(srcPicturePath, destDir, destFileName, options.outWidth, options.outHeight); 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

Что я сделал не так ???

Большое спасибо!

P.S. Извините за плохой английский!

+0

Исходный код ... Вы пытались использовать 'sbrk (incrementcount)' для увеличения вашей кучи? –

+0

Пробовал, но не работал. – user950117

ответ

3

Выглядит хорошо для меня. Вы убедились, что источники libjpegturbo действительны и стабильны?

2

Ваш код выглядит нормально, он хорошо написан и обрабатывает ошибки в порядке. Но из того, что я вижу, проблема может быть либо ошибкой во внешней lib, но вы можете проверить это путем разгрузки (или uninit) и перезагрузки и повторного использования библиотеки, а затем кодирования следующего файла.

Вы также можете попробовать более старую версию lib, чтобы узнать, работает ли она.

Вторая проблема может быть указателем, не установленным в NULL после освобождения и начинающим записывать плохие данные в память. Вы должны использовать такие инструменты, как valgrind, или сопоставлять все свои malloc на своей собственной странице и заполнять их страницами readonly memory (см. Mprotect), а затем, когда вы пишете на плохую страницу, программа будет segfail, и вы увидите проблему.

Я не эксперт в этой библиотеке, но дважды проверьте документацию и код примера. Возможно, есть что-то, что нужно вызывать между 2-мя файлами или после каждого из них, а первый из них - просто удача.

Также: попробуйте изменить порядок кодируемых файлов, возможно, это поможет.

 Смежные вопросы

  • Нет связанных вопросов^_^