OpenHarmony图片处理——XmlGraphicsBatik

发布于:2024-04-20 ⋅ 阅读:(20) ⋅ 点赞:(0)

简介

XmlGraphicsBatik项目用于处理可缩放矢量图形(SVG)格式的图像,例如显示、生成、解析或者操作图像。

支持SVG图像的显示,可显示静态及动态SVG图像;

支持快捷生成SVG图像文件;

支持操作SVG图像进行颜色、样式、内容的修改;

支持将SVG图像的xml文本解析为可操作对象。

下载安装

ohpm install @ohos/xmlgraphicsbatik 

OpenHarmony ohpm 环境配置等更多内容,请参考如何安装 OpenHarmony ohpm 包

使用说明

对SVG图像进行生成、操作、解析等操作均依赖于SVGManager管理类

使用本库需要预先在MainAbility.ts 中预制文件路径: GlobalContext.getContext().setObject(“filesDir”, this.context.filesDir);

import {SVGManager} from '@ohos/XmlGraphicsBatik';

private svgManager: SVGManager = SVGManager.getInstance();

1. 显示SVG图像

// Iamge组件支持显示media资源文件 及 工程目录中的SVG图片
Image($r('app.media.svgSample'))
  .width(150)
  .height(150)

Image('file://' + this.filePath + '/svg.svg')
  .width(150)
  .height(150)

2. 生成SVG图像文件

2.1 创建SVG文件声明及子标签

// 创建SVG 对象:声明及SVG标签
this.svgManager.createSVGDeclares();

// 获取SVG标签对应的对象
let svgTagObj = this.svgManager.getSVGRoot();

// 构建SVG中的rect节点
let rect: SVGRect = new SVGRect();
rect.setX(50);
rect.setY(50);
rect.setRX(20);
rect.setRY(20);
rect.setWidth(100);
rect.setHeight(100);
rect.addAttribute('style', 'fill:rgb(255,0,255);stroke-width:2;stroke:rgb(0,0,0)')

// 输出标准格式rect对象
let rectObj = rect.toObj();

// 构建固定格式的节点描述对象
let svgFormatForRect: SVGSpecifiedFormat = new SVGSpecifiedFormat();
svgFormatForRect.setElementType(SVGAttrConstants.ATTR_VALUE_ELEMENT);
svgFormatForRect.setElementName('rect');
svgFormatForRect.setAttributes(rectObj);

if (svgTagObj) {

  // 为SVG标签添加固定格式的Rect子标签
  this.svgManager.addChildNode(svgTagObj, svgFormatForRect.toObj());
  consoleInfo('Test svg: add svg svgTotalRoot', JSON.stringify(this.svgManager.getSVGTotalObj()));
}

// 获取整个SVG文件对应的对象
let svgTotalObj = this.svgManager.getSVGTotalObj();
let success = function () {
     consoleInfo('saveFile', 'success');
}

// 将SVG文件对象保存为.svg格式文件,文件保存在 /project's path/files中
this.svgManager.saveSVG('svg.svg', svgTotalObj, success);

结果

add svg svgTotalRoot: {
    "declaration":{
        "attributes":{
            "version":"1.0","encoding":"utf-8","standalone":"yes"

     }

      },"elements":[{
        "type":"element","name":"svg","attributes":{
          "xmlns":"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"
      },"elements":[{
        "type":"element","name":"rect","attributes":{
    "x":50,"y":50,"rx":20,"ry":20,"width":100,"height":100,"style":"fill:rgb(255,0,255);stroke-width:2;stroke:rgb(0,0,0)"
        }
    }]
  }]
}

2.2 手动创建SVG文件及子标签

// 清空已存在的SVG根
this.svgXMLRoot = this.svgManager.getSVGTotalObj();
this.svgManager.removeByKey(this.svgXMLRoot, SVGAttrConstants.ATTR_KEY_DECLARATION);
this.svgManager.removeByKey(this.svgXMLRoot, SVGAttrConstants.ATTR_KEY_ELEMENTS);

// 构建SVG标签对应的对象
let svg: SVGRoot = new SVGRoot();
svg.setXMLNS(XMLConstants.XMLNS_NAMESPACE_URI_SVG);
svg.setXMLNSLink(XMLConstants.XLINK_NAMESPACE_URI);
svg.setSvgId('svgRoot');
svg.setXMLSpace(false);
svg.setWidth(250);
svg.setHeight(250);
svg.setViewBox(10, 10, 250, 250);
let svgObj = svg.toObj();

let svgSpecifiedFormat: SVGSpecifiedFormat = new SVGSpecifiedFormat();
svgSpecifiedFormat.setElementType(SVGAttrConstants.ATTR_VALUE_ELEMENT);
svgSpecifiedFormat.setElementName('svg');
svgSpecifiedFormat.setAttributes(svgObj);

