# 圖片

- Human documentation: [https://docs.univer.ai/zh-TW/guides/sheets/features/images](https://docs.univer.ai/zh-TW/guides/sheets/features/images)

- Agent Markdown: [https://docs.univer.ai/zh-TW/guides/sheets/features/images.md](https://docs.univer.ai/zh-TW/guides/sheets/features/images.md)

- Requested language: `zh-TW`

- Content language: `zh-TW`

- Documentation version: `1.2.0`

- Source: [sheets/features/images.zh-TW.mdx](https://github.com/dream-num/documentation/blob/dev/content/guides/sheets/features/images.zh-TW.mdx)

---

#### Package metadata

```json
{
  "mobile": true,
  "preset": [
    {
      "client": "@univerjs/preset-sheets-drawing",
      "locale": "@univerjs/preset-sheets-drawing/locales/zh-TW",
      "style": "@univerjs/preset-sheets-drawing/lib/index.css"
    }
  ],
  "plugins": [
    {
      "client": "@univerjs/drawing"
    },
    {
      "client": "@univerjs/drawing-ui",
      "locale": "@univerjs/drawing-ui/locale/zh-TW",
      "style": "@univerjs/drawing-ui/lib/index.css"
    },
    {
      "client": "@univerjs/sheets-drawing"
    },
    {
      "client": "@univerjs/sheets-drawing-ui",
      "facade": "@univerjs/sheets-drawing-ui/facade",
      "locale": "@univerjs/sheets-drawing-ui/locale/zh-TW",
      "style": "@univerjs/sheets-drawing-ui/lib/index.css"
    }
  ],
  "server": false
}
```

圖片功能允許使用者在電子表格中插入和管理圖片，以便更好地展示資料和資訊。它支援多種圖片格式和操作，幫助使用者建立更豐富的文件。

目前支援插入的圖片型別為：浮動圖片、單元格圖片

> Interactive example: [Open the playground](/playground/sheets/images)

## 外掛模式

### 安裝

#### npm

```bash
npm install @univerjs/docs-drawing @univerjs/drawing @univerjs/drawing-ui @univerjs/sheets-drawing @univerjs/sheets-drawing-ui
```

#### pnpm

```bash
pnpm add @univerjs/docs-drawing @univerjs/drawing @univerjs/drawing-ui @univerjs/sheets-drawing @univerjs/sheets-drawing-ui
```

#### yarn

```bash
yarn add @univerjs/docs-drawing @univerjs/drawing @univerjs/drawing-ui @univerjs/sheets-drawing @univerjs/sheets-drawing-ui
```

#### bun

```bash
bun add @univerjs/docs-drawing @univerjs/drawing @univerjs/drawing-ui @univerjs/sheets-drawing @univerjs/sheets-drawing-ui
```

### 使用

```typescript
import { IImageIoService, LocaleType, mergeLocales, Univer } from '@univerjs/core'
import { UniverDocsDrawingPlugin } from '@univerjs/docs-drawing' // [!code ++]
import { UniverDrawingPlugin } from '@univerjs/drawing' // [!code ++]
import { UniverDrawingUIPlugin } from '@univerjs/drawing-ui' // [!code ++]
import DrawingUIZhTW from '@univerjs/drawing-ui/locale/zh-TW' // [!code ++]
import { UniverSheetsDrawingPlugin } from '@univerjs/sheets-drawing' // [!code ++]
import { UniverSheetsDrawingUIPlugin } from '@univerjs/sheets-drawing-ui' // [!code ++]
import SheetsDrawingUIZhTW from '@univerjs/sheets-drawing-ui/locale/zh-TW' // [!code ++]

import '@univerjs/drawing-ui/lib/index.css' // [!code ++]
import '@univerjs/sheets-drawing-ui/lib/index.css' // [!code ++]

import '@univerjs/sheets-drawing/facade' // [!code ++]
import '@univerjs/sheets-drawing-ui/facade' // [!code ++]

const univer = new Univer({
  locale: LocaleType.ZH_TW,
  locales: {
    [LocaleType.ZH_TW]: mergeLocales(
      DrawingUIZhTW, // [!code ++]
      SheetsDrawingUIZhTW, // [!code ++]
    ),
  },
})

univer.registerPlugin(UniverDrawingPlugin) // [!code ++]
univer.registerPlugin(UniverDrawingUIPlugin) // [!code ++]
univer.registerPlugin(UniverSheetsDrawingPlugin) // [!code ++]
univer.registerPlugin(UniverSheetsDrawingUIPlugin) // [!code ++]
```

如使用[協同編輯](https://docs.univer.ai/zh-TW/guides/docs/features/collaboration.md)功能，需要新增 `override` 配置：

```typescript
univer.registerPlugin(UniverDrawingPlugin, {
  override: [[IImageIoService, null]], // [!code ++]
  // allowImageSize: 20 * 1024 * 1024, // 設定上傳圖片的最大允許大小為 20MB，非必要
})
```

### 外掛與配置

```typescript
interface IUniverDrawingConfig {
  /**
   * 設定上傳圖片的最大允許大小，以位元組為單位。
   * @default 5 * 1024 * 1024 (5MB)
   */
  allowImageSize?: number
}
```

## 行動裝置支援

先設定[行動版編輯器](https://docs.univer.ai/zh-TW/guides/sheets/getting-started/installation.md#mobile-support)。在本頁外掛模式的初始化程式碼中，將下列桌面版註冊替換為同一套件匯出的行動版外掛，並在**開啟文件前**完成。保留模型外掛、樣式、語言套件與 Facade 匯入，請勿同時註冊兩個版本。

| 套件                            | 桌面版註冊                         | 行動版註冊                               |
| ----------------------------- | ----------------------------- | ----------------------------------- |
| `@univerjs/drawing-ui`        | `UniverDrawingUIPlugin`       | `UniverDrawingMobileUIPlugin`       |
| `@univerjs/sheets-drawing-ui` | `UniverSheetsDrawingUIPlugin` | `UniverSheetsDrawingMobileUIPlugin` |

## 預設模式

### 安裝

#### npm

```bash
npm install @univerjs/preset-sheets-drawing
```

#### pnpm

```bash
pnpm add @univerjs/preset-sheets-drawing
```

#### yarn

```bash
yarn add @univerjs/preset-sheets-drawing
```

#### bun

```bash
bun add @univerjs/preset-sheets-drawing
```

### 使用

```typescript
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'
import UniverPresetSheetsCoreZhTW from '@univerjs/preset-sheets-core/locales/zh-TW'
import { UniverSheetsDrawingPreset } from '@univerjs/preset-sheets-drawing' // [!code ++]
import UniverPresetSheetsDrawingZhTW from '@univerjs/preset-sheets-drawing/locales/zh-TW' // [!code ++]
import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'

import '@univerjs/preset-sheets-core/lib/index.css'
import '@univerjs/preset-sheets-drawing/lib/index.css' // [!code ++]

const { univerAPI } = createUniver({
  locale: LocaleType.ZH_TW,
  locales: {
    [LocaleType.ZH_TW]: mergeLocales(
      UniverPresetSheetsCoreZhTW,
      UniverPresetSheetsDrawingZhTW, // [!code ++]
    ),
  },
  presets: [
    UniverSheetsCorePreset(),
    UniverSheetsDrawingPreset(), // [!code ++]
  ],
})
```

如使用[協同編輯](https://docs.univer.ai/zh-TW/guides/sheets/features/collaboration.md)功能，請確保在 `UniverSheetsDrawingPreset` 中傳入 `collaboration: true` 選項。

```typescript
UniverSheetsDrawingPreset({
  collaboration: true, // [!code ++]
})
```

### 預設與配置

```typescript
interface IUniverSheetsDrawingPresetConfig {
  /**
   * 是否使用了協同編輯功能。
   * @default false
   */
  collaboration?: boolean
  /**
   * 設定上傳圖片的最大允許大小，以位元組為單位。
   * @default 5 * 1024 * 1024 (5MB)
   */
  allowImageSize?: number
}
```

## Facade API

完整 Facade API 型別定義，請檢視 [FacadeAPI](https://docs.univer.ai/zh-TW/reference/facade/univer.md)。

### 引入

> [!INFO: 外掛模式提示]
> 僅外掛模式需要手動引入 Facade 套件。預設模式已內建對應的 Facade 套件，無需額外引入。

```typescript
import '@univerjs/sheets-drawing/facade'
import '@univerjs/sheets-drawing-ui/facade'
```

### 新增浮動 DOM

`FWorksheet.addFloatDomToPosition(layer)` 方法可以新增一個浮動的 DOM 元素到指定位置。

```tsx
const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet()

// 你應該在合適的時機註冊元件（例如 Univer 載入完成時）
// 這是一個 React 元件。對於 Vue3 元件，第三個參數應該是 `{ framework: 'vue3' }`
univerAPI.registerComponent(
  'myFloatDom',
  ({ data }) => (
    <div style={{ width: '100%', height: '100%', background: '#fff', border: '1px solid #ccc', boxSizing: 'border-box' }}>
      popup content:
      {' '}
      {data?.label}
    </div>
  ),
)

// 新增浮動 DOM
// 如果 disposable 為 null，則浮動 DOM 新增失敗
const disposable = fWorksheet.addFloatDomToPosition({
  componentKey: 'myFloatDom',
  initPosition: {
    startX: 100,
    endX: 300,
    startY: 100,
    endY: 200,
  },

  // 元件資料
  data: {
    label: 'hahah',
  },
})

// 2 秒後移除浮動 DOM
setTimeout(() => {
  disposable?.dispose()
}, 2000)
```

`FWorksheet.addFloatDomToRange(range, layer, domLayout)` 方法可以新增一個浮動的 DOM 元素到指定範圍。

```tsx
const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet()

// 註冊一個範圍載入元件
function RangeLoading() {
  const divStyle = {
    width: '100%',
    height: '100%',
    backgroundColor: '#fff',
    border: '1px solid #ccc',
    boxSizing: 'border-box' as const,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    textAlign: 'center' as const,
    transformOrigin: 'top left',
  }

  return (
    <div style={divStyle}>
      Loading...
    </div>
  )
}
univerAPI.registerComponent('RangeLoading', RangeLoading)

// 新增範圍載入元件覆蓋範圍 A1:C3
const fRange = fWorksheet.getRange('A1:C3')
const disposable = fWorksheet.addFloatDomToRange(fRange, { componentKey: 'RangeLoading' }, {}, 'myRangeLoading')

// 2 秒後移除浮動 DOM
setTimeout(() => {
  disposable?.dispose()
}, 2000)

// 另外一個示例 -------------------
// 註冊一個浮動按鈕元件
function FloatButton() {
  const divStyle = {
    width: '100px',
    height: '30px',
    backgroundColor: '#fff',
    border: '1px solid #ccc',
    boxSizing: 'border-box' as const,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    textAlign: 'center' as const,
    cursor: 'pointer',
  }

  const clickHandler = () => {
    console.warn('click')
  }

  return (
    <div style={divStyle} onClick={clickHandler}>
      FloatButton
    </div>
  )
}
univerAPI.registerComponent('FloatButton', FloatButton)

// 新增浮動按鈕到範圍 A5:C7，位置從 A5 單元格開始，寬度為 100px，高度為 30px，邊距為範圍寬度和高度的 100%
const fRange2 = fWorksheet.getRange('A5:C7')
const disposable2 = fWorksheet.addFloatDomToRange(
  fRange2,
  {
    componentKey: 'FloatButton',
  },
  {
    width: 100,
    height: 30,
    marginX: '100%', // 邊距百分比到範圍寬度，或畫素
    marginY: '100%',
  },
  'myFloatButton',
)
```

`FWorksheet.addFloatDomToColumnHeader(column, layer, domPos)` 方法可以新增一個浮動的 DOM 元素到指定列頭。

```tsx
const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet()

// 註冊一個浮動按鈕元件
function FloatButton() {
  const divStyle = {
    width: '100px',
    height: '30px',
    backgroundColor: '#fff',
    border: '1px solid #ccc',
    boxSizing: 'border-box' as const,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    textAlign: 'center' as const,
    cursor: 'pointer',
  }

  const clickHandler = () => {
    console.warn('click')
  }

  return (
    <div style={divStyle} onClick={clickHandler}>
      FloatButton
    </div>
  )
}
univerAPI.registerComponent('FloatButton', FloatButton)

// 新增浮動按鈕到列 D 頭部，位置為右對齊，寬度為 100px，高度為 30px，邊距為 0
const disposable = fWorksheet.addFloatDomToColumnHeader(
  3,
  {
    componentKey: 'FloatButton',
    allowTransform: false,
  },
  {
    width: 100,
    height: 30,
    marginX: 0,
    marginY: 0,
    horizonOffsetAlign: 'right',
  },
  'myFloatButton',
)

// 2 秒後移除浮動按鈕
setTimeout(() => {
  disposable?.dispose()
}, 2000)
```

### 插入浮動圖片

[`FWorksheet.newOverGridImage()`](https://docs.univer.ai/zh-TW/reference/facade/worksheet.md#newovergridimage) 建立一個浮動圖片構建器，返回一個 `FOverGridImageBuilder` 例項，可以透過鏈式呼叫生成 `ISheetImage` 物件用於插入浮動圖片。

以下是 [`FOverGridImageBuilder`](https://docs.univer.ai/zh-TW/reference/facade/over-grid-image-builder.md) 上的一些成員方法：

| 方法              | 描述                                    |
| --------------- | ------------------------------------- |
| buildAsync      | 構建 `ISheetImage` 物件用於插入浮動圖片           |
| setSource       | 設定 image 的來源                          |
| setColumn       | 設定 image 的水平方向位置                      |
| setRow          | 設定 image 的垂直方向位置                      |
| setColumnOffset | 設定 image 的水平方向偏移                      |
| setRowOffset    | 設定 image 的垂直方向偏移                      |
| setWidth        | 設定 image 的寬度                          |
| setHeight       | 設定 image 的高度                          |
| setAnchorType   | 設定 image 的錨點型別，是否隨單元格位置和大小變化          |
| setCropTop      | 設定 image 的裁剪區域，定義頂部邊緣，從而顯示你想要的影象的特定部分 |
| setCropLeft     | 設定 image 的裁剪區域，定義左邊緣，從而顯示你想要的影象的特定部分  |
| setCropBottom   | 設定 image 的裁剪區域，定義底部邊緣，從而顯示你想要的影象的特定部分 |
| setCropRight    | 設定 image 的裁剪區域，定義右邊緣，從而顯示你想要的影象的特定部分  |
| setRotate       | 設定 image 的旋轉角度                        |

```typescript
// 建立一個新的圖片構建器並設定圖片來源。
// 然後構建 `ISheetImage` 並插入到工作表中，位置從 F6 單元格開始，寬度為 500px，高度為 300px
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const image = await fWorksheet.newOverGridImage()
  .setSource('https://avatars.githubusercontent.com/u/61444807?s=48&v=4', univerAPI.Enum.ImageSourceType.URL)
  .setColumn(5)
  .setRow(5)
  .setWidth(500)
  .setHeight(300)
  .buildAsync()
fWorksheet.insertImages([image])
```

亦可以透過 `FWorksheet.insertImage(url, column, row, offsetX, offsetY)` 方法插入圖片。

```typescript
// 插入一個圖片到工作表，位置為 F6，偏移為 10px
const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet()
const result = await fWorksheet.insertImage('https://avatars.githubusercontent.com/u/61444807?s=48&v=4', 5, 5, 10, 10)
```

### 獲取浮動圖片

`FWorksheet.getImages()` 方法可以獲取工作表中的所有浮動圖片，返回一個 [`FOverGridImage[]`](https://docs.univer.ai/zh-TW/reference/facade/chart.md) 例項陣列。

```typescript
const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet()
const images = fWorksheet.getImages()
images.forEach((image) => {
  image.getId()
})
```

亦可以透過 `FWorksheet.getImageById(id)` 方法獲取指定 id 的浮動圖片。

### 更新浮動圖片

`FWorksheet.updateImages(sheetImages)` 方法可以更新浮動圖片的位置和大小等屬性。

```typescript
// 建立一個新的圖片構建器並設定圖片來源。
// 然後構建 `ISheetImage` 並插入到工作表中，位置從 F6 單元格開始，寬度為 500px，高度為 300px
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const image = await fWorksheet.newOverGridImage()
  .setSource('https://avatars.githubusercontent.com/u/61444807?s=48&v=4', univerAPI.Enum.ImageSourceType.URL)
  .setColumn(5)
  .setRow(5)
  .setWidth(500)
  .setHeight(300)
  .buildAsync()
fWorksheet.insertImages([image])

// 4 秒後更新圖片寬度為 100px，高度為 50px
setTimeout(async () => {
  const imageBuilder = fWorksheet.getImageById(image.drawingId).toBuilder()
  const newImage = await imageBuilder.setWidth(100).setHeight(50).buildAsync()
  fWorksheet.updateImages([newImage])
}, 4000)
```

### 刪除浮動圖片

`FWorksheet.deleteImages(sheetImages)` 方法可以刪除浮動圖片。

```typescript
const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet()
const image = fWorksheet.getImages()[0]

// 刪除工作表中的第一個圖片
fWorksheet.deleteImages([image])
```

### 插入單元格圖片

`FRange.insertCellImageAsync(file)` 方法可以插入單元格圖片。

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// 在 A10 單元格插入一個圖片
const fRange = fWorksheet.getRange('A10')
const result = await fRange.insertCellImageAsync('https://avatars.githubusercontent.com/u/61444807?s=48&v=4')
```

## 工作表背景圖

工作表另支援一張平鋪背景圖，繪製於儲存格下方，獨立於浮動與儲存格圖片，儲存在 `IWorksheetData.backgroundImage`。繪圖預設已包含此功能；外掛模式需要 `@univerjs/sheets-drawing` 與其 Facade，並由繪圖 UI 提供渲染及上傳入口。

```ts
import '@univerjs/sheets-drawing/facade'

const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet()
if (!sheet) throw new Error('No active worksheet')

sheet.setBackgroundImage('https://example.com/background.png')
console.log(sheet.getBackgroundImage())
sheet.deleteBackgroundImage()
```

`setBackgroundImage()` 預設使用 `ImageSourceType.URL` 並取代原背景；`deleteBackgroundImage()` 移除背景。兩者透過命令支援復原與重做。UI 上傳使用設定的圖片 I/O 服務。背景僅供螢幕顯示，不參與列印。

## 圖片不透明度

浮動圖片支援整體不透明度。`setOpacity()` 接受 `0`（完全透明）到 `1`（完全不透明）之間的有限數值，預設值為 `1`，無效值會拋出 `RangeError`。可在建立前透過 `FOverGridImageBuilder` 設定，也可透過現有的 `FOverGridImage` 修改；兩者皆提供 `getOpacity()`。圖片屬性面板也提供透明度控制項。

```ts
const sheet = univerAPI.getActiveWorkbook()?.getActiveSheet()
const image = sheet?.getImages()[0]
if (image) {
  image.setOpacity(0.5)
  console.log(image.getOpacity())
}
```

## 圖片尺寸與錨點

透過內建檔案選擇器插入圖片時，保留原始長寬比，必要時縮小至 500 × 500 像素以內，不放大小圖。這是顯示尺寸，與限制上傳位元組數的 `allowImageSize` 不同。透過 Facade 插入時可自行指定尺寸。

使用 `SheetDrawingAnchorType.Position` 隨儲存格移動但保持尺寸，`Both` 隨錨定範圍移動並縮放，`None` 固定位置與尺寸。隱藏與顯示列欄會保留錨點定義：隨範圍縮放的圖片可能暫時收縮，重新顯示後恢復。請勿將隱藏列欄產生的暫時幾何尺寸回寫為錨點。
