Browse Source

[web_demo] 支持上传pdf文件,对上传文件格式进行限制,打包

yanxin 2 years ago
parent
commit
9d84b1af79

+ 1 - 1
src/api/index.ts

@@ -1,7 +1,7 @@
 import axios from "axios";
 
 const server = axios.create({
-  baseURL: "http://192.168.10.138:80",
+  baseURL: "http://192.168.10.12:80",
 });
 
 server.interceptors.request.use(

+ 189 - 0
src/components/PdfPreview.vue

@@ -0,0 +1,189 @@
+<!-- <template>
+  <div class="pdf-preview">
+        <div class="pdf-wrap">
+          <vue-pdf-embed :source="state.source" :style="scale" class="vue-pdf-embed" :page="state.pageNum" />
+        </div>
+        <div class="page-tool">
+          <div class="page-tool-item" @click="prePage">上一页</div>
+          <div class="page-tool-item" @click="nextPage">下一页</div>
+          <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
+          <div class="page-tool-item" @click="pageZoomOut">放大</div>
+          <div class="page-tool-item" @click="pageZoomIn">缩小</div>
+          <el-input type="number" v-model="pdf_page"></el-input>
+          <el-button type="primary" @click="SetPdfPage" plain>页面跳转</el-button>
+        </div>
+      </div>
+</template>
+
+<script lang="ts" setup>
+import { reactive, ref, toRefs, computed } from 'vue'
+import { onMounted } from "vue";
+import VuePdfEmbed from "vue-pdf-embed";
+import { createLoadingTask } from "vue3-pdfjs/esm"; // 获得总页数
+
+let loadingTask: any;
+
+const pdf_page = ref(1);
+
+const state = reactive({
+  source: "", //预览pdf文件地址
+  pageNum: 1, //当前页面
+  scale: 1, // 缩放比例
+  numPages: 0, // 总页数
+});
+
+const scale = computed(() => `transform:scale(${state.scale})`)
+
+function getPdfImage(index: number) {
+  // console.log(index, state.pageNum)
+  loadingTask.promise.then((pdf: any) => {
+    state.numPages = pdf.numPages;
+    pdf.getPage(index).then((page: any) => {
+      const viewport = page.getViewport({ scale: 1 })
+      canvas.value.height = viewport.height;
+      canvas.value.width = viewport.width;
+      // 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
+      // const clientWidth = document.body.clientWidth;
+      const destWidth = 398;
+      canvas.value.style.width = destWidth + 'px';
+      // 根据pdf每页的宽高比例设置canvas的高度
+      canvas.value.style.height = destWidth * (viewport.height / viewport.width) + 'px';
+      const ctx = canvas.value.getContext('2d');
+      page.render({
+        canvasContext: ctx,
+        viewport,
+      });
+      canvas.value.toBlob(function (blob) {
+        pdf_img.value = dataURLtoBlob(canvas.value.toDataURL())
+        // console.log(pdf_img.value);
+        console.log(canvas.value.toDataURL(), state.pageNum)
+      });
+    })
+  });
+}
+
+function SetPdfPage() {
+  if (pdf_page.value >= 1 && pdf_page.value <= state.numPages) {
+    console.log(pdf_page.value)
+    state.pageNum = Number(pdf_page.value);
+    getPdfImage(state.pageNum);
+  } else {
+    console.log(pdf_page.value)
+    alert('输入的pdf页面无效!')
+  }
+}
+
+function prePage() {
+  if (state.pageNum > 1) {
+    state.pageNum -= 1;
+    getPdfImage(state.pageNum);
+  }
+}
+
+function nextPage() {
+  if (state.pageNum < state.numPages) {
+    state.pageNum += 1;
+    getPdfImage(state.pageNum);
+  }
+}
+function pageZoomOut() {
+  if (state.scale < 2) {
+    state.scale += 0.1;
+  }
+}
+function pageZoomIn() {
+  if (state.scale > 1) {
+    state.scale -= 0.1;
+  }
+}
+
+function dataURLtoBlob(dataURL: any) {
+  var arr = dataURL.split(','),
+      mime = arr[0].match(/:(.*?);/)[1],
+      bstr = atob(arr[1]),
+      n = bstr.length,
+      u8arr = new Uint8Array(n);
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n);
+  }
+  return new Blob([u8arr], {type:mime});
+}
+
+async function convertCanvasToFile(canvas: HTMLCanvasElement, fileName: any) {
+  // 将 Canvas 转为 Blob 对象
+  const blob = await new Promise(resolve => canvas.toBlob(blob => {
+            resolve(blob);
+        }, pdf_img.value.type, 1.0));
+  // 手动构造 File 对象
+  let file = null;
+  try {
+    file = new File([pdf_img.value], fileName, { type: pdf_img.value.type });
+  } catch (e) {
+    // Safari 浏览器不支持直接通过 new File() 创建文件对象,需要手动构造
+    const rawFile = blobToFile(blob, fileName);
+    file = Object.assign(rawFile, { lastModifiedDate: new Date(), name: fileName });
+  }
+  return file;
+}
+
+</script>
+
+<style scoped>
+.pdf-preview {
+  position: relative;
+  height: 100vh;
+  padding: 20px 0;
+  box-sizing: border-box;
+  background: rgb(66, 66, 66);
+}
+
+.vue-pdf-embed {
+  text-align: center;
+  width: 515px;
+  border: 1px solid #e5e5e5;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+.pdf-preview {
+  position: relative;
+  height: 100vh;
+  padding: 20px 0;
+  box-sizing: border-box;
+  background-color: e9e9e9;
+}
+
+.pdf-wrap {
+  overflow-y: auto;
+}
+
+.vue-pdf-embed {
+  text-align: center;
+  width: 515px;
+  border: 1px solid #e5e5e5;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+.page-tool {
+  position: absolute;
+  /* bottom: 35px; */
+  /* padding-left: 15px; */
+  /* padding-right: 15px; */
+  display: flex;
+  align-items: center;
+  background: rgb(66, 66, 66);
+  color: white;
+  border-radius: 19px;
+  z-index: 100;
+  cursor: pointer;
+  margin-left: 50%;
+  transform: translateX(-50%);
+}
+
+.page-tool-item {
+  padding: 8px 15px;
+  padding-left: 10px;
+  cursor: pointer;
+}
+</style> -->

