跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
TypeScript大前端

HarmonyOS Image Kit 单图、多图、GIF 编码全场景实践

综述由AI生成HarmonyOS Image Kit 提供了完整的图片编码能力,涵盖单图、多图及 GIF 序列场景。 ImagePacker 工具与 PackingOption 配置,通过封装工具类实现 PixelMap 和 Picture 对象到 JPEG、HEIF、PNG 等格式的转换。内容包含内存流与文件写入两种输出方式,并针对 HDR 支持、API 版本校验、资源释放及图库保存提供避坑指南与最佳实践,帮助开发者构建高效的图片处理闭环。

神经兮兮发布于 2026/3/24更新于 2026/5/97 浏览

华为 Image Kit 提供的 ImagePacker 工具,封装了全套编码能力:支持单图/多图/序列图(GIF)编码,兼容 HDR 格式,还能灵活控制压缩质量。本文将聚焦编码全场景,结合实际开发需求,拆解每个场景的实现步骤、代码示例与避坑要点,让你快速掌握编码技巧。

一、编码基础:先搞懂 ImagePacker 与核心配置

在动手编码前,先明确两个核心要素:编码工具 ImagePacker 和配置参数 PackingOption——它们是所有编码操作的基础,选对配置才能避免「编码成功但文件无法打开」的坑。

1.1 核心工具与支持格式

编码的核心工具是 image.createImagePacker() 创建的实例,它提供了 4 类核心接口,覆盖不同场景:

接口名称功能描述支持的输入对象支持的输出格式最低 API 版本
packToData编码为 ArrayBuffer(内存流)PixelMap、ImageSourceJPEG、WebP、PNG、HEIF-
packToFile直接编码为文件(写入磁盘)PixelMap、ImageSource、PictureJPEG、WebP、PNG、HEIF(Picture 仅支持 JPEG/HEIF)-
packToDataFromPixelmapSequence多 PixelMap 序列编码为 GIF 内存流PixelMap 数组GIF18
packToFileFromPixelmapSequence多 PixelMap 序列编码为 GIF 文件PixelMap 数组GIF18
1.2 关键配置:PackingOption 解析

编码配置 PackingOption 决定了输出文件的格式、质量、动态范围等核心属性,不同场景的配置差异较大,整理成表格方便快速查阅:

配置项作用描述可选值/注意事项适用场景
format输出格式(遵循 MIME 标准)image/jpeg(.jpg/.jpeg)、image/webp(.webp)、image/png(.png)、image/heif(.heif)、image/gif(.gif)所有编码场景
quality压缩质量(仅有损格式支持)0-100,数值越高质量越好、文件越大;PNG 是无损格式,此参数无效JPEG、WebP 编码
desiredDynamicRange动态范围(HDR 编码控制)AUTO(自动识别)、SDR、HDR;仅 JPEG 格式支持 HDR 编码HDR 图片编码
needsPackProperties是否保留多图元数据true/false;仅 Picture 多图编码时需要配置多图(Picture)编码

核心提醒:格式对应关系必须正确!比如 format: 'image/jpeg' 对应文件扩展名 .jpg 或 .jpeg,如果扩展名写成 .png,会导致文件无法正常打开。

用一张流程图理清编码的核心流程:

PixelMap/ImageSource -> 单图编码
Picture -> 多图编码
PixelMap 数组(API18+) -> GIF 序列编码
↓
配置 PackingOption
↓
ImagePacker 接口
↓
ArrayBuffer(内存流) / 文件(磁盘存储)
↓
保存到图库/网络传输 / 直接使用/分享

二、核心场景实战:编码功能手把手实现

下面按「单图→多图→GIF 序列」的顺序,拆解每个场景的实战代码,所有示例均基于官方 API,可直接复用。

2.1 单图编码:最常用场景(PixelMap/ImageSource)

单图编码是开发中最频繁的需求,比如将裁剪后的头像保存为 JPEG,将 HDR 图片压缩为 HEIF 格式。支持两种输入对象(PixelMap/ImageSource)和两种输出方式(ArrayBuffer/文件)。

