在加速度计支持的黑莓设备上拍照后错误的透视图像

时间:2012-09-26 14:27:56

标签: blackberry rotation orientation image exif

当我读取从相机拍摄的照片时,会出现透视图像问题。当方向为北时,图片看起来需要旋转270度。当方向为东方时,图片应旋转180度。但是当方向是西方时,它是好的。我在EncodedImage中尝试了getMetaData()getKeyValue("orientation")来生成一个好的旋转公式,但它返回了空字符串。请帮我解决这个问题。

1 个答案:

答案 0 :(得分:3)

在此找到解决方案: https://gist.github.com/3788313

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EncodedImage;

public class ExifRotate {

    /**
     * Flip the image horizontally.
     */
    public static final int FLIP_H = 1;

    /**
     * Flip the image vertically.
     */
    public static final int FLIP_V = 2;

    /**
     * Flip the image horizontally and vertically.
     */
    public static final int FLIP_HV = 3;

    /**
     * Rotate the image 90 degrees clockwise.
     */
    public static final int FLIP_90CW = 4;

    /**
     * Rotate the image 90 degrees counter-clockwise.
     */
    public static final int FLIP_90CCW = 5;

    /**
     * Rotate the image 180 degrees.
     */
    public static final int FLIP_180 = 6;

    private final static int read2bytes(InputStream in) throws IOException  {
        return in.read() << 8 | in.read();
    }

    private final static int readByte(InputStream in) throws IOException {
        return in.read();
    }

