在图片上进行标注画红色虚线矩形框,可以画多个矩形框多个标注信息;同时可以具有编辑,清除,保存等功能,可以把标注信息红色矩形框相关信息保存起来,可存储在服务器,然后在图片上复现标注矩形框(一)

最近公司项目需要对图片进行标注,然后把标注信息通过接口存到后台,下次进入的时候获取标注信息并展示在前端图片上。功能简单描述一下:三个按钮开始绘制,清除,保存;编辑模式下才能清除和保存;点击某个矩形敲击键盘Backspace可以删除对应的矩形;画一个矩形框后会出现输入框,输入的文字会展示在矩形框上面;非编辑模式清除和保存禁用;矩形信息通过数组存储起来,方便存到服务器,下次进入可以复现标注信息。
话不多说,直接上最初版本的,最基础版本,各位可以根据自己的需求对初始版本进行加工成适合自己项目的功能;初级版本功能有瑕疵,可以根据自己项目进行修改。
可以扩展很多功能例如:
1、按钮区域增加上传图片,底部右侧展示一个图片列表;选中哪个图片就标注哪个图片就给哪个图片画红色虚线矩形边框;这个图片列表也可以来自远程服务器;
2、底部右侧有许多文字描述,选中文字描述,绘制矩形框的时候就把文字描述同时绘制在图片上

样式结构部分

<template>
  <div id="markBox">
    <div class="box-top">
        <button class="btn-item" @click="toggleEditing">{{ isEditing ? "退出编辑" : "开始绘制" }}</button>
        <button class="btn-item" @click="clearRectangles" :disabled="!isEditing">清除</button>
        <button class="btn-item" @click="saveRectangles" :disabled="!isEditing">保存</button>
    </div>
    <div class="box-bottom">
    <input
      v-if="selectedRectIndex !== null"
      type="text"
      v-model="rectangles[selectedRectIndex].description"
      @input="updateDescription"
      placeholder="输入描述文字"
    />
    <canvas
      ref="canvas"
      :width="imageWidth"
      :height="imageHeight"
      @mousedown="onMouseDown"
      @mousemove="drawRect"
      @mouseup="endDrawing"
    ></canvas>
    <img  :src="imageSrc"  alt="Image"  @load="initializeCanvas"  style="display: none"/>
    </div>
  </div>
</template>

JavaScript部分

