Quagga在iOS 苹果 iphone 中图片旋转 无法识别条形码

186 阅读4分钟

项目需求是用户选取手机文件或者拍照,代码能识别图片里的条形码.

安卓机很正常,苹果手机上总是把图片顺时针旋转90度,导致无法识别.

用了很多方法,比如compressorjs处理,结果是文件选择可以,拍照不可以.

用exif-js获取图片的Orientation,然后用canvas旋转正确,但是搜索的博客代码怎么也不能正确实现.

但是中途实验中发现了一个特别简单的处理方法就可以解决这个问题,如下代码关键点在selectFileImage这个方法里,相当于重新读取一遍图片就能好. 项目用的vue3,如下是移动端单个页面.

<template>
    <div class="content1">
        <section id="container" class="container">
            <div class="controls">
                <fieldset class="input-group">
                    <input type="file" accept="">
                    <button id="btnIdents" @click="resultFunc">识别</button>
                </fieldset>
            </div>
            <div id="resulet">识别结果:{{ resultVal }}</div>
            <div>识别时间:{{ timeStr }}</div>
            <div id="interactive" class="viewport"><br clear="all"></div>
        </section>
        <van-uploader :after-read="imgAfterRead" :accept="''" result-type="text">
            <div class="btn btn_plus"><van-icon name="plus" />&nbsp;添加文件</div>
        </van-uploader>

        <!-- <img style="max-width:100%" :src="imgSrc" alt=""> -->

    </div>



</template>
<script lang='ts' setup>
import { ref } from 'vue';
import Quagga from 'quagga';
// import Compressor from 'compressorjs';
// import EXIF from "exif-js"
// const imgSrc = ref('')
const imgAfterRead = (file: any) => {
    // console.log('file1', file)
    // console.log('file2', file.file)
    // new Compressor(file.file, {
    //     success: (result) => {
    //         console.log('success', result)
    //         selectFileImage(result).then(res=>{
    //             decodeFunc(URL.createObjectURL(res));
    //         })
    //     },
    //     error(err) {
    //         console.log('error', err.message);
    //     },
    // });
    //需要判断下 只有苹果和web 估计要重置下,安卓应该挺正常的
    selectFileImage(file.file).then(res => {
        // console.log('selectFileImage1', res)
        // imgSrc.value = res
        decodeFunc(res);
    })


}

const resultFunc = () => {
    var input = document.querySelector(".controls input[type=file]");
    if (input.files && input.files.length) {
        // new Compressor(input.files[0], {
        //     success: (result) => {
        //         console.log('success', result)
        //         decodeFunc(URL.createObjectURL(result));
        //     },
        //     error(err) {
        //         console.log('error', err.message);
        //     },
        // });
        decodeFunc(URL.createObjectURL(input.files[0]));
    }
}
const defaultConfig = {
    inputStream: {
        size: 1920,
        // 最后一个键singchannel仅在有人想要调试解码器错误行为的情况下才相关。
        singleChannel: false
    },
    locator: {
        patchSize: "small",
        // halfSample标志告诉定位器进程它是否应该操作按比例缩小的图像(半宽/高,四分之一像素计数)。打开halfSample大大减少了处理时间,并且由于隐式平滑也有助于找到条形码模式。在条形码非常小并且需要全分辨率才能找到位置的情况下,应该关闭它。建议保持打开状态,必要时使用分辨率更高的视频图像。
        halfSample: true
    },
    decoder: {
        readers: [{
            format: "code_128_reader",
            config: {}
        }]
    },
    //对条形码定位---必开
    locate: true,
    src: null
}

const resultVal = ref('')
const timeStr = ref('')
const decodeFunc = (src) => {
    const config = { ...defaultConfig, src };

    Quagga.decodeSingle(config, function (result) {
        //识别结果
        if (result.codeResult) {
            resultVal.value = result.codeResult.code
            timeStr.value = new Date().toLocaleString()
        } else {
            resultVal.value = "未识别到图片中的条形码!"
            timeStr.value = ''
        }
    });
}






const selectFileImage = (file) => {
    return new Promise<void>((resolve, reject) => {
        if (file) {
                var oReader = new FileReader();
                oReader.onload = function (e) {
                    // console.log('oReader',e)
                    resolve(e.target.result)
                };
                oReader.readAsDataURL(file);
        }else{
            console.log('无文件传入')
        }
    })
}



</script>
<style lang='less' scoped>
.content1 {
    width: 100%;
    height: 100%;
    overflow: auto
}

#container {
    width: 100%;
    margin: 20px auto;
    padding: 10px;
}

#interactive.viewport {
    width: 100%;
    min-height: 480px;
}