File diff suppressed because it is too large
+ 188 - 0
src/dist/assets/index-0abca9b8.js


File diff suppressed because it is too large
+ 1 - 1
src/dist/assets/index-24806aec.css


File diff suppressed because it is too large
+ 0 - 188
src/dist/assets/index-6d75ca26.js


+ 2 - 2
src/dist/index.html

@@ -4,8 +4,8 @@
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>DocumentAI Web Demo</title>
-    <script type="module" crossorigin src="./assets/index-6d75ca26.js"></script>
-    <link rel="stylesheet" href="./assets/index-24806aec.css">
+    <script type="module" crossorigin src="./assets/index-0abca9b8.js"></script>
+    <link rel="stylesheet" href="./assets/index-557b431a.css">
   </head>
   <body>
     <div id="app"></div>

+ 257 - 17
src/pages/main/views/ImageProcess/magicColor.vue

@@ -9,7 +9,7 @@
           <p>V1 主要针对文档图片,去阴影效果较好</p>
         </el-row>
         <el-row style="color: gray; font-size: small;">
-          <h4>上传原图</h4>
+          <h4>支持jpg, png, bmp, pdf格式</h4>
         </el-row>
         <div class="common-layout">
           <el-container>
@@ -17,12 +17,35 @@
             <el-button type="primary" @click="predict">Predict</el-button>
           </el-container>
         </div>
-        <el-row>
+        <el-row v-show="!is_pdf">
           <!-- 用于展示图片 -->
           <img id="show-img" class="show-area" />
           <!-- 用于存放真实图片 -->
           <img id="raw-img" style="display: none" />
         </el-row>
+        <div class="pdf-preview" v-show="is_pdf">
+          <div class="pdf-wrap">
+            <vue-pdf-embed :source="state.source" :style="scale" class="vue-pdf-embed" :page="state.pageNum" />
+          </div>
+          <div class="page-tool">
+            <div class="page-tool-item" @click="prePage">上一页</div>
+            <div class="page-tool-item" @click="nextPage">下一页</div>
+            <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
+            <div class="page-tool-item" @click="pageZoomOut">放大</div>
+            <div class="page-tool-item" @click="pageZoomIn">缩小</div>
+          </div>
+          <div style="margin-top: 50px;">
+            <el-row class="page-tool">
+              <div class="common-layout">
+                <el-container>
+                  <el-input type="number" v-model="pdf_page"></el-input>
+                  <el-button type="primary" @click="SetPdfPage" plain>页面跳转</el-button>
+                </el-container>
+              </div>
+            </el-row>
+          </div>
+        </div>
+        <canvas id="canvas" style="display: none;"></canvas>
       </el-col>
     </div>
     <div class="block">
@@ -55,12 +78,131 @@
 </template>
 
 <script lang="ts" setup>
-import { onMounted, ref } from "vue";
 import { IMMagicColor, SubmitBug } from '../../../../api/api'
 import { useServerIpStore } from '../../../../store/ServerIp';
 import { storeToRefs } from 'pinia'