export default {
  name:'mark',
  data() {
    return {
      imageSrc: require("@/assets/images/1.jpg"), // 确保图片路径正确
      imageWidth: 800, // 根据你的图片宽度调整
      imageHeight: 600, // 根据你的图片高度调整
      isDrawing: false,
      startX: 0,
      startY: 0,
      ctx: null,
      img: new Image(),
      rectangles: [], // 用于存储矩形框信息
      selectedRectIndex: null, // 选中的矩形框索引
      isEditing: false, // 编辑模式状态
    };
  },
  methods: {
    initializeCanvas() {
      const canvas = this.$refs.canvas;
      this.ctx = canvas.getContext("2d");
      this.img.src = this.imageSrc;

      this.img.onload = () => {
        this.ctx.drawImage(this.img, 0, 0, this.imageWidth, this.imageHeight);
        this.redrawRectangles();
      };
    },
    //切换编辑模式
    toggleEditing() {
      this.isEditing = !this.isEditing;
    },
    //鼠标事件
    onMouseDown(event) {
      if (!this.isEditing) return;

      const x = event.offsetX;
      const y = event.offsetY;

      // 检查点击位置是否在某个矩形框内
      this.selectedRectIndex = this.rectangles.findIndex((rect) => {
        return (
          x >= rect.x &&
          x <= rect.x + rect.width &&
          y >= rect.y &&
          y <= rect.y + rect.height
        );
      });

      if (this.selectedRectIndex === -1) {
        // 如果没有选中矩形框,开始绘制新矩形框
        this.isDrawing = true;
        this.startX = x;
        this.startY = y;
      } else {
        // 如果选中矩形框,监听键盘事件
        window.addEventListener("keydown", this.onKeyDown);
      }
    },
    //绘制矩形
    drawRect(event) {
      if (!this.isDrawing) return;

      const canvas = this.$refs.canvas;
      this.ctx.clearRect(0, 0, canvas.width, canvas.height);
      this.ctx.drawImage(this.img, 0, 0, this.imageWidth, this.imageHeight);

      // 绘制已有的矩形框
      this.redrawRectangles();

      // 绘制当前矩形框
      const currentX = event.offsetX;
      const currentY = event.offsetY;
      const width = currentX - this.startX;
      const height = currentY - this.startY;

      this.ctx.strokeStyle = "red";
      this.ctx.setLineDash([5, 3]);
      this.ctx.lineWidth = 2;
      this.ctx.strokeRect(this.startX, this.startY, width, height);
    },
    endDrawing(event) {
      if (!this.isDrawing) return;

      this.isDrawing = false;
      const currentX = event.offsetX;
      const currentY = event.offsetY;
      const width = currentX - this.startX;
      const height = currentY - this.startY;

      // 保存当前矩形框信息
      this.rectangles.push({
        x: this.startX,
        y: this.startY,
        width: width,
        height: height,
        description: "", // 初始化描述文字
      });
    },
    //键盘按键事件删除选中的矩形
    onKeyDown(event) {
      if (event.key === "Backspace" && this.selectedRectIndex !== null) {
        // 删除选中的矩形框
        this.rectangles.splice(this.selectedRectIndex, 1);
        this.selectedRectIndex = null;

        // 重新绘制矩形框
        this.ctx.clearRect(0, 0, this.imageWidth, this.imageHeight);
        this.ctx.drawImage(this.img, 0, 0, this.imageWidth, this.imageHeight);
        this.redrawRectangles();

        // 取消键盘事件监听
        window.removeEventListener("keydown", this.onKeyDown);
      }
    },
    clearRectangles() {
      this.rectangles = [];
      this.ctx.clearRect(0, 0, this.imageWidth, this.imageHeight);
      this.ctx.drawImage(this.img, 0, 0, this.imageWidth, this.imageHeight);
    },
    //保存信息
      saveRectangles() {
      localStorage.setItem("savedRectangles", JSON.stringify(this.rectangles));
      alert("矩形框已保存到 localStorage");
    },
    //复现标注信息于图片
    loadRectangles() {
      const savedRectangles = localStorage.getItem("savedRectangles");
      if (savedRectangles) {
        this.rectangles = JSON.parse(savedRectangles);
        this.redrawRectangles();
      }
    },
    updateDescription() {
      // 重新绘制矩形框,更新描述文字
      this.ctx.clearRect(0, 0, this.imageWidth, this.imageHeight);
      this.ctx.drawImage(this.img, 0, 0, this.imageWidth, this.imageHeight);
      this.redrawRectangles();
    },
    redrawRectangles() {
      this.rectangles.forEach((rect) => {
        this.ctx.strokeStyle = "red";
        this.ctx.setLineDash([5, 3]);
        this.ctx.lineWidth = 2;
        this.ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);

        // 绘制描述文字
        if (rect.description) {
          this.ctx.font = "16px Arial";
          this.ctx.fillStyle = "red";
          this.ctx.fillText(rect.description, rect.x, rect.y - 5);
        }
      });
    },
  },
  mounted() {
    this.loadRectangles(); // 加载保存的矩形框信息
  },
};

css样式部分

#markBox {
  height: 100%;
  width: 100%;
  text-align: center;
  padding-top:20px ;
  .box-top{
    display: flex;
    align-items: center;
    justify-content: center;
    .btn-item{
        height: 30px;
        width: 100px;
        margin: 5px;
    }
    button[disabled]{
        cursor: not-allowed;
    }
  }
  .box-bottom{
    input {
        display: block;
        margin: 10px auto;
    }
    canvas {
        border: 1px solid black;
    }
  }
}
  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值