[开源项目]ZXing -横竖屏以及前/后置摄像头问题

本文介绍了一种ZXing相机管理器的封装实现,包括摄像头切换、预览旋转、原始数据旋转修改等功能,适用于手机横竖屏预览场景。

[ZXing](https://github.com/zxing/zxing
- 该类替换默认的CamerManager .
- 该类添加了打开前置和后置摄像头
- 手机的横屏以及竖屏的预览旋转
- 原始数据的旋转修改
- 预览窗出现的画面变形可调用getCameraResolution() 来获取到摄像头分辨率来等比修改预览SurfaceView 的大小,可解决.

import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;

import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.client.android.camera.CameraManager;


import java.io.IOException;

/**
 * Created by Luo on 2015/5/21.
 * zxing CameraManager 包装
 */
public class WrapperCameraManager extends CameraManager {
    private static final String TAG = WrapperCameraManager.class.getSimpleName();
    private boolean isPortrait = false;  //是否竖屏
    private boolean isFrontCamera = false; //前置true/后置摄像头false
    private final Context context;
    private SurfaceHolder holder;


    public WrapperCameraManager(Context context) {
        super(context);
        this.context = context;
    }

    private void openCamera(int face, SurfaceHolder holder) throws IOException {
        this.holder = holder;
        Camera theCamera = camera;
        if (theCamera == null) {
            theCamera = open(face);
            if (theCamera == null) {
                throw new IOException();
            }
            setCameraDisplayOrientation(context, requestedCameraId, theCamera);
            camera = theCamera;
        }
        theCamera.setPreviewDisplay(holder);
        if (!initialized) {
            initialized = true;
            configManager.initFromCameraParameters(theCamera);
            if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
                setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
                requestedFramingRectWidth = 0;
                requestedFramingRectHeight = 0;
            }
        }

        Camera.Parameters parameters = theCamera.getParameters();
        String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save these, temporarily
        try {
            configManager.setDesiredCameraParameters(theCamera, false);
        } catch (RuntimeException re) {
            // Driver failed
            Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters");
            Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened);
            // Reset:
            if (parametersFlattened != null) {
                parameters = theCamera.getParameters();
                parameters.unflatten(parametersFlattened);
                try {
                    theCamera.setParameters(parameters);
                    configManager.setDesiredCameraParameters(theCamera, true);
                } catch (RuntimeException re2) {
                    // Well, darn. Give up
                    Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration");
                }
            }
        }
    }


    public synchronized void openFrontCamera(SurfaceHolder holder) throws IOException {
        openCamera(Camera.CameraInfo.CAMERA_FACING_FRONT, holder);
        isFrontCamera = true;
    }


    public synchronized void openBackCamera(SurfaceHolder holder) throws IOException {

        openCamera(Camera.CameraInfo.CAMERA_FACING_BACK, holder);
        isFrontCamera = false;


    }

    /**
     * 打开相机
     *
     * @param face
     * @return null 没有符合条件的或没有相机
     */
    private Camera open(int face) {
        int numCameras = Camera.getNumberOfCameras();
        if (numCameras == 0) {
            Log.w(TAG, "No cameras!");
            return null;
        }
        // Select a camera if no explicit camera requested
        int index = 0;
        while (index < numCameras) {
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(index, cameraInfo);
            if (cameraInfo.facing == face) {
                break;
            }
            index++;
        }
        requestedCameraId = index;
        Camera camera = null;
        if (index < numCameras) {
            Log.i(TAG, "Opening camera #" + index);
            camera = Camera.open(index);
        } else {
            Log.i(TAG, "No camera facing back; returning camera #0");
        }
        return camera;
    }


    /**
     *
     * @param holder The surface object which the camera will draw preview frames into.
     * @throws IOException
     * @deprecated 使用 {@link #openBackCamera(SurfaceHolder)}打开前置摄像头 或 {@link #openFrontCamera(SurfaceHolder)}打开后置摄像头
     */
    @Deprecated
    @Override
    public synchronized void openDriver(SurfaceHolder holder) throws IOException {
        openBackCamera(holder);
    }

    @Override
    public Point getCameraResolution() {
        Point cameraResolution = super.getCameraResolution();
        if (isPortrait) return new Point(cameraResolution.y, cameraResolution.x);
        return cameraResolution;
    }

    @Override
    public synchronized Rect getFramingRectInPreview() {
        if (framingRectInPreview == null) {
            Rect framingRect = getFramingRect();
            if (framingRect == null) {
                return null;
            }
            Rect rect = new Rect(framingRect);
            Point cameraResolution = configManager.getCameraResolution();
            Point screenResolution = configManager.getScreenResolution();
            if (cameraResolution == null || screenResolution == null) {
                // Called early, before init even finished
                return null;
            }
            //-----竖屏修改----------
            if (isPortrait) {
                rect.left = rect.left * cameraResolution.y / screenResolution.x;
                rect.right = rect.right * cameraResolution.y / screenResolution.x;
                rect.top = rect.top * cameraResolution.x / screenResolution.y;
                rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
                //---------------
            } else {
                rect.left = rect.left * cameraResolution.x / screenResolution.x;
                rect.right = rect.right * cameraResolution.x / screenResolution.x;
                rect.top = rect.top * cameraResolution.y / screenResolution.y;
                rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
            }
            framingRectInPreview = rect;
        }
        return framingRectInPreview;

    }

    /**
     * A factory method to build the appropriate LuminanceSource object based on the format
     * of the preview buffers, as described by Camera.Parameters.
     *
     * @param data   A preview frame.
     * @param width  The width of the image.
     * @param height The height of the image.
     * @return A PlanarYUVLuminanceSource instance.
     */
    public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
        Rect rect = getFramingRectInPreview();
        if (rect == null) {
            return null;
        }

        byte[] rotate = new byte[data.length];

        if (isPortrait) {    //竖屏
            if (isFrontCamera) {
                //前置摄像头竖屏顺旋转90度,垂直翻转<上下>
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
                        rotate[(width - 1 - x) * height + (height - 1 - y)] = data[x + y * width];
                    }
                }
            } else {
                //后置摄像头竖屏变换,顺旋转90度
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++)
                        rotate[x * height + height - y - 1] = data[x + y * width];
                }
            }
            int tmp = width;
            width = height;
            height = tmp;
        } else {
            if (isFrontCamera) {
                //前置横屏水平翻转<左右对换>
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
                        rotate[width - 1 - x + y * width] = data[x + y * width];
                    }
                }
            } else {
                System.arraycopy(data, 0, rotate, 0, data.length);
            }
        }
        // Go ahead and assume it's YUV rather than die.
        return new PlanarYUVLuminanceSource(rotate, width, height, rect.left, rect.top, rect.width(), rect.height(), false);
    }




    /**
     * 设置相机预览旋转角度
     *
     * @param context
     * @param cameraId
     * @param camera
     */
    public void setCameraDisplayOrientation(Context context,
                                            int cameraId, android.hardware.Camera camera) {
        android.hardware.Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        int rotation = manager.getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 0;
                break;
            case Surface.ROTATION_270:
                degrees = 90;
                break;
        }

        isPortrait = degrees == 0;
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }
}
<think> 我们正在处理一个CMake构建问题,涉及使用FetchContent模块克隆zxing-cpp仓库失败,以及后续构建停止。根据引用内容,我们知道zxing-cpp是一个条码处理库,使用CMake构建系统。错误信息包括克隆失败和构建失败。 可能的原因分析: 1. 网络问题:无法访问GitHub仓库(https://github.com/zxing-cpp/zxing-cpp.git) 2. 仓库地址变更或暂时不可用 3. CMake版本过低,FetchContent模块功能不完善 4. Git版本过低,无法正常克隆 5. 依赖缺失:如未安装必需的编译工具(C++编译器)或库(OpenCV可选) 6. 克隆过程中断(如超时) 7. CMake配置中可能缺少必要的设置,比如ZXING_EXPERIMENTAL_API等标志(引用[2]提到) 此外,构建失败(ninja: build stopped: subcommand failed)可能是由于克隆步骤失败导致无法继续构建,也可能是克隆成功后编译过程中出错。 解决步骤建议: 1. 检查网络连接,尝试手动克隆仓库:在终端运行`git clone https://github.com/zxing-cpp/zxing-cpp.git`,看是否成功。 2. 如果手动克隆成功,则问题可能出在CMake的FetchContent配置上;如果手动克隆失败,则可能是网络或仓库问题。 3. 检查CMake版本(引用[1]要求使用CMake),确保使用较新版本(建议3.14以上)。 4. 确保系统已安装Git和C++编译器(引用[1])。 5. 检查CMake配置中是否需要设置代理(如果网络需要)。 6. 查看详细错误日志,CMake构建失败通常会给出更具体的错误信息。 关于引用[2]中提到的实验性API标志,如果项目需要使用实验性API,则需要在CMake中设置`ZXING_EXPERIMENTAL_API=ON`,但这不是导致克隆失败的原因。 根据错误信息“Failed to clone repository”,我们首先应解决克隆问题。 因此,回答将围绕克隆失败的可能原因和解决方案展开。 </think> 根据您的描述,CMake 使用 FetchContent 克隆 zxing-cpp 仓库失败并导致构建终止,可能的原因及解决方案如下: ### 错误原因分析 1. **网络连接问题** 克隆 GitHub 仓库失败最常见的原因是网络限制或代理配置不当。错误信息 `Failed to clone repository: 'https://github.com/zxing-cpp/zxing-cpp.git'` 表明 CMake 无法访问该 URL[^1]。 2. **依赖项缺失** 引用[1]强调需预装 Git 和 CMake,未正确安装会导致克隆失败。可通过以下命令验证: ```bash git --version && cmake --version ``` 3. **仓库地址变更或权限问题** 虽然 zxing-cpp 主仓库地址未变,但企业网络可能封锁 GitHub。可尝试直接访问 `https://github.com/zxing-cpp/zxing-cpp` 测试连通性。 4. **子模块依赖问题** zxing-cpp 的 CMake 配置涉及实验性 API 标志(引用[2]),若 `ZXING_EXPERIMENTAL_API` 启用但依赖缺失,会导致后续 `ninja` 构建失败。 5. **构建环境不兼容** Ninja 构建失败(`subcommand failed`)可能是编译器(GCC/Clang)版本过低或 OpenCV 未安装(引用[1][3])。 ### 解决方案 #### 阶段1:解决克隆失败 ```cmake # CMakeLists.txt 示例 include(FetchContent) FetchContent_Declare( zxing GIT_REPOSITORY https://github.com/zxing-cpp/zxing-cpp.git GIT_TAG v1.4.0 # 指定稳定版本 ) FetchContent_MakeAvailable(zxing) ``` 1. **手动验证克隆** 终端执行: ```bash git clone --depth=1 https://github.com/zing-cpp/zxing-cpp.git ``` 若失败,检查: - 网络代理设置(`git config --global http.proxy`) - DNS 解析(`nslookup github.com`) 2. **使用镜像仓库**(若企业网络限制) 修改 URL 为镜像站: ```cmake GIT_REPOSITORY https://gitee.com/mirrors/zxing-cpp.git ``` #### 阶段2:解决构建失败 1. **安装必需依赖** Ubuntu 示例: ```bash sudo apt install build-essential cmake git libopencv-dev ``` 2. **显式关闭实验性 API** 在 CMake 配置中添加(引用[2]): ```cmake set(ZXING_EXPERIMENTAL_API OFF CACHE BOOL "Disable experimental API") ``` 3. **检查构建日志** 查看完整错误: ```bash cmake --build build --verbose > build.log 2>&1 grep "error:" build.log ``` ### 验证步骤 ```bash mkdir build && cd build cmake -DZXING_EXPERIMENTAL_API=OFF .. make -j$(nproc) ``` > **重要提示**:若问题持续,尝试直接下载发行版源码(Releases 页)并用 `add_subdirectory` 替代 `FetchContent`[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值