2.1.1 工具类封装(统一编码逻辑)

先封装一个编码工具类,避免重复代码,支持不同输入对象和输出方式:

// 图片编码工具类(基于 ImagePacker)
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { Context } from '@kit.AbilityKit';

export class ImageEncoder {
  /**
   * 通用编码配置生成器
   * @param format 目标格式(MIME 标准)
   * @param quality 压缩质量(0-100,有损格式有效)
   * @param isHdr 是否需要 HDR 编码(仅 JPEG 支持)
   * @returns PackingOption
   */
  private static getPackingOption(
    format: string,
    quality: number = 90,
    isHdr: boolean = false
  ): image.PackingOption {
    const option: image.PackingOption = {
      format,
      quality: Math.max(0, Math.min(100, quality)), // 限制质量在 0-100 之间
    };
    // HDR 编码配置:仅 JPEG 格式支持,需资源本身是 HDR 且设备支持
    if (isHdr && format === 'image/jpeg') {
      option.desiredDynamicRange = image.PackingDynamicRange.AUTO;
    }
    return option;
  }

  /**
   * PixelMap 编码为 ArrayBuffer(内存流)
   * @param pixelMap 输入位图对象
   * @param format 目标格式
   * @param quality 压缩质量
   * @param isHdr 是否 HDR 编码
   * @returns 编码后的 ArrayBuffer
   */
  static async encodePixelMapToBuffer(
    pixelMap: image.PixelMap,
    format: string = 'image/jpeg',
    quality: number = 90,
    isHdr: boolean = false
  ): Promise<ArrayBuffer | undefined> {
    const imagePacker = image.createImagePacker();
    const packOpts = this.getPackingOption(format, quality, isHdr);
    try {
      const data = await imagePacker.packToData(pixelMap, packOpts);
      console.log(`PixelMap 编码为${format}成功,数据长度:${data.byteLength}字节`);
      return data;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`PixelMap 编码失败:code=${err.code}, message=${err.message}`);
      return undefined;
    }
  }

  /**
   * PixelMap 编码为文件
   * @param context 应用上下文
   * @param pixelMap 输入位图对象
   * @param fileName 输出文件名(含扩展名)
   * @param format 目标格式
   * @param quality 压缩质量
   * @param isHdr 是否 HDR 编码
   * @returns 输出文件路径
   */
  static async encodePixelMapToFile(
    context: Context,
    pixelMap: image.PixelMap,
    fileName: string,
    format: string = 'image/jpeg',
    quality: number = 90,
    isHdr: boolean = false
  ): Promise<string | undefined> {
    const imagePacker = image.createImagePacker();
    const packOpts = this.getPackingOption(format, quality, isHdr);
    // 输出路径:应用沙箱缓存目录(无需额外权限)
    const outputPath = `${context.cacheDir}/${fileName}`;
    try {
      // 打开文件:创建 + 读写模式
      const file = fs.openSync(outputPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      // 编码并写入文件
      await imagePacker.packToFile(pixelMap, file.fd, packOpts);
      console.log(`PixelMap 编码为文件成功:${outputPath}`);
      // 关闭文件句柄
      file.closeSync();
      return outputPath;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`PixelMap 编码为文件失败:code=${err.code}, message=${err.message}`);
      return undefined;
    }
  }

  /**
   * ImageSource 编码为文件(跳过 PixelMap,直接编码原文件)
   * @param context 应用上下文
   * @param imageSource 图片源对象
   * @param fileName 输出文件名
   * @param format 目标格式
   * @param quality 压缩质量
   * @returns 输出文件路径
   */
  static async encodeImageSourceToFile(
    context: Context,
    imageSource: image.ImageSource,
    fileName: string,
    format: string = 'image/png',
    quality: number = 90
  ): Promise<string | undefined> {
    const imagePacker = image.createImagePacker();
    const packOpts = this.getPackingOption(format, quality);
    const outputPath = `${context.cacheDir}/${fileName}`;
    try {
      const file = fs.openSync(outputPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      await imagePacker.packToFile(imageSource, file.fd, packOpts);
      file.closeSync();
      console.log(`ImageSource 编码为文件成功:${outputPath}`);
      return outputPath;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`ImageSource 编码失败:code=${err.code}, message=${err.message}`);
      return undefined;
    }
  }
}
2.1.2 调用示例(结合解码/编辑逻辑)
// 完整流程:解码→编辑→编码保存
async function imageProcessFullFlow(context: Context, inputFileName: string) {
  // 1. 解码逻辑:获取 PixelMap
  const pixelMap = await decodeToPixelMap(context, inputFileName);
  if (!pixelMap) return;

  // 2. 编辑逻辑:裁剪 + 缩放
  const cropRegion = { x: 0, y: 0, size: { width: 500, height: 500 } };
  const croppedMap = await ImageEditor.cropImage(pixelMap, cropRegion);
  if (!croppedMap) {
    pixelMap.release();
    return;
  }

  // 3. 编码保存为 JPEG 文件(质量 95,非 HDR)
  const outputPath = await ImageEncoder.encodePixelMapToFile(
    context,
    croppedMap,
    'edited_avatar.jpg',
    'image/jpeg',
    95,
    false
  );

  // 4. 编码为 PNG 内存流(无损格式,用于网络上传)
  const pngBuffer = await ImageEncoder.encodePixelMapToBuffer(croppedMap, 'image/png');
  if (pngBuffer) {
    // 此处可调用网络接口上传
    console.log(`PNG 内存流准备完成,可用于上传:${pngBuffer.byteLength}字节`);
  }

  // 5. 释放资源(避免内存泄漏)
  pixelMap.release();
  croppedMap.release();
}
2.2 多图编码:Picture 对象专属场景

