【sgUploadTileImage】自定义组件:浏览器端生成瓦片图,并转换为File文件序列上传瓦片图

特性:

  1. 支持自定义瓦片图尺寸
  2. 支持显示预览最小尺寸100x100像素大小,切换为实际切割尺寸
  3. 支持获取切割后的文件Files数组

 sgUploadTileImage源码

<template>
    <div :class="$options.name">
        <div class="sg-ctrl">
            <div class="px">
                <span>瓦片图边长</span>
                <el-input-number style="width: 130px;" v-model.trim="tileSize" :precision="0" :step="100" :min="100"
                    :max="500" :controls-position="`left`" /><span>像素</span>

            </div>
            <div class="btns">
                <el-switch v-model="view100px" inactive-color="#ccc" active-color="#409EFF" inactive-text=""
                    active-text="固定100宽高显示预览" :inactive-value="false" :active-value="true" />

                <el-button :loading="loading" type="primary" icon="el-icon-upload2"
                    @click="d => $refs.sgUpload.triggerUploadFile()">上传大图</el-button>

                <el-button type="success" icon="el-icon-s-promotion" @click="uploadTiles"
                    v-if="tiles.length">上传瓦片图</el-button>
            </div>

            <div class="tip-text">
                <p>{{ loadingText }}</p>
            </div>
        </div>
        <div class="sg-tiles" :view100px="view100px">
            <div :style="{ width: `${(view100px ? 100 : tileSize) * colCount}px` }" v-if="tiles.length">
                <img v-for="(a, i) in tiles" :key="i" :src="a" :width="view100px ? 100 : tileSize"
                    :height="view100px ? 100 : tileSize">
            </div>
            <el-alert v-else style="width: 555px;height: 50px;margin-top: 10px;" :closable="true" :close-text="``"
                :description="``" :effect="'light'" :show-icon="false" :title="`温馨提示:请上传超大图片文件(大于100M)`" :type="'success'">
            </el-alert>
        </div>

        <!-- 上传组件 -->
        <sgUpload :disabledWhenShowSels="['.v-modal']" drag ref="sgUpload" :data="{
            maxSize: 1000,//最大支持上传图片文件1G
            accept: `*`,
        }" @resultBase64Image="resultBase64Image" @success="uploadSuccess" @error="uploadError" hideUploadTray
            @showFakeLoading="showFakeLoading" />
    </div>
</template>
    