// 构建SVG标签内的Rect子标签的对象
let rect: SVGRect = new SVGRect();
rect.setX(50);
rect.setY(50);
rect.setRX(20);
rect.setRY(20);
rect.setWidth(100);
rect.setHeight(100);
rect.addAttribute('style', 'fill:rgb(0,0,255);stroke-width:2;stroke:rgb(0,0,0)')
let rectObj = rect.toObj();

let svgFormatForRect: SVGSpecifiedFormat = new SVGSpecifiedFormat();
svgFormatForRect.setElementType(SVGAttrConstants.ATTR_VALUE_ELEMENT);
svgFormatForRect.setElementName('rect');
svgFormatForRect.setAttributes(rectObj);
svgSpecifiedFormat.setElements(svgFormatForRect.toObj());

if (this.svgXMLRoot) {

  // 构建SVG文件声明
  let declarationAttrs: object = {};
  declarationAttrs['version'] = '1.0';
  declarationAttrs['encoding'] = 'utf-8';
  declarationAttrs['standalone'] = 'no';

  let declarationObj: object = {};
  declarationObj[SVGAttrConstants.ATTR_KEY_ATTRIBUTES] = declarationAttrs

  this.svgXMLRoot[SVGAttrConstants.ATTR_KEY_DECLARATION] = declarationObj;
  this.svgManager.addChildNode(this.svgXMLRoot, svgSpecifiedFormat.toObj());
  consoleInfo('Test svg: add line svgTotalRoot', JSON.stringify(this.svgManager.getSVGTotalObj()));
}

结果

Test svg: add svg svgTotalRoot: {
  "declaration":{"attributes":{
      "version":"1.0","encoding":"utf-8","standalone":"no"
    }
  },"elements":[{
          "type":"element","name":"svg","attributes":{
    "xmlns":"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","id":"svgRoot","xml:space":"default","width":250,"height":250,"viewBox":{
      "x":10,"y":10,"width":250,"height":250
     }
    },"elements":[{
          "type":"element","name":"rect","attributes":{"x":50,"y":50,"rx":20,"ry":20,"width":100,"height":100,"style":"fill:rgb(0,0,255);stroke-width:2;stroke:rgb(0,0,0)"}
      }]
    }]
}

3. 操作SVG图像对象

3.1 修改已存在的子标签的属性

// 获取SVG根标签对应的操作对象
let svgRoot = this.svgManager.getSVGRoot();
if (!svgRoot) {
  consoleInfo('Test rect: update attr for rect1', 'svg tag is null');
  return false;
}

// 根据主键获取对应的属性值
let svgElements = this.svgManager.getValueForKey(svgRoot, SVGAttrConstants.ATTR_KEY_ELEMENTS);
if (!svgElements) {
  consoleInfo('Test rect: update attr for rect1', `svg tag's elements is null`);
  return false;
}

if (typeof svgElements !== SVGAttrConstants.TYPEOF_OBJECT || !Array.isArray(svgElements)) {
  consoleInfo('Test rect: update attr for rect1', `the elements's type of svg tag is not array`);
  return;
}

let rectResult = null;
try {
  svgElements.forEach((item) => {
    if (typeof item === SVGAttrConstants.TYPEOF_OBJECT) {
      let nameValue: string = this.svgManager.getValueForKey(item, SVGAttrConstants.ATTR_KEY_NAME);
      if (nameValue === 'rect') {
        rectResult = item;
        throw 'has got rect,jump out';
      }
    }
  })
} catch (e) {
  if (!rectResult) {
    consoleInfo('Test rect: update attr for rect1', 'rect not exist');
    return;
  }

  if (typeof rectResult === SVGAttrConstants.TYPEOF_OBJECT) {
    let rectAttributes = rectResult[SVGAttrConstants.ATTR_KEY_ATTRIBUTES];
    rectAttributes['x'] = 20;
    rectAttributes['y'] = 20;
    rectAttributes['rx'] = 10;
    rectAttributes['ry'] = 50;
    rectAttributes['width'] = 80;
    rectAttributes['height'] = 80;
    
    // 为标签添加/设置属性键值对
    this.svgManager.setAttribute(rectAttributes, 'style', 'fill:rgb(0,255,0);stroke-width:10;stroke:rgb(0,255,255)');
    this.allAttrRectObj = rectResult;
  }
  consoleInfo('Test rect: update attr for rect1 svgTotalObj', JSON.stringify(this.svgManager.getSVGTotalObj()));
}

3.2 移除属性键值对

let attrs = this.svgManager.getValueForKey(rectOriginData, SVGAttrConstants.ATTR_KEY_ATTRIBUTES);
if (!attrs) {
  consoleInfo('test remove ' + firstAttrName, 'rect1 has no attributes');
  return;
}
this.svgManager.removeByKey(attrs, firstAttrName);

