如何旋转在Android上的JPEG文件,而不会丢失的质量和获得文件的大小? [英] How to rotate a JPEG file on Android without losing quality and gaining file size?

查看:777
本文介绍了如何旋转在Android上的JPEG文件,而不会丢失的质量和获得文件的大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要旋转相机拍摄的图像,使他们永远有一个正常的方向。

I need to rotate images taken by the camera so that they will always have a normal orientation.

对于这一点,我用的是下一个code(使用 这篇文章 到获得图像方向)

for this, I use the next code (used this post to get the image orientation)

//<= get the angle of the image , and decode the image from the file
final Matrix matrix = new Matrix();
//<= prepare the matrix based on the EXIF data (based on https://gist.github.com/9re/1990019 )
final Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),matrix,false);
bitmap.recycle();
fileOutputStream = new FileOutputStream(tempFilePath);
rotatedBitmap.compress(CompressFormat.JPEG, 100, fileOutputStream);
rotatedBitmap.recycle();

在这里融为一体pression率(又名质量参数)为100。

here the compression rate (AKA "quality" parameter) is 100.

在code正常工作,但结果是比原来更大,更大得多。

The code works fine, but the result is larger than the original, much much larger.

原始文件大约是600-700 KB,而生成的文件大约是3MB ...

The original file is around 600-700 KB, while the resulting file is around 3MB ...

这是即使两个输入文件和输出文件是相同的格式(JPEG)的。

This is even though both the input file and the output file are of the same format (JPEG).

的相机设置为超细的品质。不知道这意味着什么,但我认为这事做与COM pression比。

The camera settings are at "super fine" quality. not sure what it means, but I think it has something to do with the compression ratio.

我试着过滤器参数设置为虚假或真实的。都导致大文件。

I've tried to set the "filter" parameter to either false or true. both resulted in large files.

即使没有旋转本身(只是去code和EN code),我得到更大的文件大小...

Even without the rotation itself (just decode and encode), I get much larger files sizes...

只有当我设置COM pression比85左右,我得到类似的文件大小,但我不知道质量如何比较原始文件不受影响。

Only when I've set compression ratio to around 85, I get similar files sizes, but I wonder how the quality is affected compared to the original files.

为什么会出现这种问题?

Why does it occur?

有没有办法让输入文件完全相同的尺寸和质量?

Is there a way to get the exact same size and quality of the input file ?

将使用相同​​的COM pression率与原始文件做到这一点?它甚至有可能获得原始文件的COM pression率是多少?

Will using the same compression rate as the original file make it happen? Is it even possible to get the compression rate of the original file?

这是什么意思有100%的COM pression率是多少?

What does it mean to have a 100% compression rate ?

编辑:我发现<一个href=\"http://stackoverflow.com/questions/543402/can-a-jpeg-com$p$pssed-image-be-rotated-without-a-loss-in-quality\">this链接 谈论不失质量和文件大小的JPEG文件旋转,但有在Android为它的解决方案?

I've found this link talking about rotation of JPEG files without losing the quality and file size , but is there a solution for it on Android ?

这里是另一个链接 ,说这是可能的,但我找不到允许的JPEG文件旋转而不会丢失任何图书馆的质量

Here's another link that says it's possible, but I couldn't find any library that allows rotation of jpeg files without losing their quality

推荐答案

我试过两种方法,但我发现这些方法花费太长的时间在我的情况。我还是我分享使用什么。

I tried two methods but I found out those methods take too long in my case. I still share what I used.

方法1:LLJTran Android版

从这里获取LLJTran:
https://github.com/bkhall/AndroidMediaUtil

Get the LLJTran from here: https://github.com/bkhall/AndroidMediaUtil

在code:

public static boolean rotateJpegFileBaseOnExifWithLLJTran(File imageFile, File outFile){
    try {

        int operation = 0;
        int degree = getExifRotateDegree(imageFile.getAbsolutePath());
        //int degree = 90;
        switch(degree){
            case 90:operation = LLJTran.ROT_90;break;
            case 180:operation = LLJTran.ROT_180;break;
            case 270:operation = LLJTran.ROT_270;break;
        }   
        if (operation == 0){
            Log.d(TAG, "Image orientation is already correct");
            return false;
        }

        OutputStream output = null;
        LLJTran llj = null;
        try {   
            // Transform image
            llj = new LLJTran(imageFile);
            llj.read(LLJTran.READ_ALL, false); //don't know why setting second param to true will throw exception...
            llj.transform(operation, LLJTran.OPT_DEFAULTS
                    | LLJTran.OPT_XFORM_ORIENTATION);

            // write out file
            output = new BufferedOutputStream(new FileOutputStream(outFile));
            llj.save(output, LLJTran.OPT_WRITE_ALL);
            return true;
        } catch(Exception e){
            e.printStackTrace();
            return false;
        }finally {
            if(output != null)output.close();
            if(llj != null)llj.freeMemory();
        }
    } catch (Exception e) {
        // Unable to rotate image based on EXIF data
        e.printStackTrace();
        return false;
    }
}

