svg图片解码改为imageSource解码

Signed-off-by: zenggaofeng <zenggaofeng2@h-partners.com>
This commit is contained in:
zenggaofeng 2023-12-27 11:42:14 +08:00
parent 34a121d454
commit 1cc2202522
14 changed files with 105 additions and 94 deletions

View File

@ -1,3 +1,6 @@
## 2.1.2-rc.3
- svg图片解码改为imageSource解码
-
## 2.1.2-rc.2 ## 2.1.2-rc.2
- HSP兼容性优化 - HSP兼容性优化
- 暴露DetachFromLayout接口 - 暴露DetachFromLayout接口

View File

@ -80,7 +80,6 @@ struct Index {
加载svg其实和普通流程没有区别,只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.svgSample'),` 加载svg其实和普通流程没有区别,只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.svgSample'),`
svg类型图片即可。 svg类型图片即可。
目前加载SVG图片解析依赖了 [SVG三方库](https://gitee.com/openharmony-sig/ohos-svg)由于目前该库还无法解析mask标签所以这里大家需要留意一下。
### 4.加载GIF图片 ### 4.加载GIF图片
@ -523,4 +522,44 @@ HSP场景适配:
2.目前svg和gif动图不支持变换效果。 2.目前svg和gif动图不支持变换效果。
3.svg解析目前不支持mask标签。 ## 补充说明
### SVG标签说明
使用版本为(SVG)1.1,当前支持的标签列表有:
- a
- circla
- clipPath
- defs
- ellipse
- feBlend
- feColorMatrix
- feComposite
- feDiffuseLighting
- feDisplacementMap
- feDistantLight
- feFlood
- feGaussianBlur
- feImage
- feMorphology
- feOffset
- fePointLight
- feSpecularLighting
- feSpotLight
- feTurbulence
- filter
- g
- image
- line
- linearGradient
- mask
- path
- pattern
- polygon
- polyline
- radialGradient
- rect
- stop
- svg
- text
- textPath
- tspan
- use

View File

@ -4,7 +4,7 @@
"name": "entry", "name": "entry",
"description": "example description", "description": "example description",
"repository": {}, "repository": {},
"version": "2.1.2-rc.2", "version": "2.1.2-rc.3",
"dependencies": { "dependencies": {
"@ohos/libraryimageknife": "file:../sharedlibrary", "@ohos/libraryimageknife": "file:../sharedlibrary",
"@ohos/disklrucache": "^2.0.2-rc.0", "@ohos/disklrucache": "^2.0.2-rc.0",

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {SVGParseImpl} from '@ohos/libraryimageknife' import {SVGParseImpl} from '@ohos/libraryimageknife'
import {ImageKnifeGlobal} from '@ohos/libraryimageknife' import { ImageKnifeComponent } from '@ohos/libraryimageknife'
import resourceManager from '@ohos.resourceManager'; import resourceManager from '@ohos.resourceManager';
import {BusinessError} from '@ohos.base' import {BusinessError} from '@ohos.base'
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
@ -21,8 +21,8 @@ import common from '@ohos.app.ability.common';
@Component @Component
struct svgTestCasePage { struct svgTestCasePage {
@State svgSamplePixelMap?:PixelMap = undefined @State svgSamplePixelMap?: Resource = undefined
@State svgIconPixelMap?:PixelMap = undefined @State svgIconPixelMap?: Resource = undefined
build() { build() {
Scroll() { Scroll() {
@ -30,20 +30,7 @@ struct svgTestCasePage {
Flex({direction:FlexDirection.Row}){ Flex({direction:FlexDirection.Row}){
Button("加载SVG图片") Button("加载SVG图片")
.onClick(()=>{ .onClick(()=>{
this.svgSamplePixelMap = $r('app.media.svgSample')
((ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).resourceManager as resourceManager.ResourceManager)
.getMediaContent($r('app.media.svgSample').id)
.then((data:Uint8Array) => {
console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data)
let svgImpl = new SVGParseImpl();
svgImpl.parseSvg(data.buffer).then((pixelmap)=>{
this.svgSamplePixelMap = pixelmap;
})
})
.catch((err:BusinessError) => {
console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err));
})
}).margin({left:5}).backgroundColor(Color.Blue) }).margin({left:5}).backgroundColor(Color.Blue)
} }
@ -51,7 +38,9 @@ struct svgTestCasePage {
Text("下面为展示图片区域").margin({top:5}) Text("下面为展示图片区域").margin({top:5})
Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){
Image(this.svgSamplePixelMap == undefined ? '':this.svgSamplePixelMap!) ImageKnifeComponent({imageKnifeOption:{
loadSrc:this.svgSamplePixelMap as Resource
}})
.width(400) .width(400)
.height(400) .height(400)
.backgroundColor(Color.Pink) .backgroundColor(Color.Pink)
@ -60,20 +49,7 @@ struct svgTestCasePage {
Flex({direction:FlexDirection.Row}){ Flex({direction:FlexDirection.Row}){
Button("加载SVG图片") Button("加载SVG图片")
.onClick(()=>{ .onClick(()=>{
this.svgIconPixelMap = $r('app.media.iconsvg')
((ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).resourceManager as resourceManager.ResourceManager)
.getMediaContent($r('app.media.iconsvg').id)
.then(data => {
console.log('basicTestFileIOPage - 本地加载资源 解析后数据data = ' + data)
let svgImpl = new SVGParseImpl();
svgImpl.parseSvg(data.buffer).then((pixelmap)=>{
this.svgIconPixelMap = pixelmap;
})
})
.catch((err:BusinessError) => {
console.log('basicTestFileIOPage - 本地加载资源err' + JSON.stringify(err));
})
}).margin({left:5}).backgroundColor(Color.Blue) }).margin({left:5}).backgroundColor(Color.Blue)
} }
@ -81,7 +57,9 @@ struct svgTestCasePage {
Text("下面为展示图片区域").margin({top:5}) Text("下面为展示图片区域").margin({top:5})
Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){ Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }){
Image(this.svgIconPixelMap == undefined ? '':this.svgIconPixelMap!) ImageKnifeComponent({imageKnifeOption:{
loadSrc:this.svgIconPixelMap as Resource
}})
.width(400) .width(400)
.height(400) .height(400)
.backgroundColor(Color.Pink) .backgroundColor(Color.Pink)

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="ic_launcher_round.css" ?> <?xml-stylesheet type="text/css" href="ic_launcher_round.css" ?>
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 800 800" xml:space="preserve"> viewBox="0 0 800 800" xml:space="preserve" width="200" height="200">
<rect class="brick4" width="800" height="800.5" fill="#6A6ACC"/> <rect class="brick4" width="800" height="800.5" fill="#6A6ACC"/>
<g fill="#55346A"> <g fill="#55346A">
<path d="M242.4,800.6c-0.2-0.9-0.3-1.9-0.5-2.8c-0.2-0.8-0.3-1.7-0.5-2.5c-0.5-2.5-1.1-5-1.7-7.5l0,0 <path d="M242.4,800.6c-0.2-0.9-0.3-1.9-0.5-2.8c-0.2-0.8-0.3-1.7-0.5-2.5c-0.5-2.5-1.1-5-1.7-7.5l0,0

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -14,11 +14,10 @@
"main": "index.ets", "main": "index.ets",
"repository": "https://gitee.com/openharmony-tpc/ImageKnife", "repository": "https://gitee.com/openharmony-tpc/ImageKnife",
"type": "module", "type": "module",
"version": "2.1.2-rc.2", "version": "2.1.2-rc.3",
"dependencies": { "dependencies": {
"pako": "^2.1.0", "pako": "^2.1.0",
"@ohos/disklrucache": "^2.0.2-rc.0", "@ohos/disklrucache": "^2.0.2-rc.0",
"@ohos/svg": "^2.1.1-rc.0",
"@ohos/gpu_transform": "^1.0.0" "@ohos/gpu_transform": "^1.0.0"
}, },
"tags": [ "tags": [

View File

@ -15,7 +15,6 @@
import { GIFFrame } from './utils/gif/GIFFrame' import { GIFFrame } from './utils/gif/GIFFrame'
import { DetachFromLayout } from './RequestOption' import { DetachFromLayout } from './RequestOption'
import { LogUtil } from './utils/LogUtil' import { LogUtil } from './utils/LogUtil'
import { Ellipse2 } from '@ohos/svg/src/main/ets/components/utils/SVGBase'
export enum ImageKnifeType { export enum ImageKnifeType {
PIXELMAP = 'PixelMap', PIXELMAP = 'PixelMap',

View File

@ -91,13 +91,7 @@ export class ErrorHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl:SVGParseImpl = new SVGParseImpl() let svgParseImpl:SVGParseImpl = new SVGParseImpl()
let size:Size = { width: this.options.size.width, height: this.options.size.height } svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
svgParseImpl.parseSvg(arraybuffer, size).then((value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData)
}).catch((err:BusinessError) => {
onError(err)
})
} }
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {

View File

@ -89,13 +89,7 @@ export class PlaceHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl:SVGParseImpl = new SVGParseImpl() let svgParseImpl:SVGParseImpl = new SVGParseImpl()
let size:Size = { width: this.options.size.width, height: this.options.size.height } svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
svgParseImpl.parseSvg(arraybuffer, size).then((value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData)
}).catch((err:BusinessError) => {
onError(err)
})
} }
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {

View File

@ -89,13 +89,7 @@ export class RetryHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl = new SVGParseImpl() let svgParseImpl = new SVGParseImpl()
let size:Size = { width: this.options.size.width, height: this.options.size.height } svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
svgParseImpl.parseSvg(arraybuffer, size).then((value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData)
}).catch( (err:BusinessError) => {
onError(err)
})
} }
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {

View File

@ -189,7 +189,7 @@ export class RequestManager {
// 加载网络资源 // 加载网络资源
private loadSourceFromNetwork(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private loadSourceFromNetwork(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
let success = (arraybuffer:ArrayBuffer) => { let success = (arraybuffer:ArrayBuffer) => {
this.downloadSuccess(arraybuffer, onComplete, onError) this.downloadSuccess(request,arraybuffer, onComplete, onError)
} }
let error = (errorMsg:string) =>{ let error = (errorMsg:string) =>{
onError(errorMsg) onError(errorMsg)
@ -214,7 +214,7 @@ export class RequestManager {
}) })
}else if(ImageKnifeData.SVG == typeValue){ }else if(ImageKnifeData.SVG == typeValue){
// 处理svg // 处理svg
this.svgProcess(onComplete,onError,arrayBuffer,typeValue,(imageKnifeData)=>{ this.svgProcess(request,onComplete,onError,arrayBuffer,typeValue,(imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey,imageKnifeData) this.mMemoryCacheProxy.putValue(this.options.generateCacheKey,imageKnifeData)
}) })
} else { } else {
@ -318,7 +318,7 @@ export class RequestManager {
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData) this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
}) })
}else if(ImageKnifeData.SVG == typeValue){ }else if(ImageKnifeData.SVG == typeValue){
this.svgProcess(onComplete,onError, source, typeValue, (imageKnifeData)=>{ this.svgProcess(request,onComplete,onError, source, typeValue, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData) this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
}) })
} else { } else {
@ -433,7 +433,7 @@ export class RequestManager {
} }
} }
private downloadSuccess(source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private downloadSuccess(request: RequestOption,source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log('Download task completed.'); LogUtil.log('Download task completed.');
if(source == null || source == undefined || source.byteLength <= 0){ if(source == null || source == undefined || source.byteLength <= 0){
@ -474,7 +474,7 @@ export class RequestManager {
}) })
}else if(ImageKnifeData.SVG == filetype){ }else if(ImageKnifeData.SVG == filetype){
// 处理svg // 处理svg
this.svgProcess(onComplete,onError, source, filetype, (imageKnifeData)=>{ this.svgProcess(request,onComplete,onError, source, filetype, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData) this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
}) })
@ -596,18 +596,9 @@ export class RequestManager {
}}) }})
}, this.options.thumbDelayTime) }, this.options.thumbDelayTime)
} }
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) { private svgProcess(option: RequestOption,onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
let svgParseImpl = new SVGParseImpl() let svgParseImpl = new SVGParseImpl()
let size:Size = { width: this.options.size.width, height: this.options.size.height } svgParseImpl.parseSvg(option,arraybuffer, onComplete,onError)
svgParseImpl.parseSvg(arraybuffer, size).then((value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
if(cacheStrategy){
cacheStrategy(imageKnifeData)
}
onComplete(imageKnifeData)
}).catch((err:BusinessError) => {
onError(err)
})
} }
private gifProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) { private gifProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {

View File

@ -12,8 +12,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import {Size} from '../../RequestOption' import { RequestOption } from '../../RequestOption'
import { BusinessError } from '@ohos.base'
import { ImageKnifeData } from '../../ImageKnifeData'
export interface IParseSvg { export interface IParseSvg {
// 解析svg // 解析svg
parseSvg:(imageinfo: ArrayBuffer,size?:Size)=> Promise<PixelMap> parseSvg:(option: RequestOption, imageInfo: ArrayBuffer | ArrayBufferLike,
onComplete: (value: ImageKnifeData) => void | PromiseLike<ImageKnifeData>,
onErrorFunction: (reason?: BusinessError | string) => void)=> void
} }

View File

@ -12,20 +12,35 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import {IParseSvg} from'./IParseSvg' import { IParseSvg } from './IParseSvg'
import {SVGImageView} from '@ohos/svg' import { RequestOption } from '../../RequestOption'
import {Size} from '../../RequestOption' import { BusinessError } from '@ohos.base'
import { ImageKnifeData, ImageKnifeType } from '../../ImageKnifeData'
import image from '@ohos.multimedia.image'
export class SVGParseImpl implements IParseSvg{ export class SVGParseImpl implements IParseSvg {
parseSvg(imageinfo: ArrayBuffer | ArrayBufferLike,size?:Size): Promise<PixelMap>{ parseSvg(option: RequestOption, imageInfo: ArrayBuffer,
let model = new SVGImageView.SVGImageViewModel(); onComplete: (value: ImageKnifeData) => void | PromiseLike<ImageKnifeData>,
let svgSize:SVGImageView.Size = new SVGImageView.Size(); onErrorFunction: (reason?: BusinessError | string) => void) {
svgSize.width = 0;
svgSize.height = 0; let imageSource: image.ImageSource = image.createImageSource(imageInfo); // 步骤一文件转为pixelMap 然后变换 给Image组件
if(size != undefined){ let hValue = Math.round(option.size.height);
svgSize.width = size.width; let wValue = Math.round(option.size.width);
svgSize.height = size.height; let defaultSize: image.Size = {
} height: hValue,
return model.getSVGPixelMap(new Uint8Array(imageinfo),svgSize); width: wValue
};
let opts: image.DecodingOptions = {
editable: true,
desiredSize: defaultSize
};
imageSource.createPixelMap(opts).then((pixelMap: image.PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap)
onComplete(imageKnifeData);
imageSource.release()
}).catch((err: string) => {
onErrorFunction(err);
imageSource.release()
})
} }
} }

View File

@ -6,6 +6,6 @@
"name": "imageknife", "name": "imageknife",
"description": "example description", "description": "example description",
"repository": {}, "repository": {},
"version": "2.1.2-rc.2", "version": "2.1.2-rc.3",
"dependencies": {} "dependencies": {}
} }