    public static Bitmap readImageFromFile(String filename, int width, int height) throws IOException {
        EncodedImage img = null;
        byte[] data = null;

        FileConnection file = null;
        try {
            file = (FileConnection) Connector.open(filename, Connector.READ);
            int fileSize = (int) file.fileSize();
            if (fileSize == 0) {
                throw new IOException("File is empty");
            }

            data = new byte[fileSize];
            InputStream input = file.openInputStream();
            input.read(data);
            input.close();

            img = EncodedImage.createEncodedImage(data, 0, data.length);

            int orientation = -1;
            if ( filename.toLowerCase().endsWith(".jpg") || filename.toLowerCase().endsWith(".jpeg")) {
                ByteArrayInputStream is = new ByteArrayInputStream( data );
                orientation = getRotation(is);
            }

            if ( orientation == 2 ) {
                return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
            } else if ( orientation == 3 ) {
                return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_180);
            } else if ( orientation == 4 ) {
                return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_V);
            } else if ( orientation == 5 ) {
                Bitmap tmp = rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
                tmp = rotateBitmap(tmp, ImageUtil.FLIP_90CCW);
                return tmp;
            } else if ( orientation == 6 ) {
                return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_90CW);
            } else if ( orientation == 7 ) {
                Bitmap tmp = rotateBitmap(img.getBitmap(), ImageUtil.FLIP_H);
                tmp = rotateBitmap(tmp, ImageUtil.FLIP_90CW);
                return tmp;
            } else if ( orientation == 8 ) {
                return rotateBitmap(img.getBitmap(), ImageUtil.FLIP_90CCW);
            } else {
                return img.getBitmap();
            }
        } finally {
            if (file != null) {
                try { file.close(); }
                catch(Exception ex){}
            }
        }
    }

    public static int getRotation(InputStream in) throws IOException {
        int [] exif_data = new int[100];
        int n_flag = 0, set_flag = 0;
        int is_motorola = 0;

        /* Read File head, check for JPEG SOI + Exif APP1 */
        for (int i = 0; i < 4; i++)
            exif_data[i] = readByte(in);

        if (exif_data[0] != 0xFF || exif_data[1] != 0xD8 || exif_data[2] != 0xFF || exif_data[3] != 0xE1)
            return -2;

        /* Get the marker parameter length count */
        int length = read2bytes(in);
        // exif_data = new int[length];

        /* Length includes itself, so must be at least 2 */
        /* Following Exif data length must be at least 6 */
        if (length < 8)
            return -1;
        length -= 8;
        /* Read Exif head, check for "Exif" */
        for (int i = 0; i < 6; i++)
            exif_data[i] = in.read();

        if (exif_data[0] != 0x45 || exif_data[1] != 0x78 || exif_data[2] != 0x69 || exif_data[3] != 0x66 || exif_data[4] != 0 || exif_data[5] != 0)
            return -1;

        /* Read Exif body */
        length = length > exif_data.length ? exif_data.length : length;
        for (int i = 0; i < length; i++)
            exif_data[i] = in.read();

        if (length < 12)
            return -1; /* Length of an IFD entry */

        /* Discover byte order */
        if (exif_data[0] == 0x49 && exif_data[1] == 0x49)
            is_motorola = 0;
        else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D)
            is_motorola = 1;
        else
            return -1;

        /* Check Tag Mark */
        if (is_motorola == 1) {
            if (exif_data[2] != 0)
                return -1;
            if (exif_data[3] != 0x2A)
                return -1;
        } else {
            if (exif_data[3] != 0)
                return -1;
            if (exif_data[2] != 0x2A)
                return -1;
        }

        /* Get first IFD offset (offset to IFD0) */
        int offset;
        if (is_motorola == 1) {
            if (exif_data[4] != 0)
                return -1;
            if (exif_data[5] != 0)
                return -1;
            offset = exif_data[6];
            offset <<= 8;
            offset += exif_data[7];
        } else {
            if (exif_data[7] != 0)
                return -1;
            if (exif_data[6] != 0)
                return -1;
            offset = exif_data[5];
            offset <<= 8;
            offset += exif_data[4];
        }
        if (offset > length - 2)
            return -1; /* check end of data segment */

        /* Get the number of directory entries contained in this IFD */
        int number_of_tags;
        if (is_motorola == 1) {
            number_of_tags = exif_data[offset];
            number_of_tags <<= 8;
            number_of_tags += exif_data[offset + 1];
        } else {
            number_of_tags = exif_data[offset + 1];
            number_of_tags <<= 8;
            number_of_tags += exif_data[offset];
        }
        if (number_of_tags == 0)
            return -1;
        offset += 2;

        /* Search for Orientation Tag in IFD0 */
        for (;;) {
            if (offset > length - 12)
                return -1; /* check end of data segment */
            /* Get Tag number */
            int tagnum;
            if (is_motorola == 1) {
                tagnum = exif_data[offset];
                tagnum <<= 8;
                tagnum += exif_data[offset + 1];
            } else {
                tagnum = exif_data[offset + 1];
                tagnum <<= 8;
                tagnum += exif_data[offset];
            }
            if (tagnum == 0x0112)
                break; /* found Orientation Tag */
            if (--number_of_tags == 0)
                return -1;
            offset += 12;
        }

        /*
         * if (set_flag==1) { Set the Orientation value if (is_motorola==1) {
         * exif_data[offset+2] = 0; Format = unsigned short (2 octets)
         * exif_data[offset+3] = 3; exif_data[offset+4] = 0; Number Of
         * Components = 1 exif_data[offset+5] = 0; exif_data[offset+6] = 0;
         * exif_data[offset+7] = 1; exif_data[offset+8] = 0; exif_data[offset+9]
         * = set_flag; exif_data[offset+10] = 0; exif_data[offset+11] = 0; }
         * else { exif_data[offset+2] = 3; Format = unsigned short (2 octets)
         * exif_data[offset+3] = 0; exif_data[offset+4] = 1; Number Of
         * Components = 1 exif_data[offset+5] = 0; exif_data[offset+6] = 0;
         * exif_data[offset+7] = 0; exif_data[offset+8] = set_flag;
         * exif_data[offset+9] = 0; exif_data[offset+10] = 0;
         * exif_data[offset+11] = 0; } }
         */
        // else {
        /* Get the Orientation value */
        if (is_motorola == 1) {
            if (exif_data[offset + 8] != 0)
                return -1;
            set_flag = exif_data[offset + 9];
        } else {
            if (exif_data[offset + 9] != 0)
                return -1;
            set_flag = exif_data[offset + 8];
        }
        if (set_flag > 8)
            return -1;
        // }

        /* Write out Orientation value */

        if (n_flag == 1)
            System.out.println("set_flag " + set_flag);
        else
            System.out.println("set_flag " + set_flag);

        return set_flag;
    }

    public static Bitmap rotateBitmap(Bitmap src, int operation) {
        int width = src.getWidth();
        int height = src.getHeight();

        int[] inPixels = new int[width*height];
        src.getARGB(inPixels, 0, width, 0, 0, width, height);

        int x = 0, y = 0;
        int w = width;
        int h = height;

        int newX = 0;
        int newY = 0;
        int newW = w;
        int newH = h;
        switch (operation) {
        case FLIP_H:
            newX = width - (x + w);
            break;
        case FLIP_V:
            newY = height - (y + h);
            break;
        case FLIP_HV:
            newW = h;
            newH = w;
            newX = y;
            newY = x;
            break;
        case FLIP_90CW:
            newW = h;
            newH = w;
            newX = height - (y + h);
            newY = x;
            break;
        case FLIP_90CCW:
            newW = h;
            newH = w;
            newX = y;
            newY = width - (x + w);
            break;
        case FLIP_180:
            newX = width - (x + w);
            newY = height - (y + h);
            break;
        }

        int[] newPixels = new int[newW * newH];
        int index, newRow, newCol, newIndex;

        if ( operation == FLIP_H ) {
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    index = row * width + col;
                    newRow = row;
                    newCol = w - col - 1;
                    newIndex = newRow * newW + newCol;
                    newPixels[newIndex] = inPixels[index];
                }
            }
        } else if ( operation == FLIP_V ) {
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    index = row * width + col;
                    newRow = h - row - 1;
                    newCol = col;
                    newIndex = newRow * newW + newCol;
                    newPixels[newIndex] = inPixels[index];
                }
            }
        } else if ( operation == FLIP_HV ) {
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    index = row * width + col;
                    newRow = col;
                    newCol = row;
                    newIndex = newRow * newW + newCol;
                    newPixels[newIndex] = inPixels[index];
                }
            }
        } else if ( operation == FLIP_90CW ) {
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    index = row * width + col;
                    newRow = col;
                    newCol = h - row - 1;
                    newIndex = newRow * newW + newCol;
                    newPixels[newIndex] = inPixels[index];
                }
            }
        } else if ( operation == FLIP_90CCW ) {
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    index = row * width + col;
                    newRow = w - col - 1;
                    newCol = row;
                    newIndex = newRow * newW + newCol;
                    newPixels[newIndex] = inPixels[index];
                }
            }
        } else if ( operation == FLIP_180 ) {
            for (int row = 0; row < h; row++) {
                for (int col = 0; col < w; col++) {
                    index = row * width + col;
                    newRow = h - row - 1;
                    newCol = w - col - 1;
                    newIndex = newRow * newW + newCol;
                    newPixels[newIndex] = inPixels[index];
                }
            }
        }

        Bitmap dst = new Bitmap( newW, newH );
        dst.setARGB(newPixels, 0, newW, 0, 0, newW, newH);

        return dst;
    }

}