<script>
import sgUpload from "@/vue/components/admin/sgUpload";
export default {
    name: 'sgUploadTileImage',
    components: {
        sgUpload,
    },
    data() {
        return {
            loading: false,
            view100px: true,
            loadingText: '',
            colCount: 0,
            rowCount: 0,
            src: '',
            fileFormat: '',
            tileSize: 500,
            tiles: [],//瓦片图数组
        }
    },
    watch: {
        tileSize(d) {
            this.tiles = [];
            this.loading = false;
            this.loadingText = '';
        },
    },
    methods: {
        uploadTiles(d) {
            let r = [];
            let format = this.fileFormat.toLocaleLowerCase().split('/')[1];
            this.tiles.forEach((base64, i) => {
                let fileName = `${i}.${format}`;
                let file = this.$g.image.getFileFromBase64(base64, fileName);
                r.push(file);
            });
            this.$emit(`uploadTiles`, r);
        },
        getRowColIndex(itemIndex = 0, colCount = 3) {
            //必选参数:itemIndex是当前元素的索引值,从0开始计算(如果是从1开始,则需将传入值-1,即itemIndex--)
            //必选参数:colCount是每一行显示多少个元素
            return {
                colIndex: itemIndex % colCount,//计算列索引(从0开始)
                rowIndex: Math.floor(itemIndex / colCount),//计算行索引(从0开始)        
            }
        },
        // 获取瓦片图
        getTiles({ img, format = "image/png", cb } = {}) {
            this.fileFormat = format;
            let canvas = document.createElement('canvas'), ctx = canvas.getContext('2d');
            canvas.width = this.tileSize, canvas.height = this.tileSize;

            let tiles = [];
            let colCount = Math.ceil(img.width / this.tileSize);//列数量
            let rowCount = Math.ceil(img.height / this.tileSize);//行数量
            let len = colCount * rowCount;//瓦片图总数
            this.loadingText = `已经为您生成${len}个瓦片图(尺寸:${this.tileSize}像素×${this.tileSize}像素)。`;
            this.colCount = colCount;
            this.rowCount = rowCount;
            for (let i = 0; i < len; i++) {
                let { colIndex, rowIndex } = this.getRowColIndex(i, colCount);
                let drawImageWidth = colIndex === colCount - 1 ? (img.width % this.tileSize) : this.tileSize;
                let drawImageHeight = rowIndex === rowCount - 1 ? (img.height % this.tileSize) : this.tileSize;
                canvas.width = drawImageWidth, canvas.height = drawImageHeight;
                ctx.drawImage(img,
                    this.tileSize * colIndex, this.tileSize * rowIndex,//绘制图片起始点的横纵坐标
                    drawImageWidth, drawImageHeight,//切割图片的宽高
                    0, 0,//绘制canvas的起始点横纵坐标
                    drawImageWidth, drawImageHeight);//绘制canvas的宽高
                tiles.push(canvas.toDataURL(format));
                if (i === len - 1) {
                    let scale = 100 / this.tileSize;
                    this.$el.style.setProperty("--last-img-width", `${drawImageWidth}px`); //js往css传递局部参数
                    this.$el.style.setProperty("--last-img-height", `${drawImageHeight}px`); //js往css传递局部参数
                    this.$el.style.setProperty("--last-img-width-view100px", `${drawImageWidth * scale}px`); //js往css传递局部参数
                    this.$el.style.setProperty("--last-img-height-view100px", `${drawImageHeight * scale}px`); //js往css传递局部参数
                }
            }
            cb && cb(tiles);
        },
        /* 将图片(路径)转换为Base64 */
        resultBase64Image(url, f) {
            this.tiles = [];
            this.loadingText = '正在为您分解图片,请稍候!';
            let img = new Image(); img.crossOrigin = 'Anonymous';
            img.onload = d => {
                this.getTiles({
                    img,
                    cb: tiles => {
                        this.tiles = tiles;
                        this.loading = false;
                    }
                })
            }
            img.src = url;
        },
        uploadSuccess(d, f) { }, uploadError(d, f) { },
        showFakeLoading(d) {
            this.loadingText = '图片上传中,请稍候!';
            this.loading = true;
        },
    }
};
</script>
<style lang="scss" scoped>
.sgUploadTileImage {
    display: flex;
    flex-direction: column;

    .sg-ctrl {
        display: flex;
        flex-shrink: 0;
        flex-wrap: nowrap;
        align-items: center;

        .px {
            margin-right: 10px;

            span {
                margin-left: 5px;
            }
        }

        .tip-text {
            margin-left: 10px;
            display: flex;
            align-items: center;
        }
    }

    .sg-tiles {
        overflow: auto;
        // max-height: calc(100vh - 100px);
        flex-grow: 1;

        div {
            display: flex;
            flex-wrap: wrap;

            img {
                box-sizing: border-box;
                border: 0.5px solid white;
                object-position: top left;
                object-fit: scale-down;

                &:last-of-type {
                    border-right: none;
                    border-bottom: none;
                    object-fit: fill;
                    width: var(--last-img-width);
                    height: var(--last-img-height);
                }
            }
        }

        &[view100px] {
            div {
                img {

                    &:last-of-type {
                        width: var(--last-img-width-view100px);
                        height: var(--last-img-height-view100px);
                    }
                }
            }
        }
    }
}
</style>

用例

<template>
  <div>
    <el-button type="primary" @click="dialogVisible = true">上传超大文件</el-button>
    <el-dialog :custom-class="'sgUploadTileImage-el-dialog'" :append-to-body="true" :close-on-click-modal="true"
      :close-on-press-escape="true" :destroy-on-close="true" :fullscreen="true" :show-close="true" :title="`瓦片图上传`"
      :width="'100%'" :visible.sync="dialogVisible">
      <div style="width: 100%;height: 100%;">
        <sgUploadTileImage @uploadTiles="uploadTiles" />
      </div>
    </el-dialog>
  </div>
</template>
<script>
import sgUploadTileImage from "@/vue/components/admin/sgUploadTileImage";
export default {
  components: { sgUploadTileImage, },
  data() {
    return { dialogVisible: false, }
  },
  methods: {
    uploadTiles(files) {
      console.log(`瓦片图files:`, files);
    },
  },
};
</script> 
<style lang="scss">
.sgUploadTileImage-el-dialog {
  .el-dialog__body {
    padding: 0;

    .sg-tiles {
      max-height: calc(100vh - 100px);
    }
  }
}
</style>

文章来源地址https://uudwc.com/A/JwOAG

原文地址:https://blog.csdn.net/qq_37860634/article/details/133272543

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年10月06日 17:43
Spring Boot进阶(67):高性能缓存!使用Spring Boot轻松集成Memcached。
下一篇 2023年10月06日 18:43