多图编码针对 Picture 对象(含主图、辅助图、元数据),仅支持编码为 JPEG 或 HEIF 格式,适合 HDR 合成、多图关联数据存储等场景。

// 多图编码工具函数(Picture → 文件/ArrayBuffer)
export class PictureEncoder {
  /**
   * Picture 编码为文件
   * @param context 应用上下文
   * @param picture 多图对象
   * @param fileName 输出文件名
   * @param format 目标格式(仅支持 image/jpeg、image/heif)
   * @param quality 压缩质量
   * @returns 输出文件路径
   */
  static async encodeToFile(
    context: Context,
    picture: image.Picture,
    fileName: string,
    format: 'image/jpeg' | 'image/heif' = 'image/jpeg',
    quality: number = 90
  ): Promise<string | undefined> {
    // 校验格式(多图仅支持 JPEG/HEIF)
    if (!['image/jpeg', 'image/heif'].includes(format)) {
      console.error('多图编码仅支持 image/jpeg 和 image/heif 格式');
      return undefined;
    }
    const imagePacker = image.createImagePacker();
    const packOpts: image.PackingOption = {
      format,
      quality,
      desiredDynamicRange: image.PackingDynamicRange.AUTO,
      needsPackProperties: true, // 保留多图元数据,必须设置为 true
    };
    const outputPath = `${context.cacheDir}/${fileName}`;
    try {
      const file = fs.openSync(outputPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      await imagePacker.packToFile(picture, file.fd, packOpts);
      file.closeSync();
      console.log(`Picture 多图编码成功:${outputPath}`);
      return outputPath;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`Picture 编码失败:code=${err.code}, message=${err.message}`);
      return undefined;
    }
  }