public static int getExifRotateDegree(String imagePath){
    try {
        ExifInterface exif;
        exif = new ExifInterface(imagePath);
        String orientstring = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        int orientation = orientstring != null ? Integer.parseInt(orientstring) : ExifInterface.ORIENTATION_NORMAL;
        if(orientation == ExifInterface.ORIENTATION_ROTATE_90) 
            return 90;
        if(orientation == ExifInterface.ORIENTATION_ROTATE_180) 
            return 180;
        if(orientation == ExifInterface.ORIENTATION_ROTATE_270) 
            return 270;
    } catch (IOException e) {
        e.printStackTrace();
    }       
    return 0;
}

方法2:使用libjepg涡轮增压的jpegtran可执行

1按照步骤在这里描述:
<一href=\"http://stackoverflow.com/a/12296343/1099884\">http://stackoverflow.com/a/12296343/1099884

1 Follow the step describe here: http://stackoverflow.com/a/12296343/1099884

除了你不需要 OBJ /本地/ armeabi / libjpeg.a NDK的构建,因为我只想用JNI的jpegtran的可执行文件,但不能乱用 libjepg.a

Except that you don't need obj/local/armeabi/libjpeg.a on ndk-build because I only want the jpegtran executable but not mess with JNI with libjepg.a .

2将资产文件夹中的jpegtran可执行文件。
在code:

2 Place the jpegtran executable on asset folder. The code:

public static boolean rotateJpegFileBaseOnExifWithJpegTran(Context context, File imageFile, File outFile){
    try {

        int operation = 0;
        int degree = getExifRotateDegree(imageFile.getAbsolutePath());
        //int degree = 90;
        String exe = prepareJpegTranExe(context);
        //chmod ,otherwise  premission denied
        boolean ret = runCommand("chmod 777 "+exe); 
        if(ret == false){
            Log.d(TAG, "chmod jpegTran failed");
            return false;
        }           
        //rotate the jpeg with jpegtran
        ret = runCommand(exe+
                " -rotate "+degree+" -outfile "+outFile.getAbsolutePath()+" "+imageFile.getAbsolutePath());         

        return ret;         
    } catch (Exception e) {
        // Unable to rotate image based on EXIF data
        e.printStackTrace();
        return false;
    }
}

public static String prepareJpegTranExe(Context context){
    File exeDir = context.getDir("JpegTran", 0);
    File exe = new File(exeDir, "jpegtran");
    if(!exe.exists()){
        try {
            InputStream is = context.getAssets().open("jpegtran");
            FileOutputStream os = new FileOutputStream(exe);
            int bufferSize = 16384;
            byte[] buffer = new byte[bufferSize];
            int count;
            while ((count=is.read(buffer, 0, bufferSize))!=-1) {
                os.write(buffer, 0, count);
            }               
            is.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return exe.getAbsolutePath();
}

public static boolean runCommand(String cmd){
    try{
        Process process = Runtime.getRuntime().exec(cmd);

        BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
        int read;
        char[] buffer = new char[4096];
        StringBuffer output = new StringBuffer();
        while ((read = reader.read(buffer)) > 0) {
            output.append(buffer, 0, read);
        }
        reader.close();

        // Waits for the command to finish.
        process.waitFor();

        return true;            
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

不幸的是,花费太长的时间。这是对我的三星Galaxy S116秒!!!!但我发现这个程序( https://play.google。 COM /存储/应用程序/详细信息?ID = com.lunohod.jpegtool )只需要3-4秒。一定有办法的事情。

Unfortunately, both take too long. It is 16 seconds on my Samsung Galaxy S1!!!! But I found out this app (https://play.google.com/store/apps/details?id=com.lunohod.jpegtool) only take 3-4 seconds. There must be some way to do.

这篇关于如何旋转在Android上的JPEG文件,而不会丢失的质量和获得文件的大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