<template>
    <div class="image-editor">
      <div class="editor-header">
        <h1>图片转换工具(TGA)</h1>
        <div class="editor-controls">
          <input type="file" multiple @change="onFilesSelected" accept=".jpg,.jpeg,.png" />
          <button @click="setMode('draw')">涂鸦</button>
          <button @click="setMode('view')">查看</button>
          <select v-model="channel" @change="updateChannelView">
            <option value="rgba">原图</option>
            <option value="r">R 通道</option>
            <option value="g">G 通道</option>
            <option value="b">B 通道</option>
            <option value="a">Alpha 通道</option>
          </select>
          <button @click="downloadTGA" :disabled="!currentImage">导出TGA</button>
          <button @click="downloadAllTGA" :disabled="images.length === 0">批量导出 ZIP</button>
        </div>
      </div>
  
      <div class="thumbnail-list" v-if="images.length > 0">
        <div
          v-for="(img, idx) in images"
          :key="idx"
          class="thumbnail"
          :class="{ active: idx === currentIndex }"
          @click="loadImage(idx)"
        >
          <img :src="img.preview" alt="缩略图" />
        </div>
      </div>
  
      <div class="editor-canvas" v-if="currentImage">
        <canvas ref="canvas" @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove"></canvas>
      </div>
    </div>
    
  </template>
  
  <script>
  import JSZip from "jszip"; 
  export default {
    name: "ImageEditor",
    data() {
      return {
        images: [],
        currentIndex: null,
        channel: "rgba",
        mode: "view",
        drawing: false,
        originalImageData: null,
      };
    },
    computed: {
      currentImage() {
        return this.images[this.currentIndex] || null;
      },
    },
    methods: {
      onFilesSelected(e) {
        const files = Array.from(e.target.files);
        this.images = files.map(file => ({
          file,
          preview: URL.createObjectURL(file),
          name: file.name,
        }));
        if (this.images.length) this.loadImage(0);
      },
      loadImage(index) {
        this.currentIndex = index;
        const img = new Image();
        img.onload = () => {
          const canvas = this.$refs.canvas;
          const ctx = canvas.getContext("2d");
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.drawImage(img, 0, 0);
          this.originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
          this.updateChannelView(); // show selected channel
        };
        img.src = this.images[index].preview;
      },
      setMode(mode) {
        this.mode = mode;
      },
      updateChannelView() {
        if (!this.originalImageData) return;
        const canvas = this.$refs.canvas;
        const ctx = canvas.getContext("2d");
        const imageData = new ImageData(
          new Uint8ClampedArray(this.originalImageData.data),
          this.originalImageData.width,
          this.originalImageData.height
        );
        for (let i = 0; i < imageData.data.length; i += 4) {
          let [r, g, b, a] = imageData.data.slice(i, i + 4);
          switch (this.channel) {
            case "r": g = b = 0; break;
            case "g": r = b = 0; break;
            case "b": r = g = 0; break;
            case "a": r = g = b = a; break;
          }
          imageData.data[i] = r;
          imageData.data[i + 1] = g;
          imageData.data[i + 2] = b;
        }
        ctx.putImageData(imageData, 0, 0);
      },
      onMouseDown() {
        if (this.mode === "draw") this.drawing = true;
      },
      onMouseUp() {
        this.drawing = false;
      },
      onMouseMove(e) {
        if (!this.drawing || this.mode !== "draw") return;
        const canvas = this.$refs.canvas;
        const ctx = canvas.getContext("2d");
        const rect = canvas.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        ctx.fillStyle = "red";
        ctx.beginPath();
        ctx.arc(x, y, 4, 0, Math.PI * 2);
        ctx.fill();
      },
      downloadTGA() {
        const canvas = this.$refs.canvas;
        const ctx = canvas.getContext("2d");
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        const { width, height, data: pixels } = imageData;
  
        const header = new Uint8Array(18);
        header[2] = 2;
        header[12] = width & 0xff;
        header[13] = (width >> 8) & 0xff;
        header[14] = height & 0xff;
        header[15] = (height >> 8) & 0xff;
        header[16] = 24;
  
        const data = new Uint8Array(width * height * 3);
        let offset = 0;
        for (let y = height - 1; y >= 0; y--) {
          for (let x = 0; x < width; x++) {
            const i = (y * width + x) * 4;
            data[offset++] = pixels[i + 2]; // B
            data[offset++] = pixels[i + 1]; // G
            data[offset++] = pixels[i];     // R
          }
        }
  
        const tga = new Uint8Array(header.length + data.length);
        tga.set(header, 0);
        tga.set(data, header.length);
        const blob = new Blob([tga], { type: "application/octet-stream" });
        const a = document.createElement("a");
        a.href = URL.createObjectURL(blob);
        a.download = this.currentImage?.name?.replace(/\.(jpg|jpeg|png)$/i, ".tga") || "output.tga";
        a.click();
        URL.revokeObjectURL(a.href);
      },
  
        async downloadAllTGA() {
        const zip = new JSZip();

        for (let i = 0; i < this.images.length; i++) {
            const imgInfo = this.images[i];
            const img = new Image();
            img.src = imgInfo.preview;

            await new Promise((resolve) => {
            img.onload = () => {
                const canvas = document.createElement("canvas");
                const ctx = canvas.getContext("2d");
                canvas.width = img.width;
                canvas.height = img.height;
                ctx.drawImage(img, 0, 0);

                const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                const tgaBuffer = this.convertImageDataToTGA(imageData);
                const filename = imgInfo.name.replace(/\.(jpg|jpeg|png)$/i, `.tga`);
                zip.file(filename, tgaBuffer);
                resolve();
            };
            });
        }

        const blob = await zip.generateAsync({ type: "blob" });
        const a = document.createElement("a");
        a.href = URL.createObjectURL(blob);
        a.download = "images_export.zip";
        a.click();
        URL.revokeObjectURL(a.href);
        },

        convertImageDataToTGA(imageData) {
        const { width, height, data: pixels } = imageData;
        const header = new Uint8Array(18);
        header[2] = 2;
        header[12] = width & 0xff;
        header[13] = (width >> 8) & 0xff;
        header[14] = height & 0xff;
        header[15] = (height >> 8) & 0xff;
        header[16] = 24;

        const data = new Uint8Array(width * height * 3);
        let offset = 0;
        for (let y = height - 1; y >= 0; y--) {
            for (let x = 0; x < width; x++) {
            const i = (y * width + x) * 4;
            data[offset++] = pixels[i + 2]; // B
            data[offset++] = pixels[i + 1]; // G
            data[offset++] = pixels[i];     // R
            }
        }

        const tga = new Uint8Array(header.length + data.length);
        tga.set(header, 0);
        tga.set(data, header.length);
        return tga;
        },
    },
  };
  </script>
  
  <style scoped>
  .image-editor {
    padding: 20px;
    max-width: 1400px;
    margin: 0 auto;
  }
  
  .editor-header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    margin-bottom: 20px;
  }
  
  .editor-header h1 {
    font-size: 1.5rem;
    color: #333;
    margin: 0;
  }
  
  .editor-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
  }
  
  .editor-controls input,
  .editor-controls button,
  .editor-controls select {
    padding: 8px 12px;
    border: 1px solid #ccc;
    background: #f8f9fa;
    border-radius: 4px;
    font-size: 14px;
    cursor: pointer;
    transition: all 0.2s;
  }
  
  .editor-controls button:hover,
  .editor-controls select:hover {
    background-color: #e0e0e0;
  }
  
  .thumbnail-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 15px;
  }
  
  .thumbnail {
    width: 80px;
    height: 80px;
    border: 2px solid transparent;
    cursor: pointer;
    overflow: hidden;
    border-radius: 6px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  }
  
  .thumbnail.active {
    border-color: #2196f3;
  }
  
  .thumbnail img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  
  .editor-canvas {
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  canvas {
    max-width: 100%;
    border: 1px solid #ccc;
    border-radius: 8px;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
  </style>
  