Strani risultati durante la compressione di un gruppo di immagini con libjpegturbo

In primo luogo, quello che voglio fare: comprimere e scalare un gruppo di immagini (jpg). Supponiamo che l'image originale ha questa dimensione 1600w x 1200h. Ora, voglio avere una copia compressa di 1600×1200 e un altro 800×600 e 400×300.

Quello che uso: sto usando il libJpegTurob per get questo risultato. Se il LibJpegTurob ha qualche problema cerco di utilizzare i methods android dato.

  • Come controllare un dispositivo Android è schermo HDPI o schermo MDPI?
  • Nascondere il titolo in modalità a schermo integer?
  • Conversione di string in DataTime: Android
  • Android ottiene l'image a pieno formato dalla camera
  • Perché è richiamato onLoadFinished dopo il ripristino del riquadro?
  • scrivendo alcuni personaggi come '<' in un file xml
  • Già provato: In primo luogo, ho usato il Java Wrapper portto da Tom Gall ( https://github.com/jberkel/libjpeg-turbo ).

    È andato abbastanza bene (sul nexus 4) finché non comincio a usare le immagini oltre 4mb. Quello che è accaduto fondamentalmente è stato l'android buttare OutOfMemory eccezioni. Questo è accaduto quando ho usato immagini più piccole (~ 1-2mb) ma sono state compresse una dopo l'altra.

    Ciò è diventato peggio anche dopo aver eseguito questa operazione su dispositivi di bilancio con memory inferiore come i nexus s. Il problema where è causato dal basso mucchio, questo è quello che penso.

    Ebbene, ho pensato, devo farlo in c. I problemi di memory sembrano risolti, a lungo ho usato immagini più piccole di 3mb su un dispositivo di bilancio. Su un nexus 4 potrei anche comprimere un'image> 15mb.

    Questa è l'image di src. immettere qui la descrizione dell'immagine

    Ma adesso … il problema. La prima image compressa guarda bene immettere qui la descrizione dell'immagine

    ma tutti gli altri sembrano questo immettere qui la descrizione dell'immagine o questo immettere qui la descrizione dell'immagine

    Questo è successo finché conservo le foto selezionate e le compresso.

    Ora il codice.

    È qui che si è verificata la scalatura e la compressione

    #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; } 

    La parte Java per avviare la compressione ..

     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(); } } } } 

    Che cosa faccio male ???

    Molte grazie!!

    PS Scusa per il cattivo inglese!

  • Android: 'dp' a 'px' conversione?
  • Ascolta i pulsanti di volume nel servizio di background?
  • Android ContentProvider chiama burst di setNotificationUri () a CursorAdapter quando molte righe vengono inserite con un'operazione batch
  • Impostazione del tema Holo per l'applicazione Android
  • Dagger2 scopi e ciclo di vita delle attività
  • Come passare i dati tra i frammenti?
  • 2 Solutions collect form web for “Strani risultati durante la compressione di un gruppo di immagini con libjpegturbo”

    Sembra buono per me. Hai fatto in modo che le fonti libjpegturbo siano valide e stabili?

    Il tuo codice sembra ok, è ben scritto e gestisce gli errori. Ma da quello che vedo il problema può essere un errore nel lib esterno, prova a provare questo mediante scaricando (o uninit) e ricaricare e reinitare la libreria e quindi codificare il file successivo.

    È anche ansible provare una versione precedente del lib per vedere se funziona.

    Il secondo problema può essere un puntatore non impostato su NULL dopo libero e iniziando a scrivere dati difettosi in memory. Dovresti usare strumenti come valgrind o mappare tutto il tuo malloc nella propria pagina e riempirli con pagine di memory di sola lettura (vedi: mprotect), quindi quando si scrive in una pagina difettosa, il programma seggerà e vedrai il problema.

    Io non sono un esperto in questo lib, ma duplice controllo della documentazione e del codice di esempio. Forse c'è qualcosa che deve essere chiamato tra 2 file o dopo ciascuno, e il primo che funziona è solo pura fortuna.

    Inoltre: prova a cambiare l'ordine dei file che codifica, forse ti aiuterà.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.