+
+import { reactive, ref, toRefs, computed } from 'vue'
+import { onMounted } from "vue";
+import VuePdfEmbed from "vue-pdf-embed";
+import { createLoadingTask } from "vue3-pdfjs/esm"; // 获得总页数
+
+let loadingTask: any;
+
+const pdf_page = ref(1);
+
+const pdf_img: any = ref("")
+
+const state = reactive({
+  source: "", //预览pdf文件地址
+  pageNum: 1, //当前页面
+  scale: 1, // 缩放比例
+  numPages: 0, // 总页数
+});
+
+const scale = computed(() => `transform:scale(${state.scale})`)
+
+function dataURLtoBlob(dataURL: any) {
+  var arr = dataURL.split(','),
+    mime = arr[0].match(/:(.*?);/)[1],
+    bstr = atob(arr[1]),
+    n = bstr.length,
+    u8arr = new Uint8Array(n);
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n);
+  }
+  return new Blob([u8arr], { type: mime });
+}
+
+function getPdfImage(index: number) {
+  // console.log(index, state.pageNum)
+  loadingTask.promise.then((pdf: any) => {
+    state.numPages = pdf.numPages;
+    pdf.getPage(index).then((page: any) => {
+      const viewport = page.getViewport({ scale: 1 })
+      canvas.value.height = viewport.height;
+      canvas.value.width = viewport.width;
+      // 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
+      // const clientWidth = document.body.clientWidth;
+      const destWidth = 398;
+      canvas.value.style.width = destWidth + 'px';
+      // 根据pdf每页的宽高比例设置canvas的高度
+      canvas.value.style.height = destWidth * (viewport.height / viewport.width) + 'px';
+      const ctx = canvas.value.getContext('2d');
+      page.render({
+        canvasContext: ctx,
+        viewport,
+      });
+      canvas.value.toBlob(function (blob) {
+        pdf_img.value = dataURLtoBlob(canvas.value.toDataURL())
+        // console.log(pdf_img.value);
+        console.log(canvas.value.toDataURL(), state.pageNum)
+      });
+    })
+  });
+}
+
+function SetPdfPage() {
+  if (pdf_page.value >= 1 && pdf_page.value <= state.numPages) {
+    console.log(pdf_page.value)
+    state.pageNum = Number(pdf_page.value);
+    getPdfImage(state.pageNum);
+  } else {
+    console.log(pdf_page.value)
+    alert('输入的pdf页面无效!')
+  }
+}
+
+function prePage() {
+  if (state.pageNum > 1) {
+    state.pageNum -= 1;
+    getPdfImage(state.pageNum);
+  }
+}
+
+function nextPage() {
+  if (state.pageNum < state.numPages) {
+    state.pageNum += 1;
+    getPdfImage(state.pageNum);
+  }
+}
+function pageZoomOut() {
+  if (state.scale < 2) {
+    state.scale += 0.1;
+  }
+}
+function pageZoomIn() {
+  if (state.scale > 1) {
+    state.scale -= 0.1;
+  }
+}
+
+// 构建 File 对象
+function blobToFile(blob: any, fileName: any) {
+  blob.lastModifiedDate = new Date();
+  blob.name = fileName;
+  return blob;
+}
+
+async function convertCanvasToFile(canvas: HTMLCanvasElement, fileName: any) {
+  // 将 Canvas 转为 Blob 对象
+  const blob = await new Promise(resolve => canvas.toBlob(blob => {
+    resolve(blob);
+  }, pdf_img.value.type, 1.0));
+  // 手动构造 File 对象
+  let file = null;
+  try {
+    file = new File([pdf_img.value], fileName, { type: pdf_img.value.type });
+  } catch (e) {
+    // Safari 浏览器不支持直接通过 new File() 创建文件对象,需要手动构造
+    const rawFile = blobToFile(blob, fileName);
+    file = Object.assign(rawFile, { lastModifiedDate: new Date(), name: fileName });
+  }
+  return file;
+}
+
 const si = useServerIpStore()
-const {server_ip} = storeToRefs(si);
+const { server_ip } = storeToRefs(si);
 
 let loading = ref(false)
 const fileName = ref(null);
@@ -69,6 +211,8 @@ let bugId = ref("");
 
 let predictTime = ref(0)
 