  /**
   * Picture 编码为 ArrayBuffer
   * @param picture 多图对象
   * @param format 目标格式
   * @param quality 压缩质量
   * @returns 编码后的 ArrayBuffer
   */
  static async encodeToBuffer(
    picture: image.Picture,
    format: 'image/jpeg' | 'image/heif' = 'image/heif',
    quality: number = 90
  ): Promise<ArrayBuffer | undefined> {
    if (!['image/jpeg', 'image/heif'].includes(format)) {
      console.error('多图编码仅支持 image/jpeg 和 image/heif 格式');
      return undefined;
    }
    const imagePacker = image.createImagePacker();
    const packOpts: image.PackingOption = {
      format,
      quality,
      needsPackProperties: true,
    };
    try {
      const data = await imagePacker.packing(picture, packOpts); // 多图编码用 packing 接口
      console.log(`Picture 编码为内存流成功:${data.byteLength}字节`);
      return data;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`Picture 编码为 Buffer 失败:${err.message}`);
      return undefined;
    }
  }
}

// 调用示例:多图解码后直接编码
async function pictureEncodeDemo(context: Context, inputFileName: string) {
  // 1. 多图解码逻辑:获取 Picture 对象
  const picture = await decodeToPicture(context, inputFileName);
  if (!picture) return;

  // 2. 编码为 HEIF 格式文件(保留多图元数据)
  const heifPath = await PictureEncoder.encodeToFile(
    context,
    picture,
    'multi_image.heif',
    'image/heif',
    95
  );

  // 3. 释放 Picture 资源
  picture.release();
}
2.3 GIF 序列编码:API18+ 新增功能

从 API version 18 开始,Image Kit 支持将多个 PixelMap 序列编码为 GIF 格式(动态图),适合短视频帧、动画序列等场景。

// GIF 序列编码工具(API18+)
export class GifEncoder {
  /**
   * 多个 PixelMap 编码为 GIF 文件
   * @param context 应用上下文
   * @param pixelMaps PixelMap 数组(按帧顺序排列)
   * @param fileName 输出文件名(扩展名.gif)
   * @param quality 压缩质量(0-100)
   * @returns 输出文件路径
   */
  static async encodeToGifFile(
    context: Context,
    pixelMaps: image.PixelMap[],
    fileName: string,
    quality: number = 80
  ): Promise<string | undefined> {
    // 校验 API 版本(需 API18+)
    const apiVersion = context.apiVersion;
    if (apiVersion < 18) {
      console.error('GIF 序列编码需要 API version 18 及以上');
      return undefined;
    }
    // 校验输入:至少需要 1 个 PixelMap
    if (pixelMaps.length === 0) {
      console.error('GIF 编码需要至少 1 个 PixelMap 帧');
      return undefined;
    }
    const imagePacker = image.createImagePacker();
    const packOpts: image.PackingOption = {
      format: 'image/gif', // GIF 格式的 MIME 类型
      quality,
    };
    const outputPath = `${context.cacheDir}/${fileName}`;
    try {
      const file = fs.openSync(outputPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      // 调用序列编码接口:PackToFileFromPixelmapSequence
      await imagePacker.packToFileFromPixelmapSequence(pixelMaps, file.fd, packOpts);
      file.closeSync();
      console.log(`GIF 序列编码成功:${outputPath},共${pixelMaps.length}帧`);
      return outputPath;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`GIF 编码失败:code=${err.code}, message=${err.message}`);
      return undefined;
    } finally {
      // 释放所有帧的 PixelMap 资源
      pixelMaps.forEach((pmap) => pmap.release());
    }
  }

  /**
   * 多个 PixelMap 编码为 GIF 内存流(用于网络传输)
   * @param pixelMaps PixelMap 数组
   * @param quality 压缩质量
   * @returns GIF 内存流
   */
  static async encodeToGifBuffer(
    pixelMaps: image.PixelMap[],
    quality: number = 80
  ): Promise<ArrayBuffer | undefined> {
    if (pixelMaps.length === 0) {
      console.error('GIF 编码需要至少 1 个 PixelMap 帧');
      return undefined;
    }
    const imagePacker = image.createImagePacker();
    const packOpts: image.PackingOption = {
      format: 'image/gif',
      quality,
    };
    try {
      const data = await imagePacker.packToDataFromPixelmapSequence(pixelMaps, packOpts);
      console.log(`GIF 内存流编码成功:${data.byteLength}字节`);
      return data;
    } catch (error: unknown) {
      const err = error as BusinessError;
      console.error(`GIF 内存流编码失败:${err.message}`);
      return undefined;
    } finally {
      pixelMaps.forEach((pmap) => pmap.release());
    }
  }
}

