diff --git a/entry/src/main/ets/pages/svgTestCasePage.ets b/entry/src/main/ets/pages/svgTestCasePage.ets new file mode 100644 index 0000000..69d4c93 --- /dev/null +++ b/entry/src/main/ets/pages/svgTestCasePage.ets @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {SVGParseImpl} from '@ohos/imageknife' + +@Entry +@Component +struct svgTestCasePage { + + @State pixels:PixelMap = undefined + + build() { + Scroll() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Flex({direction:FlexDirection.Row}){ + Button("加载SVG图片") + .onClick(()=>{ + + globalThis.ImageKnife.getImageKnifeContext().resourceManager.getMedia($r('app.media.ic_svg').id) + .then(data => { + console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data) + let svgImpl = new SVGParseImpl(); + svgImpl.parseSvg(data.buffer).then((pixelmap)=>{ + this.pixels = pixelmap; + }) + }) + .catch(err => { + console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err)); + }) + + }).margin({left:5}).backgroundColor(Color.Blue) + + } + .margin({top:15}) + + Text("下面为展示图片区域").margin({top:5}) + Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ + Image(this.pixels) + .width(400) + .height(400) + .backgroundColor(Color.Pink) + }.width(400).height(400).margin({top:10}).backgroundColor(Color.Pink) + } + } + .width('100%') + .height('100%') + } + + aboutToAppear() { + console.log("aboutToAppear()") + } + typedArrayToBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) + } +} + + diff --git a/imageknife/src/main/ets/components/imageknife/utils/svg/IParseSvg.ets b/imageknife/src/main/ets/components/imageknife/utils/svg/IParseSvg.ets new file mode 100644 index 0000000..116281f --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/svg/IParseSvg.ets @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export interface IParseSvg { + // 解析svg + parseSvg(imageinfo: ArrayBuffer,size?:{width:number,height:number}): Promise +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/svg/SVGImageViewModel.ets b/imageknife/src/main/ets/components/imageknife/utils/svg/SVGImageViewModel.ets new file mode 100644 index 0000000..c7480da --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/svg/SVGImageViewModel.ets @@ -0,0 +1,1107 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import image from '@ohos.multimedia.image' +import util from '@ohos.util' +import display from '@ohos.display'; +import configuration from '@system.configuration'; +import { + SVG, + PathView, + ImageSvg, + CircleView, + EllipseView, + LineView, + PolyLineView, + PolygonView, + RectView, + Group, + Switch, + TextView, + Use, + SVGXMLConstants, + SVGAttrConstants, + SVGManager, + SVGXMLChecker +} from '@ohos/svg'; + +export default class SVGImageViewModel { + private svgString: string = ""; + private rawfileName: string = ""; + private media: Resource; + svgs: SVG[] = [] + svg: SVG = new SVG(); + isPx: boolean = false; + private context: OffscreenCanvasRenderingContext2D + private svgManager: SVGManager = SVGManager.getInstance(); + + deviceW: number = display.getDefaultDisplaySync().width; + deviceH: number = display.getDefaultDisplaySync().height; + + /** + * 设置svg的字符串 + * @param svgString svg字符串 + */ + public setSvgString(svgString: string) { + this.svgString = svgString; + this.parseSvgFromString(); + } + + /** + * 设置rawfile下的svg + * @param svgRawfile rawfile下的svg文件名 + */ + public setSvgRawfile(svgRawfile: string) { + this.rawfileName = svgRawfile; + this.parseSvgFromRawfile(); + } + + /** + * 设置media下的svg + * @param media media下的svg文件 + */ + public setSvgMedia(media: Resource) { + this.media = media; + this.parseSvgFromMedia(); + } + + public setSvgUint8Array(uint8:Uint8Array){ + this.svgString = this.unit8ArrayToString(uint8) + this.parseSvgFromString(); + } + + private parseSvgFromMedia() { + globalThis.resourceManager.getMedia(this.media.id, (error, value) => { + if (error != null) { + console.error("media get error:" + error) + throw new Error("未找到media下的svg") + } else { + this.svgString = this.unit8ArrayToString(value); + this.parseSvgFromString(); + } + }) + } + + private parseSvgFromRawfile() { + globalThis.resourceManager.getRawFile(this.rawfileName, (error, value) => { + if (error != null) { + console.error("rawfile get error:" + error) + throw new Error("未找到rawfile下的svg") + } else { + this.svgString = this.unit8ArrayToString(value); + this.parseSvgFromString(); + } + }) + } + + private unit8ArrayToString(fileData) { +// var dataString = ""; +// for (var i = 0; i < fileData.length; i++) { +// dataString += String.fromCharCode(fileData[i]); +// } +// return dataString + let textDecoder = new util.TextDecoder("utf-8", {ignoreBOM:true}); + let retStr = textDecoder.decode(fileData, {stream: false}); + return retStr; + } + + private parseSvgFromString() { + this.svgs.length = 0; + this.svgManager.parseString(this.svgString, (jsonString) => { + var reg = new RegExp("stroke-", "g") + jsonString = String(jsonString).replace(reg, "stroke_"); + reg = new RegExp("font-", "g") + jsonString = String(jsonString).replace(reg, "font_"); + reg = new RegExp("fill-", "g") + jsonString = String(jsonString).replace(reg, "fill_"); + var svgElements: any[] = JSON.parse(jsonString).elements; + if (!SVGXMLChecker.checkArrayEmpty(svgElements)) { + this.getSvgData(svgElements); + } + }) + } + + private getSvgData(data: any[], g?: SVG) { + for (let i = 0;i < data.length; i++) { + if (data[i].type == SVGAttrConstants.ATTR_VALUE_ELEMENT) { + switch (data[i].name) { + case SVGXMLConstants.SVG_SVG_TAG: + if (!SVGXMLChecker.checkObjectEmpty(data[i].attributes)) { + this.parseAttributesSVG(data[i].attributes); + } + if (!SVGXMLChecker.checkArrayEmpty(data[i].elements)) { + this.getSvgData(data[i].elements); + } + break; + } + this.setSvgArrayChild(data[i], this.svgs, g) + } + } + } + + private setSvgArrayChild(elements: any, svgs: SVG[], g?: SVG) { + switch (elements.name) { + case SVGXMLConstants.SVG_G_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + g = this.parseAttributesGroup(elements.attributes, g); + } + if (!SVGXMLChecker.checkArrayEmpty(elements.elements)) { + this.getSvgData(elements.elements, g); + } + break; + case SVGXMLConstants.SVG_CIRCLE_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesCircle(elements.attributes, g)) + } + break; + case SVGXMLConstants.SVG_ELLIPSE_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesEllipse(elements.attributes, g)) + } + break; + case SVGXMLConstants.SVG_LINE_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesLine(elements.attributes, g)) + } + break; + case SVGXMLConstants.SVG_POLYLINE_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesPolyLine(elements.attributes, g)) + } + break; + case SVGXMLConstants.SVG_POLYGON_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesPolygon(elements.attributes, g)); + } + break; + case SVGXMLConstants.SVG_PATH_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesPath(elements.attributes, g)); + } + break; + case SVGXMLConstants.SVG_RECT_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesRect(elements.attributes, g)); + } + break; + case SVGXMLConstants.SVG_IMAGE_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesImage(elements.attributes, g)); + } + break; + case SVGXMLConstants.SVG_STYLE_TAG: + if (!SVGXMLChecker.checkArrayEmpty(elements.elements)) { + } + break; + case SVGXMLConstants.SVG_USE_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesUse(elements.attributes, g)); + } + break; + case SVGXMLConstants.SVG_TEXT_TAG: + if (!SVGXMLChecker.checkObjectEmpty(elements.attributes)) { + svgs.push(this.parseAttributesText(elements.attributes, g, elements.elements[0].text)); + } + break; + case SVGXMLConstants.SVG_SWITCH_TAG: + if (!SVGXMLChecker.checkArrayEmpty(elements.elements)) { + svgs.push(this.parseAttributesSwitch(elements.attributes, elements.elements)); + } + break; + } + } + + private parseAttributesSVG(svg: any) { + if (!SVGXMLChecker.checkObjectEmpty(svg.id)) { + this.svg.setId(svg.id); + } + if (!SVGXMLChecker.checkObjectEmpty(svg.width)) { + this.svg.setWidth(svg.width); + } + if (!SVGXMLChecker.checkObjectEmpty(svg.height)) { + this.svg.setHeight(svg.height); + } + if (!SVGXMLChecker.checkObjectEmpty(svg.viewBox)) { + this.svg.setViewBox(svg.viewBox); + } + if (!SVGXMLChecker.checkObjectEmpty(svg.fill)) { + this.svg.setFill(svg.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(svg.stroke)) { + this.svg.setStroke(svg.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(svg.stroke_width)) { + this.svg.setStrokeWidth(svg.stroke_width); + } + if (this.svg.width == '100%') { + this.svg.setWidth(this.svg.viewBoxWidth) + } + if (this.svg.height == '100%') { + this.svg.setHeight(this.svg.viewBoxHeight) + } + } + + private parseAttributesGroup(g: any, lastGroup?: SVG): SVG { + var newGroup: SVG = SVGXMLChecker.checkObjectEmpty(lastGroup) ? new SVG() : lastGroup + if (!SVGXMLChecker.checkObjectEmpty(g.id)) { + newGroup.setId(g.id); + } + if (!SVGXMLChecker.checkObjectEmpty(g.class)) { + newGroup.setClass(g.class); + } + if (!SVGXMLChecker.checkObjectEmpty(g.fill)) { + newGroup.setFill(g.fill); + } else { + newGroup.setFill(newGroup.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(g.fill_opacity)) { + newGroup.setFillOpacity(g.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(g.stroke)) { + newGroup.setStroke(g.stroke); + } else { + newGroup.setStroke(newGroup.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(g.stroke_width)) { + newGroup.setStrokeWidth(g.stroke_width); + } else { + newGroup.setStrokeWidth(newGroup.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(g.stroke_miterlimit)) { + newGroup.setStrokeMiterLimit(g.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(g.style)) { + newGroup.setStyle(g.style); + } + if (!SVGXMLChecker.checkObjectEmpty(g.transform)) { + newGroup.setTransform(g.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, true); + } + if (!SVGXMLChecker.checkObjectEmpty(g.systemLanguage)) { + newGroup.setSystemLanguage(g.systemLanguage); + } + return newGroup; + } + + private parseAttributesCircle(circle: any, g: SVG): CircleView { + var newCircle: CircleView = new CircleView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.id)) { + newCircle.setId(circle.id); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.class)) { + newCircle.setClass(circle.class); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.r)) { + newCircle.setWidth(circle.r); + newCircle.setHeight(circle.r); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.cx)) { + newCircle.setX(circle.cx); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.cy)) { + newCircle.setY(circle.cy); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.transform)) { + newCircle.copyTransform(g); + newCircle.setTransform(circle.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.fill)) { + newCircle.setFill(circle.fill); + } else { + newCircle.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.fill_opacity)) { + newCircle.setFillOpacity(circle.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.stroke)) { + newCircle.setStroke(circle.stroke); + } else { + newCircle.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.stroke_width)) { + newCircle.setStrokeWidth(circle.stroke_width); + } else { + newCircle.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.stroke_miterlimit)) { + newCircle.setStrokeMiterLimit(circle.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(circle.style)) { + newCircle.setStyle(circle.style); + } + return newCircle; + } + + private parseAttributesEllipse(ellipse: any, g: SVG): EllipseView { + var newEllipse: EllipseView = new EllipseView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.id)) { + newEllipse.setId(ellipse.id); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.class)) { + newEllipse.setClass(ellipse.class); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.cx)) { + newEllipse.setX(ellipse.cx) + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.cy)) { + newEllipse.setY(ellipse.cy) + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.rx)) { + newEllipse.setWidth(Number(ellipse.rx) * 2); + // newEllipse.setX(-Number(ellipse.rx)) + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.ry)) { + newEllipse.setHeight(Number(ellipse.ry) * 2); + // newEllipse.setY(-Number(ellipse.ry)) + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.x)) { + newEllipse.setX(ellipse.x); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.y)) { + newEllipse.setY(ellipse.y); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.transform)) { + newEllipse.copyTransform(g); + newEllipse.setTransform(ellipse.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.fill)) { + newEllipse.setFill(ellipse.fill); + } else { + newEllipse.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.fill_opacity)) { + newEllipse.setFillOpacity(ellipse.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.stroke)) { + newEllipse.setStroke(ellipse.stroke); + } else { + newEllipse.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.stroke_width)) { + newEllipse.setStrokeWidth(ellipse.stroke_width); + } else { + newEllipse.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.stroke_miterlimit)) { + newEllipse.setStrokeMiterLimit(ellipse.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.style)) { + newEllipse.setStyle(ellipse.style); + } + + if (newEllipse.cx > 0 && newEllipse.cy > 0) { + newEllipse.setX(Number(newEllipse.x) + Number(newEllipse.cx)) + newEllipse.setY(Number(newEllipse.y) + Number(newEllipse.cy)) + } + if (!SVGXMLChecker.checkObjectEmpty(ellipse.systemLanguage)) { + newEllipse.setSystemLanguage(ellipse.systemLanguage); + } + return newEllipse; + } + + private parseAttributesLine(line: any, g: SVG): LineView { + var newLine: LineView = new LineView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(line.id)) { + newLine.setId(line.id); + } + if (!SVGXMLChecker.checkObjectEmpty(line.class)) { + newLine.setClass(line.class); + } + if (!SVGXMLChecker.checkObjectEmpty(line.x1)) { + newLine.setStartX(line.x1); + } + if (!SVGXMLChecker.checkObjectEmpty(line.y1)) { + newLine.setStartY(line.y1); + } + if (!SVGXMLChecker.checkObjectEmpty(line.x2)) { + newLine.setEndX(line.x2); + } + if (!SVGXMLChecker.checkObjectEmpty(line.y2)) { + newLine.setEndY(line.y2); + } + if (!SVGXMLChecker.checkObjectEmpty(line.x)) { + newLine.setX(line.x); + } + if (!SVGXMLChecker.checkObjectEmpty(line.y)) { + newLine.setY(line.y); + } + if (!SVGXMLChecker.checkObjectEmpty(line.transform)) { + newLine.copyTransform(g); + newLine.setTransform(line.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(line.fill)) { + newLine.setFill(line.fill); + } else { + newLine.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(line.fill_opacity)) { + newLine.setFillOpacity(line.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(line.stroke)) { + newLine.setStroke(line.stroke); + } else { + newLine.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(line.stroke_width)) { + newLine.setStrokeWidth(line.stroke_width); + } else { + newLine.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(line.stroke_miterlimit)) { + newLine.setStrokeMiterLimit(line.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(line.style)) { + newLine.setStyle(line.style); + } + if (!SVGXMLChecker.checkObjectEmpty(line.systemLanguage)) { + newLine.setSystemLanguage(line.systemLanguage); + } + + return newLine; + } + + private parseAttributesPolyLine(polyLine: any, g: SVG): PolyLineView { + var newPolyLine = new PolyLineView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.id)) { + newPolyLine.setId(polyLine.id); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.class)) { + newPolyLine.setClass(polyLine.class); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.points)) { + let pointsArray: string[] = String(polyLine.points).split(" "); + let pointsResult: Array<[number, number]> = new Array<[number, number]>(); + for (let i = 0;i < pointsArray.length; i++) { + let pointsItem = pointsArray[i].split(",") + pointsResult.push([Number(pointsItem[0]), Number(pointsItem[1])]) + } + newPolyLine.setPointsResult(pointsResult); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.x)) { + newPolyLine.setX(polyLine.x); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.y)) { + newPolyLine.setY(polyLine.y); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.transform)) { + newPolyLine.copyTransform(g); + newPolyLine.setTransform(polyLine.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.fill)) { + newPolyLine.setFill(polyLine.fill); + } else { + newPolyLine.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.fill_opacity)) { + newPolyLine.setFillOpacity(polyLine.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.stroke)) { + newPolyLine.setStroke(polyLine.stroke); + } else { + newPolyLine.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.stroke_width)) { + newPolyLine.setStrokeWidth(polyLine.stroke_width); + } else { + newPolyLine.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.stroke_miterlimit)) { + newPolyLine.setStrokeMiterLimit(polyLine.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.style)) { + newPolyLine.setStyle(polyLine.style); + } + if (!SVGXMLChecker.checkObjectEmpty(polyLine.systemLanguage)) { + newPolyLine.setSystemLanguage(polyLine.systemLanguage); + } + + return newPolyLine; + } + + private parseAttributesPolygon(polygon: any, g: SVG): PolygonView { + var newPolygon = new PolygonView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.id)) { + newPolygon.setId(polygon.id); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.class)) { + newPolygon.setClass(polygon.class); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.points)) { + let pointsArray: string[] = String(polygon.points).split(" "); + let pointsResult: Array<[number, number]> = new Array<[number, number]>(); + for (let i = 0;i < pointsArray.length; i++) { + let pointsItem = pointsArray[i].split(",") + pointsResult.push([Number(pointsItem[0]), Number(pointsItem[1])]) + } + newPolygon.setPointsResult(pointsResult); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.x)) { + newPolygon.setX(polygon.x); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.y)) { + newPolygon.setY(polygon.y); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.transform)) { + newPolygon.copyTransform(g); + newPolygon.setTransform(polygon.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.fill)) { + newPolygon.setFill(polygon.fill); + } else { + newPolygon.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.fill_opacity)) { + newPolygon.setFillOpacity(polygon.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.stroke)) { + newPolygon.setStroke(polygon.stroke); + } else { + newPolygon.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.stroke_width)) { + newPolygon.setStrokeWidth(polygon.stroke_width); + } else { + newPolygon.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.stroke_miterlimit)) { + newPolygon.setStrokeMiterLimit(polygon.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.style)) { + newPolygon.setStyle(polygon.style); + } + if (!SVGXMLChecker.checkObjectEmpty(polygon.systemLanguage)) { + newPolygon.setSystemLanguage(polygon.systemLanguage); + } + + return newPolygon; + } + + private parseAttributesPath(path: any, g: SVG): PathView { + var newPath = new PathView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(path.id)) { + newPath.setId(path.id); + } + if (!SVGXMLChecker.checkObjectEmpty(path.class)) { + newPath.setClass(path.class); + } + if (!SVGXMLChecker.checkObjectEmpty(path.d)) { + newPath.setCommands(path.d); + } + if (!SVGXMLChecker.checkObjectEmpty(path.x)) { + newPath.setX(path.x); + } + if (!SVGXMLChecker.checkObjectEmpty(path.y)) { + newPath.setY(path.y); + } + if (!SVGXMLChecker.checkObjectEmpty(path.transform)) { + newPath.copyTransform(g); + newPath.setTransform(path.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(path.fill)) { + newPath.setFill(path.fill); + } else { + newPath.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(path.fill_opacity)) { + newPath.setFillOpacity(path.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(path.stroke)) { + newPath.setStroke(path.stroke); + } else { + newPath.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(path.stroke_width)) { + newPath.setStrokeWidth(path.stroke_width); + } else { + newPath.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(path.stroke_miterlimit)) { + newPath.setStrokeMiterLimit(path.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(path.style)) { + newPath.setStyle(path.style); + } + if (!SVGXMLChecker.checkObjectEmpty(path.systemLanguage)) { + newPath.setSystemLanguage(path.systemLanguage); + } + + return newPath; + } + + private parseAttributesRect(rect: any, g: SVG): RectView { + var newRect = new RectView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.id)) { + newRect.setId(rect.id); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.class)) { + newRect.setClass(g._class + " " + rect.class); + } else { + newRect.setClass(g._class); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.width)) { + newRect.setWidth(rect.width); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.height)) { + newRect.setHeight(rect.height); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.rx)) { + newRect.setRx(rect.rx); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.ry)) { + newRect.setRy(rect.ry); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.x)) { + newRect.setX(rect.x); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.y)) { + newRect.setY(rect.y); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.transform)) { + newRect.copyTransform(g); + newRect.setTransform(rect.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.fill)) { + newRect.setFill(!SVGXMLChecker.checkObjectEmpty(rect.fill) ? rect.fill : g.fill); + } else { + newRect.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.fill_opacity)) { + newRect.setFillOpacity(rect.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.stroke)) { + newRect.setStroke(rect.stroke); + } else { + newRect.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.stroke_width)) { + newRect.setStrokeWidth(rect.stroke_width); + } else { + newRect.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.stroke_miterlimit)) { + newRect.setStrokeMiterLimit(rect.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.style)) { + newRect.setStyle(rect.style); + } + if (!SVGXMLChecker.checkObjectEmpty(rect.systemLanguage)) { + newRect.setSystemLanguage(rect.systemLanguage); + } + + return newRect; + } + + private parseAttributesImage(image: any, g: SVG): ImageSvg { + var newImage = new ImageSvg(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(image.id)) { + newImage.setId(image.id); + } + if (!SVGXMLChecker.checkObjectEmpty(image.class)) { + newImage.setClass(image.class); + } + if (!SVGXMLChecker.checkObjectEmpty(image.width)) { + newImage.setWidth(image.width); + } + if (!SVGXMLChecker.checkObjectEmpty(image.height)) { + newImage.setHeight(image.height); + } + if (!SVGXMLChecker.checkObjectEmpty(image.opacity)) { + newImage.setOpacity(Number(image.opacity)); + } + if (!SVGXMLChecker.checkObjectEmpty(image.href)) { + newImage.setHref(image.href); + } + if (!SVGXMLChecker.checkObjectEmpty(image.transform)) { + newImage.copyTransform(g); + newImage.setTransform(image.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(image.systemLanguage)) { + newImage.setSystemLanguage(image.systemLanguage); + } + + return newImage; + } + + private parseAttributesUse(use: any, g: SVG): Use { + var newUse = new Use(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(use.id)) { + newUse.setId(use.id); + } + if (!SVGXMLChecker.checkObjectEmpty(use.x)) { + newUse.setX(use.x); + } + if (!SVGXMLChecker.checkObjectEmpty(use.y)) { + newUse.setY(use.y); + } + if (!SVGXMLChecker.checkObjectEmpty(use.width)) { + newUse.setWidth(use.width); + } + if (!SVGXMLChecker.checkObjectEmpty(use.height)) { + newUse.setHeight(use.height); + } + if (!SVGXMLChecker.checkObjectEmpty(use.href)) { + newUse.setHref(use.href); + } + if (!SVGXMLChecker.checkObjectEmpty(use.transform)) { + newUse.copyTransform(g); + newUse.setTransform(use.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(use.systemLanguage)) { + newUse.setSystemLanguage(use.systemLanguage); + } + + return newUse; + } + + private parseAttributesText(text: any, g: SVG, str: string): TextView { + var newText = new TextView(); + if (SVGXMLChecker.checkObjectEmpty(g)) { + g = new Group(); + } + if (!SVGXMLChecker.checkObjectEmpty(text.id)) { + newText.setId(text.id); + } + if (!SVGXMLChecker.checkObjectEmpty(text.x)) { + newText.setX(text.x); + } + if (!SVGXMLChecker.checkObjectEmpty(text.y)) { + newText.setY(text.y); + } + if (!SVGXMLChecker.checkObjectEmpty(text.dx)) { + newText.setDx(text.dx); + } + if (!SVGXMLChecker.checkObjectEmpty(text.dy)) { + newText.setDy(text.dy); + } + if (!SVGXMLChecker.checkObjectEmpty(str)) { + newText.setText(str); + } + if (!SVGXMLChecker.checkObjectEmpty(text.font_size)) { + newText.setFontSize(text.font_size); + } + if (!SVGXMLChecker.checkObjectEmpty(text.transform)) { + newText.copyTransform(g); + newText.setTransform(text.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, false); + } + if (!SVGXMLChecker.checkObjectEmpty(text.fill)) { + newText.setFill(!SVGXMLChecker.checkObjectEmpty(text.fill) ? text.fill : g.fill); + } else { + newText.setFill(g.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(text.fill_opacity)) { + newText.setFillOpacity(text.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(text.stroke)) { + newText.setStroke(text.stroke); + } else { + newText.setStroke(g.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(text.stroke_width)) { + newText.setStrokeWidth(text.stroke_width); + } else { + newText.setStrokeWidth(g.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(text.stroke_miterlimit)) { + newText.setStrokeMiterLimit(text.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(text.style)) { + newText.setStyle(text.style); + } + if (!SVGXMLChecker.checkObjectEmpty(text.systemLanguage)) { + newText.setSystemLanguage(text.systemLanguage); + } + + return newText; + } + + private parseAttributesSwitch(g: any, elements: any): Switch { + var newSwitch: Switch = new Switch(); + if (g != undefined) { + if (!SVGXMLChecker.checkObjectEmpty(g.id)) { + newSwitch.setId(g.id); + } + if (!SVGXMLChecker.checkObjectEmpty(g.class)) { + newSwitch.setClass(g.class); + } + if (!SVGXMLChecker.checkObjectEmpty(g.fill)) { + newSwitch.setFill(g.fill); + } else { + newSwitch.setFill(newSwitch.fill); + } + if (!SVGXMLChecker.checkObjectEmpty(g.fill_opacity)) { + newSwitch.setFillOpacity(g.fill_opacity); + } + if (!SVGXMLChecker.checkObjectEmpty(g.stroke)) { + newSwitch.setStroke(g.stroke); + } else { + newSwitch.setStroke(newSwitch.stroke); + } + if (!SVGXMLChecker.checkObjectEmpty(g.stroke_width)) { + newSwitch.setStrokeWidth(g.stroke_width); + } else { + newSwitch.setStrokeWidth(newSwitch.strokeWidth); + } + if (!SVGXMLChecker.checkObjectEmpty(g.stroke_miterlimit)) { + newSwitch.setStrokeMiterLimit(g.stroke_miterlimit); + } + if (!SVGXMLChecker.checkObjectEmpty(g.style)) { + newSwitch.setStyle(g.style); + } + if (!SVGXMLChecker.checkObjectEmpty(g.transform)) { + newSwitch.setTransform(g.transform, this.svg.viewBoxWidth, this.svg.viewBoxHeight, true); + } + if (!SVGXMLChecker.checkObjectEmpty(g.systemLanguage)) { + newSwitch.setSystemLanguage(g.systemLanguage); + } + } + for (let i = 0;i < elements.length; i++) { + this.setSvgArrayChild(elements[i], newSwitch.child, newSwitch); + } + return newSwitch; + } + + private addSvgToArray(svg: SVG) { + this.svgs.push(svg) + } + + public copy(val: SVG): SVG{ + let copySvg = null; + if (val instanceof ImageSvg) { + copySvg = new ImageSvg(); + copySvg.href = val.href; + } else if (val instanceof CircleView) { + copySvg = new CircleView(); + } else if (val instanceof EllipseView) { + copySvg = new EllipseView(); + } else if (val instanceof LineView) { + copySvg = new LineView(); + copySvg.startX = val.startX; + copySvg.startY = val.startY; + copySvg.endX = val.endX; + copySvg.endY = val.endY; + } else if (val instanceof PolyLineView) { + copySvg = new PolyLineView(); + copySvg.pointsResult = val.pointsResult; + } else if (val instanceof PolygonView) { + copySvg = new PolygonView(); + copySvg.pointsResult = val.pointsResult; + } else if (val instanceof RectView) { + copySvg = new RectView(); + copySvg.rx = val.rx; + copySvg.ry = val.ry; + } else if (val instanceof Use) { + copySvg = new Use(); + copySvg.href = val.href; + } + copySvg.id = val.id; + copySvg._class = val._class; + copySvg.x = val.x; + copySvg.y = val.y; + copySvg.width = val.width; + copySvg.height = val.height; + copySvg.fill = val.fill; + copySvg.opacity = val.opacity; + copySvg.fillOpacity = val.fillOpacity; + copySvg.stroke = val.stroke; + copySvg.strokeDashArray = val.strokeDashArray; + copySvg.strokeDashOffset = val.strokeDashOffset; + copySvg.strokeLineCap = val.strokeLineCap; + copySvg.strokeLineJoin = val.strokeLineJoin; + copySvg.strokeMiterLimit = val.strokeMiterLimit; + copySvg.strokeOpacity = val.strokeOpacity; + copySvg.strokeWidth = val.strokeWidth; + copySvg.translateX = val.translateX; + copySvg.translateY = val.translateY; + copySvg.rotateX = val.rotateX; + copySvg.rotateY = val.rotateY; + copySvg.rotateZ = val.rotateZ; + copySvg.rotateAngle = val.rotateAngle; + copySvg.scaleX = val.scaleX; + copySvg.scaleY = val.scaleY; + return copySvg; + } + + private drawSvg(val: any) { + if (val instanceof ImageSvg) { + let img: ImageBitmap = new ImageBitmap("../../../resources/rawfile/" + val.href); + this.context.drawImage(img, px2vp(val.x), px2vp(val.y), px2vp(Number(val.width)), px2vp(Number(val.height))) + } else if (val instanceof CircleView) { + this.context.beginPath() + this.context.ellipse(px2vp(val.x), px2vp(val.y), px2vp(Number(val.width)), px2vp(Number(val.height)), 0, 0, Math.PI * 2) + } else if (val instanceof EllipseView) { + this.context.beginPath() + this.context.ellipse(px2vp(val.x), px2vp(val.y), px2vp(Number(val.width) / 2), px2vp(Number(val.height) / 2), 0, 0, Math.PI * 2) + } else if (val instanceof LineView) { + this.context.beginPath(); + this.context.moveTo(px2vp(Number(val.startX)), px2vp(Number(val.startY))); + this.context.lineTo(px2vp(Number(val.endX)), px2vp(Number(val.endY))) + } else if (val instanceof PolyLineView) { + this.context.beginPath(); + this.context.moveTo(px2vp(val.pointsResult[0][0]), px2vp(val.pointsResult[0][1])) + val.pointsResult.forEach((val, idx) => { + if (idx > 0) { + this.context.lineTo(px2vp(val[0]), px2vp(val[1])) + } + }) + } else if (val instanceof PolygonView) { + this.context.beginPath(); + this.context.moveTo(px2vp(val.pointsResult[0][0]), px2vp(val.pointsResult[0][1])) + val.pointsResult.forEach((val, idx) => { + if (idx > 0) { + this.context.lineTo(px2vp(val[0]), px2vp(val[1])) + } + }) + } else if (val instanceof RectView) { + this.context.beginPath() + this.context.rect(px2vp(val.x), px2vp(val.y), px2vp(Number(val.width)), px2vp(Number(val.height))) + } else if (val instanceof Use) { + for (let i = 0;i < this.svgs.length; i++) { + if (this.svgs[i].id.trim().indexOf(val.href.replace("#", "").trim()) > -1) { + let svg = this.copy(this.svgs[i]) + if (val.x) { + svg.x = Number(this.svgs[i].x) + Number(val.x) + } + if (val.y) { + svg.y = Number(this.svgs[i].y) + Number(val.y) + } + this.drawSvg(svg) + break + } + } + } else if (val instanceof TextView) { + this.context.font = val.fontSize + " sans-serif"; + } else if (val instanceof Switch) { + let language = configuration.getLocale().language; + for (let i = 0;i < val.child.length; i++) { + if (val.child[i].systemLanguage.trim() == language.trim()) { + this.drawSvg(val.child[i]) + break + } + } + } + + this.context.save(); + if (val.strokeMiterLimit != null) { + this.context.miterLimit = val.strokeMiterLimit; + } + if (val.strokeDashOffset != 0) { + this.context.lineDashOffset = Number(val.strokeDashOffset); + } + if (val.translateX != 0 || val.translateY != 0) { + this.context.translate(px2vp(val.translateX), px2vp(val.translateY)) + } + if (val.scaleX != 1 || val.scaleY != 1) { + this.context.scale(val.scaleX, val.scaleY); + } + if (val.rotateAngle != 0) { + this.context.rotate(val.rotateAngle) + } + if (val.strokeWidth != null && Number(val.strokeWidth.toString().replace("px", "")) > 0) { + this.context.strokeStyle = val.stroke; + this.context.lineWidth = Number(val.strokeWidth.toString().replace("px", "")); + if (val instanceof PathView) { + let path2D: Path2D = new Path2D(val.commands); + this.context.stroke(path2D) + } else if (val instanceof TextView) { + this.context.strokeText(val.text, Number(val.x) + Number(val.dx), Number(val.y) + Number(val.dy)) + } else { + this.context.stroke(); + } + } + if (val.fill != null) { + this.context.fillStyle = val.fill; + if (val instanceof PathView) { + let path2D: Path2D = new Path2D(val.commands); + this.context.fill(path2D); + } else if (val instanceof TextView) { + this.context.fillText(val.text, Number(val.x) + Number(val.dx), Number(val.y) + Number(val.dy)) + } else { + this.context.fill(); + } + } + this.context.restore(); + } + + public getSVGPixelMap(size?:{width:number,height:number}): PixelMap{ + + let setttings: RenderingContextSettings = new RenderingContextSettings(true) + let offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(px2vp(this.svg.viewBoxWidth), px2vp(this.svg.viewBoxHeight),setttings) + + image.createImageSource(null) + this.context = offContext + + // 根据目标大小适配 + let targetCompWidth: number; + let targetCompHeight: number; + if(size){ + targetCompWidth = size.width + targetCompHeight = size.height + }else{ + targetCompWidth = this.deviceW*px2vp(1) + targetCompHeight = this.deviceH*px2vp(1) + } + let minScale = 1; + if(this.svg.viewBoxWidth * px2vp(1) > targetCompWidth || this.svg.viewBoxHeight*px2vp(1)> targetCompHeight){ + let scaleW = targetCompWidth / (this.svg.viewBoxWidth * px2vp(1) *1.0) + let scaleH = targetCompHeight / (this.svg.viewBoxHeight * px2vp(1) *1.0) + minScale = scaleW >= scaleH ? scaleH:scaleW; + this.context.setTransform(minScale,0,0,minScale,0,0) + } + // 缩放之后再绘制 + this.svgs.forEach((val, idx, array) => { + this.drawSvg(val) + }) + let minShowWidth = this.svg.viewBoxWidth * px2vp(1) *minScale; + let minShowHeight = this.svg.viewBoxHeight * px2vp(1) *minScale; + console.log('getPixelMap width ='+minShowWidth+'height='+minShowHeight) + let pix = this.context.getPixelMap(0,0,minShowWidth,minShowHeight) + this.context.clearRect(0, 0, this.svg.viewBoxWidth, this.svg.viewBoxHeight) + return pix + } + +// getMinShowWidth(): number{ +// return px2vp(this.svg.viewBoxWidth < globalThis.deviceW ? this.svg.viewBoxWidth : globalThis.deviceW) +// } +// +// getMinShowHeight(): number{ +// return px2vp(this.svg.viewBoxHeight < globalThis.deviceH ? this.svg.viewBoxHeight : globalThis.deviceH) +// } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets b/imageknife/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets new file mode 100644 index 0000000..d304533 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/svg/SVGParseImpl.ets @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {IParseSvg} from'./IParseSvg' +import {SVGImageView} from '@ohos/svg' +export class SVGParseImpl implements IParseSvg{ + parseSvg(imageinfo: ArrayBuffer,size?:{width:number,height:number}): Promise{ + let model = new SVGImageView.SVGImageViewModel(); + return model.getSVGPixelMap(new Uint8Array(imageinfo),size); + } +} \ No newline at end of file