+const is_pdf = ref(false);
+
 const canvas = ref(null as unknown as HTMLCanvasElement);
 
 onMounted(async () => {
@@ -87,8 +231,22 @@ const uploadImg = () => {
   try {
     const file = inputElement.files![0];
     reader.onload = () => {
-      showImg.src = URL.createObjectURL(file);
-      rawImg.src = URL.createObjectURL(file);
+      const post_ = file.name.substring(file.name.lastIndexOf("."), file.name.length).toLowerCase();
+      if (post_ == ".pdf") {
+        state.pageNum = 1;
+        state.scale = 1;
+        state.source = URL.createObjectURL(file);
+        is_pdf.value = true
+        loadingTask = createLoadingTask(state.source);
+        getPdfImage(state.pageNum);
+      } else if (post_ == ".jpg" || post_ == ".png" || post_ == ".bmp"){
+        showImg.src = URL.createObjectURL(file);
+        rawImg.src = URL.createObjectURL(file);
+        is_pdf.value = false
+      } else {
+        alert('不支持的文件格式!')
+        fileName.value = null
+      }
     };
     reader.readAsDataURL(file);
   } catch (err) {
@@ -111,19 +269,43 @@ const predict = () => {
 
   loading.value = !loading.value
   var data = new FormData();
-  data.append('images', file);
 
-  IMMagicColor(data).then(res => {
-    predictImg.src = server_ip.value + res.data.out_image
-    predictTime.value = res.data.cost
-    bugId.value = res.response_id;
+  if (is_pdf.value) {
+    const file: any = convertCanvasToFile(canvas.value, "pdf.png").then(result => {
+      console.log(result)
+      data.append('images', result);
+      IMMagicColor(data).then(res => {
+        console.log(res.code)
+        // bug_id.value = res.response_id;
+        predictImg.src = server_ip.value + res.data.out_image
+        predictTime.value = res.data.cost
+        bugId.value = res.response_id;
 
-    loading.value = !loading.value
-  }).catch(function (err) {
-    loading.value = !loading.value;
-    bugId.value = ""
-    predictTime.value = 0
-  });
+
+        loading.value = false
+      }).catch(function (err) {
+        loading.value = false
+        // bug_id.value = ""
+        predictTime.value = 0
+      });
+    })
+    // console.log(file)
+    // data.append('images', file.File);
+  } else {
+    data.append('images', file);
+
+    IMMagicColor(data).then(res => {
+      predictImg.src = server_ip.value + res.data.out_image
+      predictTime.value = res.data.cost
+      bugId.value = res.response_id;
+
+      loading.value = !loading.value
+    }).catch(function (err) {
+      loading.value = !loading.value;
+      bugId.value = ""
+      predictTime.value = 0
+    });
+  }
 }
 
 const submitBug = async () => {
@@ -191,4 +373,62 @@ let src = ''
   justify-content: space-between;
   align-items: center;
 }
+
+.pdf-preview {
+  position: relative;
+  height: 100vh;
+  padding: 20px 0;
+  box-sizing: border-box;
+  background: rgb(66, 66, 66);
+}
+
+.vue-pdf-embed {
+  text-align: center;
+  width: 515px;
+  border: 1px solid #e5e5e5;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+.pdf-preview {
+  position: relative;
+  height: 100vh;
+  padding: 20px 0;
+  box-sizing: border-box;
+  background-color: e9e9e9;
+}
+
+.pdf-wrap {
+  overflow-y: auto;
+}
+
+.vue-pdf-embed {
+  text-align: center;
+  width: 515px;
+  border: 1px solid #e5e5e5;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+.page-tool {
+  position: absolute;
+  /* bottom: 35px; */
+  /* padding-left: 15px; */
+  /* padding-right: 15px; */
+  display: flex;
+  align-items: center;
+  background: rgb(66, 66, 66);
+  color: white;
+  border-radius: 19px;
+  z-index: 100;
+  cursor: pointer;
+  margin-left: 50%;
+  transform: translateX(-50%);
+}
+
+.page-tool-item {
+  padding: 8px 15px;
+  padding-left: 10px;
+  cursor: pointer;
+}
 </style>

+ 264 - 31
src/pages/main/views/Recognize/ocr.vue

@@ -9,7 +9,7 @@
         <p>支持识别图片/通过领先的深度学习技术,对各种表格,图片,文档、证件、面单等多种通用场景进行快速、精准的检测和识别,支持简体中文/繁体中文/英文/西欧主流语言等多种种语言,同时支持印刷体、手写体、倾斜、折叠、旋转等。</p>
       </el-row>
       <el-row style="color: gray; font-size: small;">
-        <h4>上传文本图片</h4>
+        <h4>支持jpg, png, bmp, pdf格式</h4>
       </el-row>
       <el-row>
         <div class="common-layout">
@@ -20,6 +20,28 @@
           </el-container>
         </div>
       </el-row>
+      <div class="pdf-preview" v-show="is_pdf">
+        <div class="pdf-wrap">
+          <vue-pdf-embed :source="state.source" :style="scale" class="vue-pdf-embed" :page="state.pageNum" />
+        </div>
+        <div class="page-tool">
+          <div class="page-tool-item" @click="prePage">上一页</div>
+          <div class="page-tool-item" @click="nextPage">下一页</div>
+          <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
+          <div class="page-tool-item" @click="pageZoomOut">放大</div>
+          <div class="page-tool-item" @click="pageZoomIn">缩小</div>
+        </div>
+        <div style="margin-top: 50px;">
+          <el-row class="page-tool">
+            <div class="common-layout">
+              <el-container>
+                <el-input type="number" v-model="pdf_page"></el-input>
+                <el-button type="primary" @click="SetPdfPage" plain>页面跳转</el-button>
+              </el-container>
+            </div>
+          </el-row>
+        </div>
+      </div>
     </el-col>
     <el-col :span="8" class="place">
       <el-row class="small-title">
@@ -29,10 +51,10 @@
         <!-- <p v-if="loading">处理中</p> -->
       </el-row>
       <el-row>
-        <!-- <canvas id="canvas" class="show-area"></canvas> -->
-        <!-- <img id="predict-img" class="show-area" v-show="show_predict" /> -->
+        <!-- 用于展示图片 -->
         <img id="show-img" class="show-area" />
       </el-row>
+      <canvas id="canvas" style="display: none;"></canvas>
       <el-row>
         <section> 耗时:{{ predictTime }} ms.</section>
       </el-row>
@@ -51,7 +73,7 @@
           </el-collapse-item>
           <el-collapse-item title="识别结果" name="2">
             <el-scrollbar height="600px">
-              <span v-html="result"></span>
+              <span v-html="rec_result"></span>
             </el-scrollbar>
           </el-collapse-item>
         </el-collapse>
@@ -61,26 +83,144 @@
 </template>
 
 <script lang='ts' setup>
-import { reactive, ref, toRefs } from 'vue'
-import { onMounted } from "vue";
 import { OcrRec, SubmitBug } from '../../../../api/api'
 import { useServerIpStore } from '../../../../store/ServerIp';
 import { storeToRefs } from 'pinia'
 import OcrLangList from '../../../../components/OcrLangList.vue'
 import { useOcrLangStore } from '../../../../store/OcrLang';
 
+import { reactive, ref, toRefs, computed } from 'vue'
+import { onMounted } from "vue";
+import VuePdfEmbed from "vue-pdf-embed";
+import { createLoadingTask } from "vue3-pdfjs/esm"; // 获得总页数
+
+let loadingTask: any;
+
+const is_pdf = ref(false);
+const pdf_page = ref(1);
+const pdf_img: any = ref("")
+
+const state = reactive({
+  source: "", //预览pdf文件地址
+  pageNum: 1, //当前页面
+  scale: 1, // 缩放比例
+  numPages: 0, // 总页数
+});
+
+const scale = computed(() => `transform:scale(${state.scale})`)
+
+function dataURLtoBlob(dataURL: any) {
+  var arr = dataURL.split(','),
+    mime = arr[0].match(/:(.*?);/)[1],
+    bstr = atob(arr[1]),
+    n = bstr.length,
+    u8arr = new Uint8Array(n);
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n);
+  }
+  return new Blob([u8arr], { type: mime });
+}
+
+function getPdfImage(index: number) {
+  // console.log(index, state.pageNum)
+  loadingTask.promise.then((pdf: any) => {
+    state.numPages = pdf.numPages;
+    pdf.getPage(index).then((page: any) => {
+      const viewport = page.getViewport({ scale: 1 })
+      canvas.value.height = viewport.height;
+      canvas.value.width = viewport.width;
+      // 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
+      // const clientWidth = document.body.clientWidth;
+      const destWidth = 398;
+      canvas.value.style.width = destWidth + 'px';
+      // 根据pdf每页的宽高比例设置canvas的高度
+      canvas.value.style.height = destWidth * (viewport.height / viewport.width) + 'px';
+      const ctx = canvas.value.getContext('2d');
+      page.render({
+        canvasContext: ctx,
+        viewport,
+      });
+      canvas.value.toBlob(function (blob) {
+        pdf_img.value = dataURLtoBlob(canvas.value.toDataURL())
+        const showImg = document.getElementById("show-img") as HTMLImageElement;
+        showImg.src = canvas.value.toDataURL();
+        // console.log(canvas.value.toDataURL(), state.pageNum)
+      });
+    })
+  });
+}
+
+function SetPdfPage() {
+  if (pdf_page.value >= 1 && pdf_page.value <= state.numPages) {
+    console.log(pdf_page.value)
+    state.pageNum = Number(pdf_page.value);
+    getPdfImage(state.pageNum);
+  } else {
+    console.log(pdf_page.value)
+    alert('输入的pdf页面无效!')
+  }
+}
+
+function prePage() {
+  if (state.pageNum > 1) {
+    state.pageNum -= 1;
+    getPdfImage(state.pageNum);
+  }
+}
+
+function nextPage() {
+  if (state.pageNum < state.numPages) {
+    state.pageNum += 1;
+    getPdfImage(state.pageNum);
+  }
+}
+function pageZoomOut() {
+  if (state.scale < 2) {
+    state.scale += 0.1;
+  }
+}
+function pageZoomIn() {
+  if (state.scale > 1) {
+    state.scale -= 0.1;
+  }
+}
+
+// 构建 File 对象
+function blobToFile(blob: any, fileName: any) {
+  blob.lastModifiedDate = new Date();
+  blob.name = fileName;
+  return blob;
+}
+
+async function convertCanvasToFile(canvas: HTMLCanvasElement, fileName: any) {
+  // 将 Canvas 转为 Blob 对象
+  const blob = await new Promise(resolve => canvas.toBlob(blob => {
+    resolve(blob);
+  }, pdf_img.value.type, 1.0));
+  // 手动构造 File 对象
+  let file = null;
+  try {
+    file = new File([pdf_img.value], fileName, { type: pdf_img.value.type });
+  } catch (e) {
+    // Safari 浏览器不支持直接通过 new File() 创建文件对象,需要手动构造
+    const rawFile = blobToFile(blob, fileName);
+    file = Object.assign(rawFile, { lastModifiedDate: new Date(), name: fileName });
+  }
+  return file;
+}
+
 const ol = useOcrLangStore();
 const { ocr_lang } = storeToRefs(ol);
 
 const si = useServerIpStore()
-const {server_ip} = storeToRefs(si);
+const { server_ip } = storeToRefs(si);
 
 let loading = ref(false)
 let show_predict = ref(false)
 let predictTime = ref(0)
 const fileName = ref(null);
 const canvas = ref(null as unknown as HTMLCanvasElement);
-const result = ref("");
+const rec_result = ref("");
 let bugId = ref("");
 
 const activeName = ref('2')
@@ -97,8 +237,6 @@ const uploadImg = () => {
   const reader = new FileReader();
   // 用于展示
   const showImg = document.getElementById("show-img") as HTMLImageElement;
-  // 用于识别
-  // const rawImg = document.getElementById("raw-img") as HTMLImageElement;
   const inputElement = document
     .getElementsByClassName("el-input")[0]
     .getElementsByTagName("input")[0];
@@ -106,8 +244,21 @@ const uploadImg = () => {
   try {
     const file = inputElement.files![0];
     reader.onload = () => {
-      showImg.src = URL.createObjectURL(file);
-      // rawImg.src = URL.createObjectURL(file);
+      const post_ = file.name.substring(file.name.lastIndexOf("."), file.name.length).toLowerCase();
+      if (post_ == ".pdf") {
+        state.pageNum = 1;
+        state.scale = 1;
+        state.source = URL.createObjectURL(file);
+        is_pdf.value = true
+        loadingTask = createLoadingTask(state.source);
+        getPdfImage(state.pageNum);
+      } else if (post_ == ".jpg" || post_ == ".png" || post_ == ".bmp") {
+        showImg.src = URL.createObjectURL(file);
+        is_pdf.value = false
+      }  else {
+        alert('不支持的文件格式!')
+        fileName.value = null
+      }
     };
     reader.readAsDataURL(file);
   } catch (err) {
@@ -137,24 +288,48 @@ const predict = async () => {
   loading.value = !loading.value
   var data = new FormData();
   data.append('lang', ocr_lang.value);
-  data.append('images', file);
-
-  OcrRec(data).then(res => {
-    console.log("res code: " + res.code)
-    json_result.value = JSON.stringify(res.data, null, 4);
-    // let json_obj = JSON.parse(json_result.value)
-    result.value = res.data.text.reduce((total: any, cur: any) => total + `<p>${cur}</p>`);
-    img.src = server_ip.value + res.data.visualize_img;
-    predictTime.value = res.data.cost;
-    loading.value = !loading.value;
-    bugId.value = res.response_id;
-    if (show_predict.value === false)
-      show_predict.value = !show_predict.value;
-  }).catch(function (err) {
-    loading.value = !loading.value;
-    bugId.value = ""
-    predictTime.value = 0
-  });
+
+  if (is_pdf.value) {
+    const file: any = convertCanvasToFile(canvas.value, "pdf.png").then(result => {
+      console.log(result)
+      data.append('images', result);
+      OcrRec(data).then(res => {
+        console.log("res code: " + res.code)
+        json_result.value = JSON.stringify(res.data, null, 4);
+        // let json_obj = JSON.parse(json_result.value)
+        rec_result.value = res.data.text.reduce((total: any, cur: any) => total + `<p>${cur}</p>`);
+        img.src = server_ip.value + res.data.visualize_img;
+        predictTime.value = res.data.cost;
+        loading.value = !loading.value;
+        bugId.value = res.response_id;
+        if (show_predict.value === false)
+          show_predict.value = !show_predict.value;
+      }).catch(function (err) {
+        loading.value = !loading.value;
+        bugId.value = ""
+        predictTime.value = 0
+      });
+    })
+  } else {
+    data.append('images', file);
+
+    OcrRec(data).then(res => {
+      console.log("res code: " + res.code)
+      json_result.value = JSON.stringify(res.data, null, 4);
+      // let json_obj = JSON.parse(json_result.value)
+      rec_result.value = res.data.text.reduce((total: any, cur: any) => total + `<p>${cur}</p>`);
+      img.src = server_ip.value + res.data.visualize_img;
+      predictTime.value = res.data.cost;
+      loading.value = !loading.value;
+      bugId.value = res.response_id;
+      if (show_predict.value === false)
+        show_predict.value = !show_predict.value;
+    }).catch(function (err) {
+      loading.value = !loading.value;
+      bugId.value = ""
+      predictTime.value = 0
+    });
+  }
 };
 
 const submitBug = async () => {
@@ -162,7 +337,7 @@ const submitBug = async () => {
     alert('请先预测结果!')
     return;
   }
-  
+
 
   SubmitBug(bugId.value).then(res => {
     console.log(res.code, res.data)
@@ -189,4 +364,62 @@ const submitBug = async () => {
   margin-left: auto;
   border-right: solid 1px #ccc;
 }
+
+.pdf-preview {
+  position: relative;
+  height: 100vh;
+  padding: 20px 0;
+  box-sizing: border-box;
+  background: rgb(66, 66, 66);
+}
+
+.vue-pdf-embed {
+  text-align: center;
+  width: 515px;
+  border: 1px solid #e5e5e5;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+.pdf-preview {
+  position: relative;
+  height: 100vh;
+  padding: 20px 0;
+  box-sizing: border-box;
+  background-color: e9e9e9;
+}
+
+.pdf-wrap {
+  overflow-y: auto;
+}
+
+.vue-pdf-embed {
+  text-align: center;
+  width: 515px;
+  border: 1px solid #e5e5e5;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+.page-tool {
+  position: absolute;
+  /* bottom: 35px; */
+  /* padding-left: 15px; */
+  /* padding-right: 15px; */
+  display: flex;
+  align-items: center;
+  background: rgb(66, 66, 66);
+  color: white;
+  border-radius: 19px;
+  z-index: 100;
+  cursor: pointer;
+  margin-left: 50%;
+  transform: translateX(-50%);
+}
+
+.page-tool-item {
+  padding: 8px 15px;
+  padding-left: 10px;
+  cursor: pointer;
+}
 </style>

+ 54 - 43
src/pages/main/views/Recognize/tableRec.vue

@@ -9,7 +9,7 @@
         <p>支持识别图片/PDF格式文档中的表格内容,包括有线表格、无线表格、合并单元格表格,同时支持单张图片内的多个表格内容识别,返回各表格的表头表尾内容、单元格文字内容及其行列位置信息。</p>
       </el-row>
       <el-row style="color: gray; font-size: small;">
-        <h4>上传图片、pdf</h4>
+        <h4>支持jpg, png, bmp, pdf格式</h4>
       </el-row>
       <div class="common-layout">
         <el-container>
@@ -79,18 +79,20 @@ import { onMounted } from "vue";
 import { TableRec, SubmitBug } from '../../../../api/api'
 import VuePdfEmbed from "vue-pdf-embed";
 import { createLoadingTask } from "vue3-pdfjs/esm"; // 获得总页数
-import { useServerIpStore } from '../../../../store/ServerIp';
+// import { useServerIpStore } from '../../../../store/ServerIp';
 import { storeToRefs } from 'pinia'
 import OcrLangList from '../../../../components/OcrLangList.vue'
 import { useOcrLangStore } from '../../../../store/OcrLang';
-import { tr } from 'element-plus/es/locale';
-import { result } from 'lodash';
+import { useBugIdStore } from '../../../../store/BugID';
 
 const ol = useOcrLangStore();
 const { ocr_lang } = storeToRefs(ol);
 
-const si = useServerIpStore()
-const { server_ip } = storeToRefs(si);
+const bi = useBugIdStore();
+const { bug_id } = storeToRefs(bi);
+
+// const si = useServerIpStore()
+// const { server_ip } = storeToRefs(si);
 
 const state = reactive({
   source: "", //预览pdf文件地址
@@ -99,8 +101,6 @@ const state = reactive({
   numPages: 0, // 总页数
 });
 
-const pdf_url = ref("")
-
 let loading = ref(false)
 let predictTime = ref(0)
 const fileName = ref(null);
@@ -114,18 +114,11 @@ const pdf_img: any = ref("")
 
 const canvas = ref(null as unknown as HTMLCanvasElement);
 
-const html_result = ref("");
-const json_result = ref("");
-
 let jsonArr: any = ref([])
 let htmlArr: any = ref([])
 
-let bugId = ref("");
-
 let loadingTask: any;
 
-// let pdf_url : Ref<string> = ref("");
-
 onMounted(async () => {
   canvas.value = document.getElementById("canvas") as HTMLCanvasElement;
 });
@@ -147,20 +140,21 @@ const uploadImg = () => {
     const file = inputElement.files![0];
     reader.onload = () => {
       // console.log(file.name.substring(file.name.lastIndexOf("."), file.name.length))
-      if (file.name.substring(file.name.lastIndexOf("."), file.name.length) == ".pdf" ||
-        file.name.substring(file.name.lastIndexOf("."), file.name.length) == ".PDF") {
-
+      const post_ = file.name.substring(file.name.lastIndexOf("."), file.name.length).toLowerCase();
+      if (post_ == ".pdf") {
         state.pageNum = 1;
         state.scale = 1;
         state.source = URL.createObjectURL(file);
         is_pdf.value = true
-        pdf_url.value = URL.createObjectURL(file);
         loadingTask = createLoadingTask(state.source);
         getPdfImage(state.pageNum);
-      } else {
+      } else if (post_ == ".jpg" || post_ == ".png" || post_ == ".bmp"){
         showImg.src = URL.createObjectURL(file);
         rawImg.src = URL.createObjectURL(file);
         is_pdf.value = false
+      } else {
+        alert('不支持的文件格式!')
+        fileName.value = null
       }
     };
     reader.readAsDataURL(file);
@@ -195,18 +189,26 @@ const predict = async () => {
       console.log(result)
       data.append('images', result);
       TableRec(data).then(res => {
-        // console.log(res.code)
-
-        bugId.value = res.response_id;
-        predictTime.value = res.data.cost;
-        // html_result.value = res.data.html;
-        // json_result.value = res.data.json;
-        loading.value = false
-      }).catch(function (err) {
-        loading.value = false
-        bugId.value = ""
-        predictTime.value = 0
-      });
+      console.log(res.code)
+      bug_id.value = res.response_id;
+      predictTime.value = res.data.cost;
+      jsonArr.value.splice(0);
+      let tmp_json = res.data.json_items;
+      for (let i = 0; i < tmp_json.length; i++) {
+        jsonArr.value.push(JSON.stringify(tmp_json[i], null, 4));
+      }
+
+      htmlArr.value.splice(0);
+      let tmp_html = res.data.html_items;
+      for (let i = 0; i < tmp_html.length; i++) {
+        htmlArr.value.push(tmp_html[i]);
+      }
+      loading.value = false
+    }).catch(function (err) {
+      loading.value = false
+      bug_id.value = ""
+      predictTime.value = 0
+    });
     })
     // console.log(file)
     // data.append('images', file.File);
@@ -215,28 +217,23 @@ const predict = async () => {
     data.append('images', file);
     TableRec(data).then(res => {
       console.log(res.code)
-      bugId.value = res.response_id;
+      bug_id.value = res.response_id;
       predictTime.value = res.data.cost;
-      // jsonArr = JSON.parse(res.data.json_items)
-      json_result.value = JSON.stringify(res.data.json_items, null, 4);
       jsonArr.value.splice(0);
       let tmp_json = res.data.json_items;
-      // jsonArr = res.data.json_items;
       for (let i = 0; i < tmp_json.length; i++) {
         jsonArr.value.push(JSON.stringify(tmp_json[i], null, 4));
       }
-      jsonArr.value.reverse();
 
       htmlArr.value.splice(0);
       let tmp_html = res.data.html_items;
       for (let i = 0; i < tmp_html.length; i++) {
         htmlArr.value.push(tmp_html[i]);
       }
-      htmlArr.value.reverse();
       loading.value = false
     }).catch(function (err) {
       loading.value = false
-      bugId.value = ""
+      bug_id.value = ""
       predictTime.value = 0
     });
   }
@@ -256,12 +253,12 @@ function SetPdfPage() {
 }
 
 const submitBug = async () => {
-  if (bugId.value == undefined || bugId.value == "") {
+  if (bug_id.value == undefined || bug_id.value == "") {
     alert('请先预测结果!')
     return;
   }
 
-  SubmitBug(bugId.value).then(res => {
+  SubmitBug(bug_id.value).then(res => {
     console.log(res.code, res.data)
   }).catch(function (err) {
     console.log(err)
@@ -271,7 +268,9 @@ const submitBug = async () => {
 
 async function convertCanvasToFile(canvas: HTMLCanvasElement, fileName: any) {
   // 将 Canvas 转为 Blob 对象
-  const blob = await new Promise(resolve => canvas.toBlob(resolve));
+  const blob = await new Promise(resolve => canvas.toBlob(blob => {
+            resolve(blob);
+        }, pdf_img.value.type, 1.0));
   // 手动构造 File 对象
   let file = null;
   try {
@@ -291,6 +290,18 @@ function blobToFile(blob: any, fileName: any) {
   return blob;
 }
 
+function dataURLtoBlob(dataURL: any) {
+  var arr = dataURL.split(','),
+      mime = arr[0].match(/:(.*?);/)[1],
+      bstr = atob(arr[1]),
+      n = bstr.length,
+      u8arr = new Uint8Array(n);
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n);
+  }
+  return new Blob([u8arr], {type:mime});
+}
+
 function getPdfImage(index: number) {
   // console.log(index, state.pageNum)
   loadingTask.promise.then((pdf: any) => {
@@ -311,7 +322,7 @@ function getPdfImage(index: number) {
         viewport,
       });
       canvas.value.toBlob(function (blob) {
-        pdf_img.value = blob
+        pdf_img.value = dataURLtoBlob(canvas.value.toDataURL())
         // console.log(pdf_img.value);
         console.log(canvas.value.toDataURL(), state.pageNum)
       });

+ 8 - 0
src/store/CanvasImg.ts

@@ -0,0 +1,8 @@
+import { defineStore } from 'pinia';
+import { ref } from 'vue'
+
+export const useCanvasImgStore = defineStore('canvas_img', () => {
+  const canvas_img = ref(HTMLCanvasElement)
+
+  return { canvas_img }
+})

+ 1 - 1
src/store/ServerIp.ts

@@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
 import { ref } from 'vue'
 
 export const useServerIpStore = defineStore('server_ip', () => {
-  const server_ip = ref("http://192.168.10.138:80")
+  const server_ip = ref("http://192.168.10.12:80")
   
 
   return { server_ip }