// 调用示例:生成 3 帧 GIF 动画
async function generateGifDemo(context: Context) {
  // 1. 准备 3 个 PixelMap 帧(模拟动画帧,实际可从视频帧或图片序列获取)
  const frame1 = await decodeToPixelMap(context, 'frame1.jpg');
  const frame2 = await decodeToPixelMap(context, 'frame2.jpg');
  const frame3 = await decodeToPixelMap(context, 'frame3.jpg');
  const frames = [frame1, frame2, frame3].filter(Boolean) as image.PixelMap[];

  // 2. 编码为 GIF 文件
  const gifPath = await GifEncoder.encodeToGifFile(context, frames, 'animation.gif', 85);
}
2.4 保存到图库:编码后的收尾操作

编码生成文件后,若需让用户在系统图库中查看,需结合 Media Library Kit 的接口(文档提到但未提供具体 API)。核心流程如下:

  1. 先通过 ImagePacker 编码生成文件(保存到沙箱目录);
  2. 调用 Media Library Kit 的 createAsset 接口,将沙箱文件导入图库;
  3. 导入成功后,可选择删除沙箱临时文件,避免占用存储空间。

注意:导入图库需申请 ohos.permission.WRITE_IMAGEVIDEO 权限,且需在 config.json 中声明。示例代码框架如下(不编造未定义的 API):

// 保存到图库(基于文档说明的流程框架)
import { mediaLibrary } from '@kit.MediaLibraryKit';

async function saveToGallery(context: Context, filePath: string) {
  try {
    // 1. 获取 MediaLibrary 实例
    const ml = mediaLibrary.getMediaLibrary(context);
    // 2. 定义图库资产参数(图片类型)
    const assetInfo = {
      uri: filePath, // 沙箱中编码后的文件路径
      type: mediaLibrary.MediaType.IMAGE,
      displayName: 'edited_image.jpg',
    };
    // 3. 导入到图库(具体 API 以 Media Library Kit 文档为准)
    const asset = await ml.createAsset(assetInfo);
    console.log(`图片已保存到图库,资产 ID:${asset.assetId}`);
    // 4. 可选:删除沙箱临时文件
    fs.unlinkSync(filePath);
  } catch (error) {
    console.error(`保存到图库失败:${error}`);
  }
}

三、避坑指南:这些错误千万别犯

3.1 格式与配置对应错误
常见错误后果解决方案
MIME 格式与文件扩展名不匹配(如 format: 'image/jpeg',扩展名.png)文件无法打开严格对应:image/jpeg→.jpg/.jpeg;image/png→.png;image/gif→.gif
多图编码选择 PNG 格式编码失败(抛出异常)多图仅支持 image/jpeg 和 image/heif
HDR 编码选择 PNG 格式无效(HDR 仅支持 JPEG)HDR 编码时 format 必须设为 image/jpeg
3.2 版本与硬件兼容问题
  • GIF 序列编码仅支持 API18+,低版本设备调用会抛出异常,需提前校验 context.apiVersion;
  • HDR 编码需要两个条件:输入资源是 HDR 格式 + 设备支持 HDR 编码,缺一不可;
  • 部分老旧设备可能不支持 HEIF 格式编码,建议优先选择 JPEG 作为兼容格式。
3.3 资源释放遗漏
  • 编码完成后,需释放 PixelMap、Picture、ImageSource 对象,尤其是 GIF 序列的多帧 PixelMap,不释放会导致内存溢出;
  • 编码到文件时,需调用 file.closeSync() 关闭文件句柄,避免文件被占用。