4. 解析SVG图像文件

this.svgManager.parse('svg.svg', (parseXMLResultObj) =>{
	this.svgJson = parseXMLResultObj;
})

结果

{"declaration":{
      "attributes":{
          "version":"1.0","encoding":"utf-8"
      }
        },"elements":[{

          "type":"element","name":"svg","attributes":{
                "id":"svgRoot","space":"default","width":"250","height":"250","viewBox":"10 10 250 250 "
      },"elements":[{
          "type":"element","name":"rect","attributes":{
      "x":"50","y":"50","rx":"20","ry":"20","width":"100","height":"100","style":"fill:rgb(0,0,255);stroke-width:2;stroke:rgb(0,0,0)"
          }
      }]
      }]
}

接口说明

  1. 获取SVG管理类实例
   static getInstance(): SVGManager
  1. 获取整个SVG文件对应的可以操作对象
   getSVGTotalObj(): object
  1. 创建SVG文件声明及SVG根标签
   createSVGDeclares(): object
  1. 获取SVG根标签对应的可操作对象
   getSVGRoot(obj: Object = this.svgObj): object
  1. 添加子标签(不覆盖原子标签)
   addChildNode(parentObj: Object, childPropertyValue: Object): boolean
  1. 设置子标签(覆盖原子标签)
   setChildNode(parentObj: Object, childPropertyValue: Object): boolean
  1. 通过主键获取对应属性值
   getValueForKey(parentObj: Object, key: string): any
  1. 根据主键移除键值对
   removeByKey(parentObj: Object, key: string): void
  1. 为对象设置属性或子节点(覆盖原有键值对)
   setAttribute(parentObj: Object, key: string, value: string): void
  1. 创建文件夹
    createFolder(path: string): void 
  1. 获取文件根路径
    getFilePath(onSuccess: (filesDir: string) => void): void
  1. 保存SVG文件
    saveSVG(fileName: string, fileContent: string | Object, onSuccess?: () => void, onFailed?: (number, Error) => void): void
  1. 解析SVG文件
    parse(fileName: string, onSuccess: (result: string) => void, onFailed?: (error: Error) => void): void

约束与限制

在下述版本验证通过:

DevEco Studio: 4.1 Canary(4.1.3.322), SDK: API11 (4.1.0.36)

DevEco Studio: 4.0 (4.0.3.600), SDK: API10 (4.0.10.11)

DevEco Studio: 4.0 (4.0.3.512), SDK: API10 (4.0.10.9)

DevEco Studio: 3.1 Beta2(3.1.0.400), SDK: API9 Release(3.2.11.9)

目录

/XmlGraphicsBatik       # 工程根目录
├── entry                  # 示例代码文件夹
├── library    # 三方库源码文件夹
│   └── src
│       ├── index.ets      # 对外暴露文件的存放目录
│       ├── package.json   # 项目介绍
│       └──main/ets/batik
│          ├── SVGManager.ets    # SVG处理管理核心类
│          ├── SVGXMLChecker.ets # 检查SVG文本是否合规
│          ├── StringReader.ets  # 读取SVG文本字符串工具类
│          └── constants
│              ├── RegexConstants.ets   # 正则表达式常量类
│              ├── SVGAttrConstants.ets # SVG标准格式主键常量类
│              ├── SVGXMLConstants.ets  # SVG文件常量类
│              └── XMLConstants.ets     # XML文件常量类
│          └── svggen
│              ├── SVGSpecifiedFormat.ets  # SVG文件对应的可操作对象标准格式构造类
│              ├── SVGDeclares.ets         # SVG文件声明构造类 
│              ├── SVGRoot.ets             # SVG文件根标签构造类
│              ├── SVGCircle.ets           # Ciecle子标签构造类
│              ├── SVGEllipse.ets          # Ellipse子标签构造类
│              ├── SVGLine.ets             # Line子标签构造类
│              ├── SVGPath.ets             # Path子标签构造类
│              ├── SVGRect.ets             # Rect子标签构造类
│              └── SVGPolygonAndPolyLine.ets # Polygon 及 PolyLine子标签构造类
│          └── tools
│              ├── DeleteProperty.ts            # Delete工具函数
│              ├── GetKeysTest.ts               # GetKeysDelete工具函数 
│              ├── GlobalContext.ets            # GlobalContext构造类
│              ├── IsArrayFunction.ts           # IsArray工具函数
│              ├── MakePropertiesImmutable.ts   # 冻结对象工具函数
│              ├── ObjCreate.ts                 # 创建空对象工具函数
│              └── StringToHex.ts               # 字符串转不同进制工具函数
│          └── util
│              ├── LogUtil.ets         # 日志打印工具类
│              ├── ObjOrArrayUtil.ets  # 可操作对象及Array处理工具类
│              └── XMLRules.ets        # XML文件固定规则工具类

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向