#interactive.viewport canvas,
video {
    float: left;
    width: 100%;
    min-height: 480px;
}

#interactive.viewport canvas.drawingBuffer,
video.drawingBuffer {
    margin-left: -640px;
}

.controls fieldset {
    border: none;
    margin: 0;
    padding: 0;
}

.controls .input-group {
    float: left;
}

.controls .input-group input,
.controls .input-group button {
    display: block;
}

.controls .reader-config-group {
    float: right;
}

.controls .reader-config-group label {
    display: block;
}

.controls .reader-config-group label span {
    width: 9rem;
    display: inline-block;
    text-align: right;
}

.controls:after {
    content: '';
    display: block;
    clear: both;
}


#result_strip {
    margin: 10px 0;
    border-top: 1px solid #EEE;
    border-bottom: 1px solid #EEE;
    padding: 10px 0;
}

#result_strip>ul {
    padding: 0;
    margin: 0;
    list-style-type: none;
    width: auto;
    overflow-x: auto;
    overflow-y: hidden;
    white-space: nowrap;
}

#result_strip>ul>li {
    display: inline-block;
    vertical-align: middle;
    width: 160px;
}

#result_strip>ul>li .thumbnail {
    padding: 5px;
    margin: 4px;
    border: 1px dashed #CCC;
}

#result_strip>ul>li .thumbnail img {
    max-width: 140px;
}

#result_strip>ul>li .thumbnail .caption {
    white-space: normal;
}

#result_strip>ul>li .thumbnail .caption h4 {
    text-align: center;
    word-wrap: break-word;
    height: 40px;
    margin: 0px;
}

#result_strip>ul:after {
    content: "";
    display: table;
    clear: both;
}


.scanner-overlay {
    display: none;
    width: 640px;
    height: 510px;
    position: absolute;
    padding: 20px;
    top: 50%;
    margin-top: -275px;
    left: 50%;
    margin-left: -340px;
    background-color: #FFF;
    -moz-box-shadow: #333333 0px 4px 10px;
    -webkit-box-shadow: #333333 0px 4px 10px;
    box-shadow: #333333 0px 4px 10px;
}

.scanner-overlay>.header {
    position: relative;
    margin-bottom: 14px;
}

.scanner-overlay>.header h4,
.scanner-overlay>.header .close {
    line-height: 16px;
}

.scanner-overlay>.header h4 {
    margin: 0px;
    padding: 0px;
}

.scanner-overlay>.header .close {
    position: absolute;
    right: 0px;
    top: 0px;
    height: 16px;
    width: 16px;
    text-align: center;
    font-weight: bold;
    font-size: 14px;
    cursor: pointer;
}




@media (max-width: 603px) {

    #container {
        width: 300px;
        margin: 10px auto;
        -moz-box-shadow: none;
        -webkit-box-shadow: none;
        box-shadow: none;
    }

    #container form.voucher-form input.voucher-code {
        width: 180px;
    }
}

@media (max-width: 603px) {

    .reader-config-group {
        width: 100%;
    }

    .reader-config-group label>span {
        width: 50%;
    }

    .reader-config-group label>select,
    .reader-config-group label>input {
        max-width: calc(50% - 2px);
    }

    #interactive.viewport {
        width: 300px;
        height: 300px;
        overflow: hidden;
    }


    #interactive.viewport canvas,
    video {
        margin-top: -50px;
        width: 300px;
        height: 400px;
    }

    #interactive.viewport canvas.drawingBuffer,
    video.drawingBuffer {
        margin-left: -300px;
    }


    #result_strip {
        margin-top: 5px;
        padding-top: 5px;
    }

    #result_strip ul.thumbnails>li {
        width: 150px;
    }

    #result_strip ul.thumbnails>li .thumbnail .imgWrapper {
        width: 130px;
        height: 130px;
        overflow: hidden;
    }

    #result_strip ul.thumbnails>li .thumbnail .imgWrapper img {
        margin-top: -25px;
        width: 130px;
        height: 180px;
    }
}

@media (max-width: 603px) {

    .overlay.scanner {
        width: 640px;
        height: 510px;
        padding: 20px;
        margin-top: -275px;
        margin-left: -340px;
        background-color: #FFF;
        -moz-box-shadow: none;
        -webkit-box-shadow: none;
        box-shadow: none;
    }

    .overlay.scanner>.header {
        margin-bottom: 14px;
    }

    .overlay.scanner>.header h4,
    .overlay.scanner>.header .close {
        line-height: 16px;
    }

    .overlay.scanner>.header .close {
        height: 16px;
        width: 16px;
    }
}
</style>