四、最佳实践:编码性能与质量双优化

  1. 质量与文件大小平衡:JPEG 格式建议质量设为 85-95(兼顾质量和大小),WebP 格式质量 80 即可达到 JPEG 90 的效果,且文件更小;
  2. 大文件编码优化:编码超过 10MB 的图片时,建议使用 packToFile 直接写入文件,避免 packToData 生成大尺寸 ArrayBuffer 占用过多内存;
  3. 无损编码场景:若需保留图片细节(如设计图、截图),选择 PNG 格式;若需更小体积,可尝试 WebP 无损模式(format: 'image/webp',quality: 100);
  4. 编码后文件处理:沙箱中的编码文件仅应用可访问,若需分享给其他应用,建议通过 DataAbility 提供访问,避免直接暴露文件路径。

五、总结:Image Kit 完整流程闭环

到这里,HarmonyOS Image Kit 的核心能力已全部覆盖——从「解码(文件→PixelMap/Picture)」到「编辑(裁剪/缩放/滤镜)」,再到「编码(对象→文件/内存流)」,形成了完整的图片处理闭环。

核心工具与场景对应关系:

  • 解码用 ImageSource → 单图用 PixelMap,多图用 Picture;
  • 编辑用 PixelMap 的内置方法 → 基础编辑全覆盖;
  • 编码用 ImagePacker → 单图/多图/GIF 全场景支持。

掌握这些能力后,无论是简单的图片显示、复杂的 HDR 处理,还是动态 GIF 生成,都能高效实现。建议在实际开发中,结合本文的工具类封装,根据业务场景选择合适的编码格式和配置,同时注意权限申请和资源释放,确保应用性能稳定。

目录

  1. 一、编码基础:先搞懂 ImagePacker 与核心配置
  2. 1.1 核心工具与支持格式
  3. 1.2 关键配置:PackingOption 解析
  4. 二、核心场景实战:编码功能手把手实现
  5. 2.1 单图编码:最常用场景(PixelMap/ImageSource)
  6. 2.1.1 工具类封装(统一编码逻辑)
  7. 2.1.2 调用示例(结合解码/编辑逻辑)
  8. 2.2 多图编码:Picture 对象专属场景
  9. 2.3 GIF 序列编码:API18+ 新增功能
  10. 2.4 保存到图库:编码后的收尾操作
  11. 三、避坑指南:这些错误千万别犯
  12. 3.1 格式与配置对应错误
  13. 3.2 版本与硬件兼容问题
  14. 3.3 资源释放遗漏
  15. 四、最佳实践:编码性能与质量双优化
  16. 五、总结:Image Kit 完整流程闭环
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Dify 前后端分离开发:独立启动前端 Docker 容器方案
  • 前端如何编写高质量的 AI Agent Skills
  • 基于 Llama-Factory 微调 Qwen3.5-4B 模型指南
  • MoonTV:基于 Next.js 的开源跨平台影视聚合播放器
  • everything-claude-code 配置详解:构建规范化 AI 开发工作流
  • 自进化医疗智能体:动态记忆与持续运行 Python 架构编程(下)
  • 云开发 Copilot:AI 赋能的低代码开发实践
  • JDK 下载与多系统安装指南
  • Moon VR Video Player 中文版下载及 8K/12K 多音轨播放教程
  • Git 常用操作详解:从安装到分支管理
  • Linux 网络基础:局域网与跨网段传输原理
  • 基于 Spring Cloud 的电商系统设计与实现:用户与商品模块
  • 基于出租车轨迹数据的可视化研究
  • 软件系统设计文档模板:架构、概要及详细设计
  • Vite7+Vue3+DeepSeek-R1 流式 AI 聊天系统实战
  • 数据结构:队列的各种实现与算法推荐
  • 软件架构师的角色定义与核心职责
  • SAP ABAP Web Dynpro 开发指南
  • 数据结构核心:顺序表的原理与模拟实现
  • Ant Design Form 表单组件实现原理

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online