1.重构imageknife整个渲染层
a.重构ImageKnifeComponent b.重构ImageOption c.抽象绘制生命周期 Signed-off-by: zhoulisheng1 <zhoulisheng1@huawei.com>
This commit is contained in:
parent
c1c3ce210f
commit
7cf9a129e9
|
@ -19,6 +19,7 @@ import {EngineKeyFactories} from "../cache/key/EngineKeyFactories"
|
|||
import {RequestOption} from "../imageknife/RequestOption"
|
||||
import {AsyncCallback} from "../imageknife/interface/asynccallback"
|
||||
import {PlaceHolderManager} from "../imageknife/holder/PlaceHolderManager"
|
||||
import {RetryHolderManager} from "../imageknife/holder/RetryHolderManager"
|
||||
import {ErrorHolderManager} from "../imageknife/holder/ErrorHolderManager"
|
||||
import {RequestManager} from "../imageknife/requestmanage/RequstManager"
|
||||
import {NONE} from "../cache/diskstrategy/enum/NONE"
|
||||
|
@ -27,12 +28,12 @@ import {DownloadClient} from '../imageknife/networkmanage/DownloadClient'
|
|||
import {IDataFetch} from '../imageknife/networkmanage/IDataFetch'
|
||||
import {ParseResClient} from '../imageknife/resourcemanage/ParseResClient'
|
||||
import {IResourceFetch} from '../imageknife/resourcemanage/IResourceFetch'
|
||||
import {ImageKnifeData} from '../imageknife/ImageKnifeData'
|
||||
import {ImageKnifeData,ImageKnifeType} from '../imageknife/ImageKnifeData'
|
||||
import {FileUtils} from '../cache/FileUtils'
|
||||
import {FileReader} from '../cache/FileReader'
|
||||
import image from "@ohos.multimedia.image"
|
||||
import featureAbility from '@ohos.ability.featureAbility';
|
||||
import {CompressBuilder} from "../imageknife/compress/CompressBuilder"
|
||||
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
|
||||
|
||||
export class ImageKnife {
|
||||
static readonly SEPARATOR: string = '/'
|
||||
|
@ -49,11 +50,15 @@ export class ImageKnife {
|
|||
private pendingRequest: Array<RequestOption>;
|
||||
private fileTypeUtil: FileTypeUtil; // 通用文件格式辨别
|
||||
private diskCacheFolder: string = "ImageKnifeDiskCache"
|
||||
private svgAndGifFolder: string = "svgAndGifFolder"; // svg和gif的文件路径地址
|
||||
private svgAndGifCommitFile: string = "svgAndGifCommitFile" // svg和gif提交记录
|
||||
|
||||
|
||||
private defaultListener: AsyncCallback<ImageKnifeData>; // 全局监听器
|
||||
|
||||
// gifWorker
|
||||
private gifWorker;
|
||||
|
||||
private defaultLifeCycle: IDrawLifeCycle;
|
||||
|
||||
private constructor(imgCtx) {
|
||||
this.imageKnifeContext = imgCtx;
|
||||
|
||||
|
@ -71,7 +76,6 @@ export class ImageKnife {
|
|||
|
||||
// 初始化本地 文件保存
|
||||
this.filesPath = this.imageKnifeContext.filesDir;
|
||||
this.initSvgAndGifEnvironment();
|
||||
|
||||
this.runningRequest = new Array();
|
||||
this.pendingRequest = new Array();
|
||||
|
@ -103,16 +107,6 @@ export class ImageKnife {
|
|||
return this.fileTypeUtil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getSvgAndGifFolder(): string{
|
||||
return this.svgAndGifFolder;
|
||||
}
|
||||
|
||||
setSvgAndGifFolder(folderPath: string){
|
||||
this.svgAndGifFolder = folderPath;
|
||||
}
|
||||
|
||||
getImageKnifeContext() {
|
||||
return this.imageKnifeContext;
|
||||
}
|
||||
|
@ -125,31 +119,21 @@ export class ImageKnife {
|
|||
return this.defaultListener;
|
||||
}
|
||||
|
||||
private initSvgAndGifEnvironment() {
|
||||
let folderExist = FileUtils.getInstance().existFolder(this.filesPath + "/" + this.svgAndGifFolder)
|
||||
let fileExist =
|
||||
FileUtils.getInstance()
|
||||
.exist(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile)
|
||||
if (folderExist && fileExist) {
|
||||
// 创建完成,需要删除上次使用的文件
|
||||
var fileReader = new FileReader(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile)
|
||||
var line: string = ''
|
||||
while (!fileReader.isEnd()) {
|
||||
line = fileReader.readLine()
|
||||
line = line.replace('\n', "").replace('\r', "")
|
||||
FileUtils.getInstance().deleteFile(this.filesPath + "/" + this.svgAndGifFolder + "/" + line)
|
||||
}
|
||||
FileUtils.getInstance().clearFile(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile)
|
||||
} else {
|
||||
if (!folderExist) {
|
||||
FileUtils.getInstance().createFolder(this.filesPath + "/" + this.svgAndGifFolder);
|
||||
}
|
||||
if (!fileExist) {
|
||||
FileUtils.getInstance().createFile(this.filesPath + "/" + this.svgAndGifFolder + "/" + this.svgAndGifCommitFile)
|
||||
}
|
||||
}
|
||||
|
||||
setGifWorker(worker){
|
||||
this.gifWorker = worker
|
||||
}
|
||||
getGifWorker(){
|
||||
return this.gifWorker;
|
||||
}
|
||||
|
||||
getDefaultLifeCycle(){
|
||||
return this.defaultLifeCycle;
|
||||
}
|
||||
|
||||
setDefaultLifeCycle(viewLifeCycle:IDrawLifeCycle){
|
||||
this.defaultLifeCycle = viewLifeCycle;
|
||||
}
|
||||
|
||||
|
||||
private static sInstance: ImageKnife;
|
||||
|
||||
|
@ -195,9 +179,7 @@ export class ImageKnife {
|
|||
preload(request: RequestOption) {
|
||||
// 每个request 公共信息补充
|
||||
request.setFilesPath(this.filesPath);
|
||||
// svg特殊处理
|
||||
request._svgAndGifFolder = this.svgAndGifFolder;
|
||||
request._svgAndGifCommitFile = this.svgAndGifCommitFile;
|
||||
|
||||
return this.parseSource(request);
|
||||
}
|
||||
|
||||
|
@ -211,16 +193,16 @@ export class ImageKnife {
|
|||
// 每个request 公共信息补充
|
||||
request.setFilesPath(this.filesPath);
|
||||
|
||||
// svg特殊处理
|
||||
request._svgAndGifFolder = this.svgAndGifFolder;
|
||||
request._svgAndGifCommitFile = this.svgAndGifCommitFile;
|
||||
|
||||
// 首先执行占位图 解析任务
|
||||
if (request.placeholderSrc) {
|
||||
PlaceHolderManager.execute(request)
|
||||
}
|
||||
// 其次执行重试占位图 解析任务
|
||||
if (request.retryholderSrc) {
|
||||
RetryHolderManager.execute(request)
|
||||
}
|
||||
|
||||
// 其次解析错误占位图
|
||||
// 最后解析错误占位图
|
||||
if (request.errorholderSrc) {
|
||||
ErrorHolderManager.execute(request)
|
||||
}
|
||||
|
@ -374,9 +356,7 @@ export class ImageKnife {
|
|||
|
||||
parseSource(request: RequestOption) {
|
||||
if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') {
|
||||
let imageKnifeData = new ImageKnifeData();
|
||||
imageKnifeData.imageKnifeType = ImageKnifeData.PIXELMAP
|
||||
imageKnifeData.imageKnifeValue = request.loadSrc as PixelMap
|
||||
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, request.loadSrc as PixelMap)
|
||||
request.loadComplete(imageKnifeData);
|
||||
} else
|
||||
if (typeof request.loadSrc == 'string') {
|
||||
|
|
|
@ -13,98 +13,176 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {ImageKnifeOption} from '../imageknife/ImageKnifeOption'
|
||||
import {TransformType} from '../imageknife/transform/TransformType'
|
||||
import {RequestOption} from '../imageknife/RequestOption'
|
||||
import {ImageKnifeData} from '../imageknife/ImageKnifeData'
|
||||
import {PixelMapPack} from '../imageknife/PixelMapPack'
|
||||
import { ImageKnifeOption } from '../imageknife/ImageKnifeOption'
|
||||
import { TransformType } from '../imageknife/transform/TransformType'
|
||||
import { RequestOption } from '../imageknife/RequestOption'
|
||||
import { ImageKnifeData } from '../imageknife/ImageKnifeData'
|
||||
import { GIFFrame } from '../imageknife/utils/gif/GIFFrame'
|
||||
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
|
||||
|
||||
|
||||
@Component
|
||||
export struct ImageKnifeComponent {
|
||||
@Watch('watchImageKnifeOption') @Link imageKnifeOption: ImageKnifeOption;
|
||||
@State imageKnifePixelMapPack: PixelMapPack = new PixelMapPack();
|
||||
@State imageKnifeResource: Resource = undefined
|
||||
@State imageKnifeString: string = ''
|
||||
@State normalPixelMap: boolean = false;
|
||||
@State normalResource: boolean = true;
|
||||
previousData: ImageKnifeData = null;
|
||||
nowData: ImageKnifeData = null;
|
||||
@State percentVisible: Visibility = Visibility.Visible
|
||||
@State retryVisible: Visibility = Visibility.Visible
|
||||
@State imageVisible: Visibility = Visibility.Visible
|
||||
@State percent: string = '0%'
|
||||
@State percentWidth: string = '0%';
|
||||
@State percentHeight: string = '0%';
|
||||
@State retryWidth: string = '0%';
|
||||
@State retryHeight: string = '0%';
|
||||
@State imageWidth: string = '100%';
|
||||
@State imageHeight: string = '100%';
|
||||
|
||||
@State imageKnifeRetry: Resource = undefined;
|
||||
// 有效onAreaChanged触发计数
|
||||
private onAreaCount:number = 0
|
||||
|
||||
hasRetry:boolean = false;
|
||||
@State componentWidth: string = '100%'
|
||||
@State componentHeight: string = '100%'
|
||||
|
||||
@State gifPixelMap:PixelMap = undefined;
|
||||
|
||||
drawLifeCycle: IDrawLifeCycle
|
||||
autoPlay = true
|
||||
private preSize: {
|
||||
width: string,
|
||||
height: string
|
||||
} = { width: '0', height: '0' }
|
||||
private settings: RenderingContextSettings = new RenderingContextSettings(true)
|
||||
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
|
||||
private hasDisplayRetryholder = false;
|
||||
private currentWidth: number = 0
|
||||
private currentHeight: number = 0
|
||||
|
||||
// 定时器id
|
||||
private gifTimerId: number = 0
|
||||
// 完整gif播放时间
|
||||
private gifLoopDuration: number = 0
|
||||
private startGifLoopTime: number = 0
|
||||
private endGifLoopTime: number = 0
|
||||
defaultLifeCycle: IDrawLifeCycle = {
|
||||
|
||||
// 展示占位图
|
||||
displayPlaceholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawPlaceholder(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
return true;
|
||||
},
|
||||
// 展示加载进度
|
||||
displayProgress: (context: CanvasRenderingContext2D, progress: number, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawProgress(context, progress, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
return true;
|
||||
},
|
||||
// 展示缩略图
|
||||
displayThumbSizeMultiplier: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawThumbSizeMultiplier(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
return true;
|
||||
},
|
||||
|
||||
// 展示主图
|
||||
displayMainSource: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawMainSource(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
return true;
|
||||
},
|
||||
|
||||
// 展示重试图层
|
||||
displayRetryholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawRetryholder(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
return true;
|
||||
},
|
||||
|
||||
// 展示失败占位图
|
||||
displayErrorholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawErrorholder(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
|
||||
Text(this.percent)
|
||||
.fontSize(this.imageKnifeOption.size ? Math.min(this.imageKnifeOption.size.height, this.imageKnifeOption.size.width) / 2 : 24)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.visibility(this.retryVisible)
|
||||
.width(this.percentWidth)
|
||||
.height(this.percentHeight)
|
||||
|
||||
Image(this.imageKnifeRetry)
|
||||
.onClick(()=>{
|
||||
this.retryClick();
|
||||
})
|
||||
.visibility(this.retryVisible)
|
||||
.width(this.retryWidth)
|
||||
.height(this.retryHeight)
|
||||
|
||||
|
||||
|
||||
Image(this.normalPixelMap ? this.imageKnifePixelMapPack.pixelMap : (this.normalResource ? this.imageKnifeResource : this.imageKnifeString))
|
||||
.objectFit(this.imageKnifeOption.imageFit ? this.imageKnifeOption.imageFit : ImageFit.Fill)
|
||||
.visibility(this.imageVisible)
|
||||
.width(this.imageWidth)
|
||||
.height(this.imageHeight)
|
||||
}
|
||||
.width(this.imageKnifeOption.size ? this.imageKnifeOption.size.width : '100%')
|
||||
.height(this.imageKnifeOption.size ? this.imageKnifeOption.size.height : '100%')
|
||||
.backgroundColor(this.imageKnifeOption.backgroundColor ? this.imageKnifeOption.backgroundColor : Color.White)
|
||||
.margin(this.imageKnifeOption.margin ? this.imageKnifeOption.margin : { left: 0, top: 0, right: 0, bottom: 0 })
|
||||
Canvas(this.context)
|
||||
.width(this.componentWidth)
|
||||
.height(this.componentHeight)
|
||||
.onAreaChange((oldValue: Area, newValue: Area) => {
|
||||
this.currentWidth = newValue.width as number
|
||||
this.currentHeight = newValue.height as number
|
||||
console.log('onAreaChange stack currentWidth =' + this.currentWidth + ' currentHeight=' + this.currentHeight)
|
||||
if (this.onAreaCount > 0) {
|
||||
this.onAreaCount--;
|
||||
this.imageKnifeExecute()
|
||||
}
|
||||
})
|
||||
.backgroundColor(this.imageKnifeOption.backgroundColor ? this.imageKnifeOption.backgroundColor : Color.White)
|
||||
.margin(this.imageKnifeOption.margin ? this.imageKnifeOption.margin : { left: 0, top: 0, right: 0, bottom: 0 })
|
||||
.onReady(() => {
|
||||
})
|
||||
.onClick(() => {
|
||||
if (this.imageKnifeOption.canRetryClick && this.hasDisplayRetryholder) {
|
||||
this.retryClick()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watchImageKnifeOption() {
|
||||
this.imageKnifeExecute();
|
||||
console.log('watchImageKnifeOption is happened!')
|
||||
|
||||
if (this.imageKnifeOption.sizeAnimate) {
|
||||
animateTo(this.imageKnifeOption.sizeAnimate, () => {
|
||||
this.resetGifData();
|
||||
this.whetherWaitSize();
|
||||
})
|
||||
} else {
|
||||
this.resetGifData();
|
||||
this.whetherWaitSize();
|
||||
}
|
||||
}
|
||||
whetherWaitSize(){
|
||||
this.componentWidth = this.imageKnifeOption.size.width
|
||||
this.componentHeight = this.imageKnifeOption.size.height
|
||||
if(this.newSizeEqualPreSize(this.imageKnifeOption.size)){
|
||||
console.log('whetherWaitSize 宽高不变 直接发送请求')
|
||||
this.imageKnifeExecute()
|
||||
}else{
|
||||
this.onAreaCount ++;
|
||||
// waitSize changed
|
||||
this.preSize = this.imageKnifeOption.size
|
||||
console.log('whetherWaitSize 宽高改变 等待组件回调onAreaChange后发送请求')
|
||||
}
|
||||
}
|
||||
|
||||
retryClick(){
|
||||
this.hasRetry = true;
|
||||
newSizeEqualPreSize(newSize:{width: string, height: string}):boolean{
|
||||
if(this.preSize.width == newSize.width && this.preSize.height == newSize.height){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
retryClick() {
|
||||
this.hasDisplayRetryholder = false;
|
||||
this.imageKnifeExecute();
|
||||
}
|
||||
|
||||
aboutToAppear() {
|
||||
console.log('imageKnifeComponent aboutToAppear happened!')
|
||||
this.imageKnifeExecute();
|
||||
this.onAreaCount ++;
|
||||
this.componentWidth = this.imageKnifeOption.size.width
|
||||
this.componentHeight = this.imageKnifeOption.size.height
|
||||
}
|
||||
|
||||
configNecessary(request: RequestOption){
|
||||
configNecessary(request: RequestOption) {
|
||||
request.load(this.imageKnifeOption.loadSrc)
|
||||
.addListener((err, data) => {
|
||||
console.log('request.load callback')
|
||||
this.imageKnifeChangeSource(data)
|
||||
this.animateTo('image');
|
||||
return false;
|
||||
})
|
||||
.addListener((err, data) => {
|
||||
console.log('request.load callback')
|
||||
this.displayMainSource(data)
|
||||
return false;
|
||||
})
|
||||
|
||||
if (this.imageKnifeOption.size) {
|
||||
request.setImageViewSize(this.imageKnifeOption.size)
|
||||
let realSize = {
|
||||
width: this.currentWidth,
|
||||
height:this.currentHeight
|
||||
}
|
||||
request.setImageViewSize(realSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configCacheStrategy(request: RequestOption){
|
||||
configCacheStrategy(request: RequestOption) {
|
||||
if (this.imageKnifeOption.onlyRetrieveFromCache) {
|
||||
request.retrieveDataFromCache(this.imageKnifeOption.onlyRetrieveFromCache)
|
||||
}
|
||||
|
@ -119,36 +197,30 @@ export struct ImageKnifeComponent {
|
|||
if (this.imageKnifeOption.allCacheInfoCallback) {
|
||||
request.addAllCacheInfoCallback(this.imageKnifeOption.allCacheInfoCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configDisplay(request: RequestOption){
|
||||
if(this.imageKnifeOption.animateDuration >= 0){
|
||||
request.animateDuration = this.imageKnifeOption.animateDuration;
|
||||
}
|
||||
configDisplay(request: RequestOption) {
|
||||
if (this.imageKnifeOption.placeholderSrc) {
|
||||
request.placeholder(this.imageKnifeOption.placeholderSrc, (data) => {
|
||||
console.log('request.placeholder callback')
|
||||
this.imageKnifeChangeSource(data)
|
||||
this.animateTo('image');
|
||||
this.displayPlaceholder(data)
|
||||
|
||||
})
|
||||
}
|
||||
if (this.imageKnifeOption.thumbSizeMultiplier) {
|
||||
request.thumbnail(this.imageKnifeOption.thumbSizeMultiplier, (data) => {
|
||||
console.log('request.thumbnail callback')
|
||||
this.imageKnifeChangeSource(data)
|
||||
this.animateTo('image');
|
||||
})
|
||||
this.displayThumbSizeMultiplier(data)
|
||||
}, this.imageKnifeOption.thumbSizeDelay)
|
||||
}
|
||||
if (this.imageKnifeOption.errorholderSrc) {
|
||||
request.errorholder(this.imageKnifeOption.errorholderSrc, (data) => {
|
||||
console.log('request.errorholder callback')
|
||||
this.imageKnifeChangeSource(data)
|
||||
this.animateTo('image');
|
||||
this.displayErrorholder(data)
|
||||
|
||||
})
|
||||
}
|
||||
if (this.imageKnifeOption.retryholderSrc) {
|
||||
this.imageKnifeRetry = this.imageKnifeOption.retryholderSrc
|
||||
}
|
||||
|
||||
if (this.imageKnifeOption.transform) {
|
||||
this.requestAddTransform(request)
|
||||
}
|
||||
|
@ -164,164 +236,301 @@ export struct ImageKnifeComponent {
|
|||
|
||||
|
||||
if (this.imageKnifeOption.displayProgress) {
|
||||
request.addProgressListener((percentValue: string) => {
|
||||
request.addProgressListener((percentValue: number) => {
|
||||
// 如果进度条百分比 未展示大小,展示其动画
|
||||
this.percent = percentValue;
|
||||
if(this.imageKnifeOption.displayProgressListener){
|
||||
this.imageKnifeOption.displayProgressListener(percentValue);
|
||||
}
|
||||
this.animateTo('progress');
|
||||
this.displayProgress(percentValue)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
if(this.imageKnifeOption.retryLoad){
|
||||
request.addRetryListener((error: any) => {
|
||||
if (this.imageKnifeOption.retryholderSrc) {
|
||||
request.retryholder(this.imageKnifeOption.retryholderSrc, (data) => {
|
||||
console.log("RetryListener callback!")
|
||||
this.animateTo('retry');
|
||||
this.hasDisplayRetryholder = true
|
||||
this.displayRetryholder(data)
|
||||
})
|
||||
}
|
||||
}
|
||||
// imageknife 第一次启动和数据刷新后重新发送请求
|
||||
imageKnifeExecute() {
|
||||
let request = new RequestOption();
|
||||
this.configNecessary(request);
|
||||
this.configCacheStrategy(request);
|
||||
this.configDisplay(request);
|
||||
let request = new RequestOption();
|
||||
this.configNecessary(request);
|
||||
this.configCacheStrategy(request);
|
||||
this.configDisplay(request);
|
||||
globalThis.ImageKnife.call(request);
|
||||
}
|
||||
|
||||
imageKnifeChangeSource(data:ImageKnifeData) {
|
||||
this.imageKnifeSpecialFixed(data);
|
||||
}
|
||||
displayPlaceholder(data: ImageKnifeData) {
|
||||
|
||||
displayPixelMap(data:ImageKnifeData){
|
||||
console.log('displayPixelMap start')
|
||||
let pixelMapPack2 = new PixelMapPack();
|
||||
pixelMapPack2.pixelMap = data.imageKnifeValue as PixelMap;
|
||||
this.imageKnifePixelMapPack = pixelMapPack2;
|
||||
this.normalPixelMap = true;
|
||||
this.normalResource = true;
|
||||
console.log('displayPixelMap end')
|
||||
}
|
||||
|
||||
displayResource(data:ImageKnifeData){
|
||||
console.log('displayResource start')
|
||||
this.imageKnifeResource = data.imageKnifeValue as Resource;
|
||||
this.normalPixelMap = false;
|
||||
this.normalResource = true;
|
||||
console.log('displayResource end')
|
||||
}
|
||||
|
||||
displayString(data:ImageKnifeData){
|
||||
console.log('displayString start')
|
||||
let imageKnifeNeedStr = 'file://' + data.imageKnifeValue;
|
||||
console.log('imageKnifeNeedStr='+imageKnifeNeedStr)
|
||||
this.imageKnifeString = imageKnifeNeedStr;
|
||||
this.normalPixelMap = false;
|
||||
this.normalResource = false;
|
||||
console.log('displayString end')
|
||||
}
|
||||
imageKnifeSpecialFixed(data:ImageKnifeData) {
|
||||
if (data.isPixelMap()) {
|
||||
this.displayPixelMap(data);
|
||||
}
|
||||
else if (data.isString()) {
|
||||
this.displayString(data);
|
||||
} else if (data.isResource()) {
|
||||
this.displayResource(data);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
animateTo(name: string) {
|
||||
if (name == 'progress') {
|
||||
this.percentVisible = Visibility.Visible;
|
||||
this.imageVisible = Visibility.Hidden;
|
||||
this.retryVisible = Visibility.Hidden;
|
||||
if (this.percentWidth == '0%' || this.percentHeight == '0%') {
|
||||
animateTo({ duration: this.imageKnifeOption.animateDuration , curve: Curve.Linear }, () => {
|
||||
this.percentWidth = '100%';
|
||||
this.percentHeight = '100%';
|
||||
this.imageWidth = '0%';
|
||||
this.imageHeight = '0%';
|
||||
this.retryWidth = '0%';
|
||||
this.retryHeight = '0%';
|
||||
})
|
||||
}
|
||||
} else if (name == 'image') {
|
||||
this.imageVisible = Visibility.Visible;
|
||||
this.percentVisible = Visibility.Hidden;
|
||||
this.retryVisible = Visibility.Hidden;
|
||||
if (this.imageWidth == '0%' || this.imageHeight == '0%') {
|
||||
animateTo({ duration: this.imageKnifeOption.animateDuration, curve: Curve.Linear }, () => {
|
||||
this.imageWidth = '100%';
|
||||
this.imageHeight = '100%';
|
||||
this.percentWidth = '0%';
|
||||
this.percentHeight = '0%';
|
||||
this.retryWidth = '0%';
|
||||
this.retryHeight = '0%';
|
||||
})
|
||||
}
|
||||
} else if (name == 'retry') {
|
||||
this.retryVisible = Visibility.Visible;
|
||||
this.imageVisible = Visibility.Hidden;
|
||||
this.percentVisible = Visibility.Hidden;
|
||||
if (this.retryWidth == '0%' || this.retryHeight == '0%') {
|
||||
animateTo({ duration: this.imageKnifeOption.animateDuration, curve: Curve.Linear }, () => {
|
||||
this.imageWidth = '0%';
|
||||
this.imageHeight = '0%';
|
||||
this.percentWidth = '0%';
|
||||
this.percentHeight = '0%';
|
||||
this.retryWidth = '100%';
|
||||
this.retryHeight = '100%';
|
||||
if (!this.drawLifeCycleHasConsumed(this.imageKnifeOption.drawLifeCycle, 'displayPlaceholder', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
if (!this.drawLifeCycleHasConsumed(globalThis.ImageKnife.getDefaultLifeCycle(), 'displayPlaceholder', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
this.defaultLifeCycle.displayPlaceholder(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
requestAddTransform(request:RequestOption){
|
||||
if(TransformType.BlurTransformation == this.imageKnifeOption.transform.transformType){
|
||||
displayProgress(percent: number) {
|
||||
|
||||
if (!this.drawLifeCycleHasConsumed(this.imageKnifeOption.drawLifeCycle, 'displayProgress', this.context, percent, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
if (!this.drawLifeCycleHasConsumed(globalThis.ImageKnife.getDefaultLifeCycle(), 'displayProgress', this.context, percent, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
this.defaultLifeCycle.displayProgress(this.context, percent, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
displayThumbSizeMultiplier(data: ImageKnifeData) {
|
||||
|
||||
if (!this.drawLifeCycleHasConsumed(this.imageKnifeOption.drawLifeCycle, 'displayThumbSizeMultiplier', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
if (!this.drawLifeCycleHasConsumed(globalThis.ImageKnife.getDefaultLifeCycle(), 'displayThumbSizeMultiplier', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
this.defaultLifeCycle.displayThumbSizeMultiplier(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
displayMainSource(data: ImageKnifeData) {
|
||||
|
||||
if (!this.drawLifeCycleHasConsumed(this.imageKnifeOption.drawLifeCycle, 'displayMainSource', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
if (!this.drawLifeCycleHasConsumed(globalThis.ImageKnife.getDefaultLifeCycle(), 'displayMainSource', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
this.defaultLifeCycle.displayMainSource(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
displayRetryholder(data: ImageKnifeData) {
|
||||
if (!this.drawLifeCycleHasConsumed(this.imageKnifeOption.drawLifeCycle, 'displayRetryholder', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
if (!this.drawLifeCycleHasConsumed(globalThis.ImageKnife.getDefaultLifeCycle(), 'displayRetryholder', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
this.defaultLifeCycle.displayRetryholder(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
displayErrorholder(data: ImageKnifeData) {
|
||||
|
||||
if (!this.drawLifeCycleHasConsumed(this.imageKnifeOption.drawLifeCycle, 'displayErrorholder', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
if (!this.drawLifeCycleHasConsumed(globalThis.ImageKnife.getDefaultLifeCycle(), 'displayErrorholder', this.context, data, this.imageKnifeOption,
|
||||
this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})) {
|
||||
this.defaultLifeCycle.displayErrorholder(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => {
|
||||
this.setGifTimeId(gifTimeId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
drawPlaceholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
console.log('default drawPlaceholder start!')
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
console.log('imageinfo widht =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
|
||||
let scaleType = (typeof imageKnifeOption.placeholderScaleType == 'number') ? imageKnifeOption.placeholderScaleType : ScaleType.FIT_CENTER
|
||||
context.save();
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
console.log('default drawPlaceholder end!')
|
||||
})
|
||||
}
|
||||
|
||||
drawProgress(context: CanvasRenderingContext2D, progress: number, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
let pi = Math.PI * 2 / 100; //pi 讲圆的周长划分为100份
|
||||
let rate = progress - 25;
|
||||
let diameter = compWidth > compHeight ? compHeight : compWidth
|
||||
context.lineWidth = Math.floor(diameter * 0.03)
|
||||
context.lineCap = "round"
|
||||
context.fillStyle = "#10a5ff"
|
||||
context.font = Math.floor(diameter * 0.3 * px2vp(1))+'px'
|
||||
|
||||
let x0 = (compWidth - diameter) / 2.0 + Math.floor(diameter * 0.5)
|
||||
let y0 = (compHeight - diameter) / 2.0 + Math.floor(diameter * 0.1)
|
||||
|
||||
let x1 = (compWidth - diameter) / 2.0 + Math.floor(diameter * 0.5)
|
||||
let y1 = (compHeight - diameter) / 2.0 + Math.floor(diameter * 0.8)
|
||||
let gradient = context.createLinearGradient(x0, y0, x1, y1)
|
||||
gradient.addColorStop(0, "#11ffe4")
|
||||
gradient.addColorStop(0.5, "#03c6fd")
|
||||
gradient.addColorStop(1, "#10a5ff")
|
||||
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
context.shadowBlur = 0
|
||||
context.beginPath()
|
||||
context.strokeStyle = "#15222d"
|
||||
let radius = Math.floor(diameter * 0.3)
|
||||
let arcX = compWidth / 2.0
|
||||
let arcY = compHeight / 2.0
|
||||
context.arc(arcX, arcY, radius, 0, Math.PI * 2, true)
|
||||
context.stroke()
|
||||
context.beginPath()
|
||||
let showText = rate + 25 + '%'
|
||||
let metrics = context.measureText(showText)
|
||||
let textX = (compWidth / 2.0) - metrics.width / 2.0
|
||||
let textY = (compHeight / 2.0) + metrics.height * 0.3
|
||||
context.fillText(showText, textX, textY)
|
||||
context.stroke()
|
||||
context.beginPath()
|
||||
context.strokeStyle = gradient
|
||||
context.arc(arcX, arcY, radius, pi * -25, pi * rate)
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
drawThumbSizeMultiplier(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
console.log('default drawThumbSizeMultiplier start!')
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
console.log('imageinfo widht =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
|
||||
let scaleType = (typeof imageKnifeOption.thumbSizeMultiplierScaleType == 'number') ? imageKnifeOption.thumbSizeMultiplierScaleType : ScaleType.FIT_CENTER
|
||||
context.save();
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
console.log('default drawThumbSizeMultiplier end!')
|
||||
})
|
||||
}
|
||||
|
||||
drawMainSource(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
console.log('default drawMainSource start!')
|
||||
if (data.isPixelMap()) {
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
let scaleType = (typeof imageKnifeOption.mainScaleType == 'number') ? imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER
|
||||
console.log('imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height + 'scaleType=' + scaleType)
|
||||
context.save();
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
console.log('default drawMainSource end!')
|
||||
})
|
||||
} else if (data.isGIFFrame()) {
|
||||
this.drawGIFFrame(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
}
|
||||
}
|
||||
|
||||
drawRetryholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
console.log('default drawRetryholder start!')
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
console.log('imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
|
||||
let scaleType = (typeof imageKnifeOption.retryholderScaleType == 'number') ? imageKnifeOption.retryholderScaleType : ScaleType.FIT_CENTER
|
||||
context.save();
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
console.log('default drawRetryholder end!')
|
||||
})
|
||||
}
|
||||
|
||||
drawErrorholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
console.log('default drawErrorholder start!')
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
console.log('imageinfo widht =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
|
||||
let scaleType = (typeof imageKnifeOption.errorholderSrcScaleType == 'number') ? imageKnifeOption.errorholderSrcScaleType : ScaleType.FIT_CENTER
|
||||
context.save();
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
console.log('default drawErrorholder end!')
|
||||
})
|
||||
}
|
||||
|
||||
requestAddTransform(request: RequestOption) {
|
||||
if (TransformType.BlurTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.blur(this.imageKnifeOption.transform.blur)
|
||||
}else if(TransformType.BrightnessFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.BrightnessFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.brightnessFilter(this.imageKnifeOption.transform.brightnessFilter)
|
||||
}else if(TransformType.ContrastFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.ContrastFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.contrastFilter(this.imageKnifeOption.transform.contrastFilter)
|
||||
}else if(TransformType.CropCircleTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.CropCircleTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.cropCircle()
|
||||
}else if(TransformType.CropCircleWithBorderTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.CropCircleWithBorderTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.cropCircleWithBorder(this.imageKnifeOption.transform.cropCircleWithBorder.border, this.imageKnifeOption.transform.cropCircleWithBorder.obj)
|
||||
}else if(TransformType.CropSquareTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.CropSquareTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.cropSquare()
|
||||
}else if(TransformType.CropTransformation == this.imageKnifeOption.transform.transformType){
|
||||
request.crop(this.imageKnifeOption.transform.crop.width,this.imageKnifeOption.transform.crop.height,this.imageKnifeOption.transform.crop.cropType)
|
||||
}else if(TransformType.GrayscaleTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.CropTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.crop(this.imageKnifeOption.transform.crop.width, this.imageKnifeOption.transform.crop.height, this.imageKnifeOption.transform.crop.cropType)
|
||||
} else if (TransformType.GrayscaleTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.grayscale()
|
||||
}else if(TransformType.InvertFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.InvertFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.invertFilter()
|
||||
}else if(TransformType.MaskTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.MaskTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.mask(this.imageKnifeOption.transform.mask)
|
||||
}else if(TransformType.PixelationFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.PixelationFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.pixelationFilter(this.imageKnifeOption.transform.pixelationFilter)
|
||||
}else if(TransformType.RotateImageTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.RotateImageTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.rotateImage(this.imageKnifeOption.transform.rotateImage)
|
||||
}else if(TransformType.RoundedCornersTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.RoundedCornersTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.roundedCorners(this.imageKnifeOption.transform.roundedCorners)
|
||||
}else if(TransformType.SepiaFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.SepiaFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.sepiaFilter()
|
||||
}else if(TransformType.SketchFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.SketchFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.sketchFilter()
|
||||
}else if(TransformType.SwirlFilterTransformation == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.SwirlFilterTransformation == this.imageKnifeOption.transform.transformType) {
|
||||
request.swirlFilter(this.imageKnifeOption.transform.swirlFilter)
|
||||
}else if(TransformType.CenterCrop == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.CenterCrop == this.imageKnifeOption.transform.transformType) {
|
||||
request.centerCrop()
|
||||
}else if(TransformType.CenterInside == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.CenterInside == this.imageKnifeOption.transform.transformType) {
|
||||
request.centerInside()
|
||||
}else if(TransformType.FitCenter == this.imageKnifeOption.transform.transformType){
|
||||
} else if (TransformType.FitCenter == this.imageKnifeOption.transform.transformType) {
|
||||
request.fitCenter()
|
||||
}
|
||||
}
|
||||
|
||||
aboutToDisappear() {
|
||||
this.resetGifData();
|
||||
}
|
||||
|
||||
onPageShow() {
|
||||
|
@ -332,6 +541,278 @@ export struct ImageKnifeComponent {
|
|||
|
||||
onBackPress() {
|
||||
}
|
||||
|
||||
setGifTimeId(timeId: number) {
|
||||
this.gifTimerId = timeId;
|
||||
}
|
||||
|
||||
private drawLifeCycleHasConsumed<K, T>(drawLifeCycle: IDrawLifeCycle, methodName: string,
|
||||
context: CanvasRenderingContext2D, data: K, imageKnifeOption: T, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void
|
||||
) {
|
||||
if (drawLifeCycle && drawLifeCycle[methodName]) {
|
||||
return drawLifeCycle[methodName](context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private drawGIFFrame(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
|
||||
let frames = data.drawGIFFrame.imageGIFFrames as GIFFrame[]
|
||||
console.log('gifFrameLength =' + frames.length);
|
||||
if (imageKnifeOption.gif && (typeof (imageKnifeOption.gif.seekTo) == 'number') && imageKnifeOption.gif.seekTo >= 0) {
|
||||
this.autoPlay = false;
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
this.drawSeekToFrame(frames, context, compWidth, compHeight)
|
||||
} else {
|
||||
this.autoPlay = true
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
this.renderFrames.bind(this, frames, 0, context, compWidth, compHeight)()
|
||||
}
|
||||
}
|
||||
|
||||
private resetGifData() {
|
||||
clearTimeout(this.gifTimerId)
|
||||
this.gifLoopDuration = 0;
|
||||
this.startGifLoopTime = 0;
|
||||
this.endGifLoopTime = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制直接到第几帧方法,由于gif非第一帧数据可能是不全的,这里采用逐帧渲染的方式来绘制保证图像的完整性
|
||||
*/
|
||||
private drawSeekToFrame(frames: GIFFrame[], context: CanvasRenderingContext2D, compWidth: number, compHeight: number) {
|
||||
for (let i = 0; i < this.imageKnifeOption.gif; i++) {
|
||||
this.drawFrame(frames, i, context, compWidth, compHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private renderFrames(frames: GIFFrame[], index: number, context: CanvasRenderingContext2D, compWidth: number, compHeight: number) {
|
||||
console.log('renderFrames frames length =' + frames.length)
|
||||
let start = new Date().getTime();
|
||||
if (index === 0) {
|
||||
// 如果是第一帧,我们只从开始渲染前记录时间
|
||||
this.startGifLoopTime = start;
|
||||
}
|
||||
// draw Frame
|
||||
this.drawFrame(frames, index, context, compWidth, compHeight);
|
||||
|
||||
// 记录渲染结束时间点
|
||||
let end = new Date().getTime();
|
||||
let diff = end - start
|
||||
|
||||
if (this.autoPlay) {
|
||||
|
||||
// 理论上该帧在屏幕上保留的时间
|
||||
let stayTime = frames[index].delay;
|
||||
if (this.imageKnifeOption.gif && this.imageKnifeOption.gif.speedFactory) {
|
||||
stayTime = frames[index].delay / (this.imageKnifeOption.gif.speedFactory * 1.0);
|
||||
}
|
||||
// 减去程序执行消耗,剩余的准确延迟时间
|
||||
let delayTime = Math.max(0, Math.floor(stayTime - diff));
|
||||
|
||||
this.endGifLoopTime = end;
|
||||
// 当前gif到第N帧,所对应的N渲染时间,和N-1的停留时间。(第一帧只有渲染时间没有停留时间)
|
||||
let loopStayTime = this.endGifLoopTime - this.startGifLoopTime;
|
||||
this.startGifLoopTime = end;
|
||||
// 整个gif累计的时长;
|
||||
this.gifLoopDuration += loopStayTime;
|
||||
// 返回gif一次循环结束回调,并且把当前循环的时间给出
|
||||
if (index === (frames.length - 1) && this.imageKnifeOption.gif && this.imageKnifeOption.gif.loopFinish) {
|
||||
this.imageKnifeOption.gif.loopFinish(this.gifLoopDuration)
|
||||
this.gifLoopDuration = 0;
|
||||
}
|
||||
// update the frame index
|
||||
index++
|
||||
if (index >= frames.length) {
|
||||
index = 0;
|
||||
}
|
||||
this.gifTimerId = setTimeout(this.renderFrames.bind(this, frames, index, context, compWidth, compHeight), delayTime)
|
||||
}
|
||||
}
|
||||
|
||||
private drawFrame(frames: GIFFrame[], index: number, context: CanvasRenderingContext2D, compWidth: number, compHeight: number) {
|
||||
// get current frame
|
||||
let frame = frames[index];
|
||||
if (!frame || !context) {
|
||||
// 数据保护,绘制保护
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frame['drawPixelMap']) {
|
||||
// 解码之后已经转为PixelMap
|
||||
} else {
|
||||
this.canvasDrawPixelMap(frames, index, context, compWidth, compHeight)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 具体绘制过程
|
||||
private canvasDrawPixelMap(frames: GIFFrame[], index: number, context: CanvasRenderingContext2D, compWidth: number, compHeight: number) {
|
||||
console.log('canvasDrawPixelMap index=' + index)
|
||||
let frame = frames[index];
|
||||
let pixelmap = frame['drawPixelMap']
|
||||
let disposal = 0
|
||||
// disposal value is from preFrame
|
||||
if (index >= 1) {
|
||||
let preFrame = frames[index-1]
|
||||
disposal = preFrame.disposalType
|
||||
}
|
||||
if (disposal === FrameDisposalType.DISPOSE_RestoreBackground) {
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
}
|
||||
let scaleType = (typeof this.imageKnifeOption.mainScaleType == 'number') ? this.imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER
|
||||
context.save();
|
||||
let frameW = frames[0].dims.left+frames[0].dims.width
|
||||
let frameH = frames[0].dims.top+frames[0].dims.height
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, compHeight,px2vp(frame.dims.left),px2vp(frame.dims.top))
|
||||
// tips:worker如果不是在展示页面中创建,使用子线程回来的数据创建的图片,会导致canvas绘制不出来
|
||||
context.restore();
|
||||
console.log('default drawMainSource end!')
|
||||
}
|
||||
}
|
||||
|
||||
export enum FrameDisposalType {
|
||||
// 0 - No disposal specified. The decoder is not required to take any action.
|
||||
// 不使用处置方法
|
||||
DISPOSE_Nothing = 0,
|
||||
// 1-Do not dispose. The graphic is to be left in place.
|
||||
// 不处置图形,把图形从当前位置移去
|
||||
DISPOSE_NotResolve = 1,
|
||||
// 2 - Restore to background color. The area used by the graphic must be restored to the background color.
|
||||
// 回复到背景色
|
||||
DISPOSE_RestoreBackground = 2,
|
||||
// 3-Restore to previous
|
||||
DISPOSE_PreviousStatus = 3
|
||||
}
|
||||
|
||||
export enum ScaleType {
|
||||
// 图像位于用户设置组件左上角显示,图像会缩放至全部展示
|
||||
FIT_START = 1,
|
||||
// 图像位于用户设置组件右下角显示,图像会缩放至全部展示
|
||||
FIT_END = 2,
|
||||
// 图像位于用户设置组件居中,图像会缩放至全部展示
|
||||
FIT_CENTER = 3,
|
||||
// 图像绝对居中展示,不缩放
|
||||
CENTER = 4,
|
||||
// 宽高中,短的部分缩放至组件大小,超出的全部裁剪
|
||||
CENTER_CROP = 5,
|
||||
// 图像拉伸至组件大小
|
||||
FIT_XY = 6,
|
||||
// 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER
|
||||
CENTER_INSIDE = 7,
|
||||
// 如果不想适配,直接展示原图大小
|
||||
NONE = 8
|
||||
}
|
||||
|
||||
export class ScaleTypeHelper {
|
||||
static drawImageWithScaleType(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | ImageBitmap, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number) {
|
||||
let scaleW = compWidth / imageWidth
|
||||
let scaleH = compHeight / imageHeight
|
||||
let minScale = scaleW > scaleH ? scaleH : scaleW
|
||||
let maxScale = scaleW > scaleH ? scaleW : scaleH
|
||||
|
||||
switch (scaleType) {
|
||||
case ScaleType.FIT_START:
|
||||
ScaleTypeHelper.drawFitStart(context, source, minScale, imageWidth, imageHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.FIT_END:
|
||||
ScaleTypeHelper.drawFitEnd(context, source, minScale, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.FIT_CENTER:
|
||||
ScaleTypeHelper.drawFitCenter(context, source, minScale, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.CENTER:
|
||||
ScaleTypeHelper.drawCenter(context, source, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.CENTER_CROP:
|
||||
ScaleTypeHelper.drawCenterCrop(context, source, maxScale, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.FIT_XY:
|
||||
ScaleTypeHelper.drawFitXY(context, source, scaleW, scaleH, imageWidth, imageHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.CENTER_INSIDE:
|
||||
ScaleTypeHelper.drawCenterInside(context, source, minScale, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
case ScaleType.NONE:
|
||||
ScaleTypeHelper.drawNone(context, source, imageWidth, imageHeight, imageOffsetX,imageOffsetY)
|
||||
break;
|
||||
default:
|
||||
ScaleTypeHelper.drawNone(context, source, imageWidth, imageHeight, imageOffsetX,imageOffsetY)
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static drawFitStart(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, minScale: number, imageWidth: number, imageHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
context.setTransform(minScale, 0, 0, minScale, 0, 0)
|
||||
let dx = 0
|
||||
let dy = 0
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
|
||||
static drawFitEnd(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, minScale: number, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
context.setTransform(minScale, 0, 0, minScale, 0, 0)
|
||||
|
||||
let dx = (compWidth - imageWidth * minScale) / (minScale * 1.0);
|
||||
let dy = (compHeight - imageHeight * minScale) / (minScale * 1.0);
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
|
||||
static drawFitCenter(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, minScale: number, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
context.setTransform(minScale, 0, 0, minScale, 0, 0)
|
||||
let dx = (compWidth - imageWidth * minScale) / (minScale * 2.0);
|
||||
let dy = (compHeight - imageHeight * minScale) / (minScale * 2.0);
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
|
||||
static drawCenter(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
let dx = (compWidth - imageWidth) / 2.0;
|
||||
let dy = (compHeight - imageHeight) / 2.0;
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
|
||||
static drawCenterCrop(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, maxScale: number, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
context.setTransform(maxScale, 0, 0, maxScale, 0, 0)
|
||||
let dx = (compWidth - imageWidth * maxScale) / (maxScale * 2.0);
|
||||
let dy = (compHeight - imageHeight * maxScale) / (maxScale * 2.0);
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
|
||||
static drawFitXY(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, scaleW: number, scaleH: number, imageWidth: number, imageHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
context.setTransform(scaleW, 0, 0, scaleH, 0, 0)
|
||||
let dx = 0;
|
||||
let dy = 0;
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
|
||||
static drawCenterInside(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, minScale: number, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
if (minScale < 1) {
|
||||
ScaleTypeHelper.drawFitCenter(context, source, minScale, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
} else {
|
||||
ScaleTypeHelper.drawCenter(context, source, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX,imageOffsetY)
|
||||
}
|
||||
}
|
||||
|
||||
static drawNone(context: CanvasRenderingContext2D, source: PixelMap | ImageBitmap, imageWidth: number, imageHeight: number, imageOffsetX?:number,imageOffsetY?:number) {
|
||||
let dx = 0;
|
||||
let dy = 0;
|
||||
let dw = imageWidth;
|
||||
let dh = imageHeight;
|
||||
context.drawImage(source, dx+imageOffsetX, dy+imageOffsetY)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,63 +12,73 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { GIFFrame } from './utils/gif/GIFFrame'
|
||||
|
||||
export enum ImageKnifeType {
|
||||
PIXELMAP = 'PixelMap',
|
||||
STRING = 'String',
|
||||
RESOURCE = 'Resource',
|
||||
GIFFRAME = 'GIFFrame'
|
||||
}
|
||||
|
||||
export class DrawPixelMap {
|
||||
imagePixelMap: PixelMap
|
||||
}
|
||||
|
||||
export class DrawString {
|
||||
imageString: string
|
||||
}
|
||||
|
||||
export class DrawResource {
|
||||
imageResource: Resource
|
||||
}
|
||||
|
||||
export class DrawGIFFrame {
|
||||
imageGIFFrames: GIFFrame[]
|
||||
}
|
||||
|
||||
export class ImageKnifeData {
|
||||
|
||||
static PIXELMAP = 'PixelMap'
|
||||
static STRING = 'string'
|
||||
static RESOURCE ='Resource'
|
||||
|
||||
static SVG = 'svg';
|
||||
static GIF = 'gif';
|
||||
static JPG = 'jpg';
|
||||
static PNG = 'png';
|
||||
static BMP = 'bmp';
|
||||
static WEBP = 'webp';
|
||||
imageKnifeType: ImageKnifeType;
|
||||
drawPixelMap: DrawPixelMap;
|
||||
drawGIFFrame: DrawGIFFrame;
|
||||
drawResource: DrawResource;
|
||||
drawString: DrawString;
|
||||
|
||||
|
||||
imageKnifeType:string = '';
|
||||
imageKnifeValue:PixelMap|string|Resource;
|
||||
imageKnifeSourceType:string = ''
|
||||
|
||||
isSvg():boolean{
|
||||
return ImageKnifeData.SVG == this.imageKnifeSourceType;
|
||||
static createImagePixelMap(type: ImageKnifeType, value: PixelMap) {
|
||||
let data = new ImageKnifeData();
|
||||
data.imageKnifeType = type;
|
||||
data.drawPixelMap = new DrawPixelMap();
|
||||
data.drawPixelMap.imagePixelMap = value;
|
||||
return data;
|
||||
}
|
||||
|
||||
isGif():boolean{
|
||||
return ImageKnifeData.GIF == this.imageKnifeSourceType;
|
||||
static createImageGIFFrame(type: ImageKnifeType, value: GIFFrame[]) {
|
||||
let data = new ImageKnifeData();
|
||||
data.imageKnifeType = type;
|
||||
data.drawGIFFrame = new DrawGIFFrame();
|
||||
data.drawGIFFrame.imageGIFFrames = value;
|
||||
return data;
|
||||
}
|
||||
|
||||
isJpg():boolean{
|
||||
return ImageKnifeData.JPG == this.imageKnifeSourceType;
|
||||
isPixelMap(): boolean {
|
||||
return ImageKnifeType.PIXELMAP == this.imageKnifeType;
|
||||
}
|
||||
|
||||
isPng():boolean{
|
||||
return ImageKnifeData.PNG == this.imageKnifeSourceType;
|
||||
isGIFFrame(): boolean {
|
||||
return ImageKnifeType.GIFFRAME == this.imageKnifeType;
|
||||
}
|
||||
|
||||
isBmp():boolean{
|
||||
return ImageKnifeData.BMP == this.imageKnifeSourceType;
|
||||
isString(): boolean {
|
||||
return ImageKnifeType.STRING == this.imageKnifeType;
|
||||
}
|
||||
|
||||
isWebp():boolean{
|
||||
return ImageKnifeData.WEBP == this.imageKnifeSourceType;
|
||||
isResource(): boolean {
|
||||
return ImageKnifeType.RESOURCE == this.imageKnifeType;
|
||||
}
|
||||
|
||||
|
||||
isString():boolean{
|
||||
return ImageKnifeData.STRING == this.imageKnifeType;
|
||||
}
|
||||
isPixelMap():boolean{
|
||||
return ImageKnifeData.PIXELMAP == this.imageKnifeType;
|
||||
}
|
||||
isResource():boolean{
|
||||
return ImageKnifeData.RESOURCE == this.imageKnifeType;
|
||||
}
|
||||
|
||||
|
||||
can2PixelMap(){ // 可以转换为PixelMap的数据源
|
||||
return this.isPixelMap() || this.isBmp() || this.isJpg() || this.isWebp() || this.isPng();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,481 @@
|
|||
/*
|
||||
* 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 { ImageKnifeOption } from '../imageknife/ImageKnifeOption'
|
||||
import { ImageKnifeData } from '../imageknife/ImageKnifeData'
|
||||
import { GIFFrame } from '../imageknife/utils/gif/GIFFrame'
|
||||
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
|
||||
import { ScaleTypeHelper,ScaleType } from '../imageknife/ImageKnifeComponent'
|
||||
|
||||
export class ImageKnifeDrawFactory{
|
||||
|
||||
/**
|
||||
* 绘制PixelMap内容情况下,主图的椭圆裁剪,可添加边框
|
||||
* @param borderWidth 外边框 borderWidth vp
|
||||
* @param colorString 例如 "#FF00FF"
|
||||
*/
|
||||
public static createOvalLifeCycle(borderWidth:number, colorString:string):IDrawLifeCycle{
|
||||
let viewLifeCycle = {
|
||||
// 展示占位图
|
||||
displayPlaceholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
// 展示加载进度
|
||||
displayProgress: (context: CanvasRenderingContext2D, progress: number, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
return false;
|
||||
},
|
||||
// 展示缩略图
|
||||
displayThumbSizeMultiplier: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
|
||||
// 展示主图
|
||||
displayMainSource: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
if (data.isPixelMap()) {
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
let scaleType = (typeof imageKnifeOption.mainScaleType == 'number') ? imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER
|
||||
|
||||
context.clearRect(0,0,compWidth,compHeight)
|
||||
context.save();
|
||||
// 绘制适配后的图像
|
||||
context.save();
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
|
||||
// 使用 destination-in 裁剪出椭圆
|
||||
context.save();
|
||||
context.globalCompositeOperation = 'destination-in'
|
||||
context.beginPath();
|
||||
this.setOval(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0,borderWidth)
|
||||
context.closePath();
|
||||
context.fill()
|
||||
context.restore();
|
||||
|
||||
// 给椭圆加上边框
|
||||
context.save();
|
||||
if(borderWidth > 0) {
|
||||
context.strokeStyle = colorString
|
||||
context.lineWidth = borderWidth;
|
||||
context.globalCompositeOperation = 'source-over'
|
||||
context.beginPath();
|
||||
this.setOval(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0, borderWidth)
|
||||
context.closePath();
|
||||
context.stroke()
|
||||
context.restore();
|
||||
}
|
||||
context.restore();
|
||||
})
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// 展示重试图层
|
||||
displayRetryholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
return false;
|
||||
},
|
||||
// 展示失败占位图
|
||||
displayErrorholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return viewLifeCycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制椭圆的计算和绘制,可借鉴,私有方法不对外提供
|
||||
* @param context
|
||||
* @param scaleType
|
||||
* @param source
|
||||
* @param imageWidth
|
||||
* @param imageHeight
|
||||
* @param compWidth
|
||||
* @param compHeight
|
||||
* @param imageOffsetX
|
||||
* @param imageOffsetY
|
||||
* @param borderWidth
|
||||
*/
|
||||
private static setOval(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | ImageBitmap, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number
|
||||
,borderWidth:number) {
|
||||
let scaleW = compWidth / imageWidth
|
||||
let scaleH = compHeight / imageHeight
|
||||
let minScale = scaleW > scaleH ? scaleH : scaleW
|
||||
let maxScale = scaleW > scaleH ? scaleW : scaleH
|
||||
let circleX = compWidth / 2
|
||||
let circleY = compHeight / 2
|
||||
switch (scaleType) {
|
||||
case ScaleType.FIT_START:
|
||||
circleX = imageWidth * minScale / 2
|
||||
circleY = imageWidth * minScale / 2
|
||||
context.ellipse(circleX,circleY, (imageWidth * minScale - borderWidth) / 2, (imageHeight * minScale - borderWidth) / 2, 0, 0, Math.PI * 2)
|
||||
break
|
||||
case ScaleType.FIT_END:
|
||||
if(scaleW >= scaleH){
|
||||
circleX = compWidth - imageWidth * minScale/2
|
||||
circleY = imageHeight * minScale / 2
|
||||
}else{
|
||||
circleX = imageWidth * minScale / 2
|
||||
circleY = compHeight - imageHeight * minScale / 2
|
||||
}
|
||||
context.ellipse(circleX, circleY, (imageWidth * minScale - borderWidth) / 2, (imageHeight * minScale - borderWidth) / 2, 0, 0, Math.PI * 2)
|
||||
break
|
||||
case ScaleType.FIT_CENTER:
|
||||
circleX = compWidth / 2;
|
||||
circleY = compHeight / 2;
|
||||
context.ellipse(circleX, circleY, (imageWidth * minScale - borderWidth) / 2, (imageHeight * minScale - borderWidth) / 2, 0, 0, Math.PI * 2)
|
||||
break
|
||||
case ScaleType.CENTER:
|
||||
circleX = compWidth / 2;
|
||||
circleY = compWidth / 2;
|
||||
let centerRadiusX = (Math.min(compWidth,imageWidth) - borderWidth)/2
|
||||
let centerRadiusY = (Math.min(compHeight,imageHeight) -borderWidth)/2
|
||||
context.ellipse(circleX, circleY, centerRadiusX, centerRadiusY, 0, 0, Math.PI * 2)
|
||||
break
|
||||
case ScaleType.CENTER_CROP:
|
||||
// 肯定会占满全屏
|
||||
circleX = compWidth / 2;
|
||||
circleY = compHeight / 2;
|
||||
let centerCropRadiusX = (compWidth-borderWidth)/2
|
||||
let centerCropRadiusY = (compHeight-borderWidth)/2
|
||||
|
||||
context.ellipse(circleX, circleY, centerCropRadiusX, centerCropRadiusY, 0, 0, Math.PI * 2)
|
||||
break
|
||||
case ScaleType.FIT_XY:
|
||||
context.ellipse(compWidth / 2, compHeight / 2, (imageWidth * scaleW - borderWidth) / 2, (imageHeight * scaleH - borderWidth) / 2, 0, 0, Math.PI * 2)
|
||||
break
|
||||
case ScaleType.CENTER_INSIDE:
|
||||
if(minScale < 1){ // FIT_CENTER
|
||||
circleX = compWidth / 2;
|
||||
circleY = compHeight / 2;
|
||||
context.ellipse(circleX,circleY,(imageWidth * minScale - borderWidth) / 2, (imageHeight * minScale - borderWidth) / 2, 0, 0, Math.PI * 2)
|
||||
}else{ // CENTER
|
||||
circleX = compWidth / 2;
|
||||
circleY = compWidth / 2;
|
||||
let centerRadiusX = (Math.min(compWidth,imageWidth) - borderWidth)/2
|
||||
let centerRadiusY = (Math.min(compHeight,imageHeight) -borderWidth)/2
|
||||
context.ellipse(circleX, circleY, centerRadiusX, centerRadiusY, 0, 0, Math.PI * 2)
|
||||
}
|
||||
break
|
||||
case ScaleType.NONE:
|
||||
circleX = Math.min(compWidth,imageWidth)/2
|
||||
circleY = Math.min(compHeight,imageHeight)/2
|
||||
let noneRadiusX = (Math.min(compWidth,imageWidth)-borderWidth)/2
|
||||
let noneRadiusY = (Math.min(compHeight,imageHeight)-borderWidth)/2
|
||||
context.ellipse(circleX,circleY,noneRadiusX,noneRadiusY,0,0, Math.PI*2)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 绘制PixelMap内容情况下,主图的圆角裁剪,可添加边框
|
||||
* @param borderWidth 边框宽度
|
||||
* @param colorString 边框颜色string
|
||||
* @param connerRadius 圆角半径
|
||||
*/
|
||||
public static createRoundLifeCycle(borderWidth:number, colorString:string, connerRadius:number){
|
||||
let viewLifeCycle = {
|
||||
// 展示占位图
|
||||
displayPlaceholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
// 展示加载进度
|
||||
displayProgress: (context: CanvasRenderingContext2D, progress: number, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
return false;
|
||||
},
|
||||
// 展示缩略图
|
||||
displayThumbSizeMultiplier: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
|
||||
// 展示主图
|
||||
displayMainSource: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
if (data.isPixelMap()) {
|
||||
// @ts-ignore
|
||||
data.drawPixelMap.imagePixelMap.getImageInfo().then((imageInfo) => {
|
||||
let scaleType = (typeof imageKnifeOption.mainScaleType == 'number') ? imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER
|
||||
|
||||
context.clearRect(0,0,compWidth,compHeight)
|
||||
context.save();
|
||||
|
||||
// 绘制适配后的图像
|
||||
context.save();
|
||||
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0)
|
||||
context.restore();
|
||||
|
||||
// 通过 destination-in 裁剪出圆角
|
||||
context.save();
|
||||
context.globalCompositeOperation = 'destination-in'
|
||||
this.setRect(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0,borderWidth,connerRadius)
|
||||
context.fill()
|
||||
context.restore();
|
||||
if(borderWidth > 0){
|
||||
// 为圆角添加边框
|
||||
context.save();
|
||||
context.strokeStyle = colorString
|
||||
context.lineWidth = borderWidth
|
||||
context.globalCompositeOperation = 'source-over'
|
||||
this.setRect(context, scaleType, data.drawPixelMap.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight,0,0,borderWidth,connerRadius)
|
||||
context.stroke()
|
||||
context.restore();
|
||||
}
|
||||
context.restore();
|
||||
console.log('TestImageKnifeOptionChangedPage4 drawMainSource end!')
|
||||
})
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// 展示重试图层
|
||||
displayRetryholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
return false;
|
||||
},
|
||||
// 展示失败占位图
|
||||
displayErrorholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return viewLifeCycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制圆角的计算,可借鉴,私有方法不对外提供
|
||||
* @param context
|
||||
* @param scaleType
|
||||
* @param source
|
||||
* @param imageWidth
|
||||
* @param imageHeight
|
||||
* @param compWidth
|
||||
* @param compHeight
|
||||
* @param imageOffsetX
|
||||
* @param imageOffsetY
|
||||
* @param borderWidth
|
||||
* @param cornerRadius
|
||||
*/
|
||||
private static setRect(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | ImageBitmap, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number
|
||||
,borderWidth:number,cornerRadius:number) {
|
||||
let scaleW = compWidth / imageWidth
|
||||
let scaleH = compHeight / imageHeight
|
||||
let minScale = scaleW > scaleH ? scaleH : scaleW
|
||||
let maxScale = scaleW > scaleH ? scaleW : scaleH
|
||||
let x1 = borderWidth/2
|
||||
let y1 = borderWidth/2
|
||||
let w1 = compWidth - borderWidth;
|
||||
let h1 = compWidth - borderWidth;
|
||||
switch (scaleType) {
|
||||
case ScaleType.FIT_START:
|
||||
x1 = borderWidth/2
|
||||
y1 = borderWidth/2
|
||||
w1 = imageWidth * minScale - borderWidth;
|
||||
h1 = imageHeight * minScale - borderWidth;
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break
|
||||
case ScaleType.FIT_END:
|
||||
x1 = compWidth - imageWidth * minScale + borderWidth / 2
|
||||
y1 = compHeight - imageHeight * minScale + borderWidth / 2
|
||||
w1 = imageWidth * minScale - borderWidth;
|
||||
h1 = imageHeight * minScale - borderWidth;
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break
|
||||
case ScaleType.FIT_CENTER:
|
||||
x1 = (compWidth - imageWidth * minScale) / 2 + borderWidth / 2
|
||||
y1 = (compHeight - imageHeight * minScale) / 2 + borderWidth / 2
|
||||
w1 = imageWidth * minScale - borderWidth
|
||||
h1 = imageHeight * minScale - borderWidth
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break
|
||||
case ScaleType.CENTER:
|
||||
x1 = Math.max(0,(compWidth - Math.min(compWidth, imageWidth)))/2 + borderWidth/2
|
||||
y1 = Math.max(0,(compHeight - Math.min(compHeight, imageHeight)))/2 + borderWidth/2
|
||||
|
||||
w1 = Math.min(compWidth, imageWidth) - borderWidth;
|
||||
h1 = Math.min(compHeight, imageHeight) - borderWidth;
|
||||
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break
|
||||
case ScaleType.CENTER_CROP:
|
||||
x1 = borderWidth/2
|
||||
y1 = borderWidth/2
|
||||
|
||||
w1 = compWidth - borderWidth;
|
||||
h1 = compWidth - borderWidth;
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break
|
||||
case ScaleType.FIT_XY:
|
||||
x1 = borderWidth/2
|
||||
y1 = borderWidth/2
|
||||
|
||||
w1 = compWidth - borderWidth;
|
||||
h1 = compWidth - borderWidth;
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break
|
||||
case ScaleType.CENTER_INSIDE:
|
||||
if(minScale < 1){ // FIT_CENTER
|
||||
x1 = (compWidth - imageWidth * minScale) / 2 + borderWidth / 2
|
||||
y1 = (compHeight - imageHeight * minScale) / 2 + borderWidth / 2
|
||||
w1 = imageWidth * minScale - borderWidth
|
||||
h1 = imageHeight * minScale - borderWidth
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
}else{ // CENTER
|
||||
x1 = Math.max(0,(compWidth - Math.min(compWidth, imageWidth)))/2 + borderWidth/2
|
||||
y1 = Math.max(0,(compHeight - Math.min(compHeight, imageHeight)))/2 + borderWidth/2
|
||||
|
||||
w1 = Math.min(compWidth, imageWidth) - borderWidth;
|
||||
h1 = Math.min(compHeight, imageHeight) - borderWidth;
|
||||
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
}
|
||||
|
||||
break;
|
||||
case ScaleType.NONE:
|
||||
|
||||
x1 = borderWidth/2
|
||||
y1 = borderWidth/2
|
||||
|
||||
w1 = Math.min(compWidth, imageWidth) - borderWidth;
|
||||
h1 = Math.min(compHeight, imageHeight) - borderWidth;
|
||||
|
||||
this.roundRect(context, x1, y1, w1, h1, cornerRadius)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制圆角的绘制,可借鉴,私有方法不对外提供
|
||||
* @param context
|
||||
* @param x
|
||||
* @param y
|
||||
* @param w
|
||||
* @param h
|
||||
* @param r
|
||||
*/
|
||||
private static roundRect(context: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, r: number) {
|
||||
if (w < 2 * r) {
|
||||
r = w / 2;
|
||||
}
|
||||
if (h < 2 * r) {
|
||||
r = h / 2;
|
||||
}
|
||||
context.beginPath();
|
||||
context.moveTo(x + r, y);
|
||||
context.arcTo(x + w, y, x + w, y + h, r);
|
||||
context.arcTo(x + w, y + h, x, y + h, r);
|
||||
context.arcTo(x, y + h, x, y, r);
|
||||
context.arcTo(x, y, x + w, y, r);
|
||||
context.closePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制下载进度条
|
||||
* @param fontColor 文字颜色
|
||||
* @param fontSizeRate 文字占半径比率[0,1]
|
||||
*/
|
||||
public static createProgressLifeCycle(fontColor:string, fontSizeRate:number){
|
||||
let viewLifeCycle: IDrawLifeCycle = {
|
||||
// 展示占位图
|
||||
displayPlaceholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
// 展示加载进度
|
||||
displayProgress: (context: CanvasRenderingContext2D, progress: number, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
this.drawDefaultProgress(context, progress, imageKnifeOption, compWidth, compHeight,fontColor,fontSizeRate,setGifTimeId)
|
||||
return true;
|
||||
},
|
||||
// 展示缩略图
|
||||
displayThumbSizeMultiplier: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
|
||||
// 展示主图
|
||||
displayMainSource: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
|
||||
// 展示重试图层
|
||||
displayRetryholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
},
|
||||
|
||||
// 展示失败占位图
|
||||
displayErrorholder: (context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) => {
|
||||
// @ts-ignore
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return viewLifeCycle;
|
||||
}
|
||||
/**
|
||||
* 绘制默认的网络下载百分比
|
||||
* @param context
|
||||
* @param progress
|
||||
* @param imageKnifeOption
|
||||
* @param compWidth
|
||||
* @param compHeight
|
||||
* @param fontColor
|
||||
* @param fontSizeRate
|
||||
* @param setGifTimeId
|
||||
*/
|
||||
private static drawDefaultProgress(context: CanvasRenderingContext2D, progress: number, imageKnifeOption: ImageKnifeOption,
|
||||
compWidth: number, compHeight: number,
|
||||
fontColor:string, fontSizeRate:number,setGifTimeId?: (timeId: number) => void,){
|
||||
let pi = Math.PI * 2 / 100; //pi 讲圆的周长划分为100份
|
||||
let rate = progress - 25;
|
||||
let diameter = compWidth > compHeight ? compHeight : compWidth
|
||||
context.lineWidth = Math.floor(diameter * 0.03)
|
||||
context.lineCap = "round"
|
||||
context.fillStyle = fontColor//"#10a5ff"
|
||||
context.font = Math.floor(diameter * fontSizeRate *px2vp(1))+'px'
|
||||
let x0 = (compWidth - diameter) / 2.0 + Math.floor(diameter * 0.5)
|
||||
let y0 = (compHeight - diameter) / 2.0 + Math.floor(diameter * 0.1)
|
||||
let x1 = (compWidth - diameter) / 2.0 + Math.floor(diameter * 0.5)
|
||||
let y1 = (compHeight - diameter) / 2.0 + Math.floor(diameter * 0.8)
|
||||
let gradient = context.createLinearGradient(x0, y0, x1, y1)
|
||||
gradient.addColorStop(0, "#11ffe4")
|
||||
gradient.addColorStop(0.5, "#03c6fd")
|
||||
gradient.addColorStop(1, "#10a5ff")
|
||||
context.clearRect(0, 0, compWidth, compHeight)
|
||||
context.shadowBlur = 0
|
||||
context.beginPath()
|
||||
context.strokeStyle = "#15222d"
|
||||
let radius = Math.floor(diameter * 0.3)
|
||||
let arcX = compWidth / 2.0
|
||||
let arcY = compHeight / 2.0
|
||||
context.arc(arcX, arcY, radius, 0, Math.PI * 2, true)
|
||||
context.stroke()
|
||||
context.beginPath()
|
||||
let showText = rate + 25 + '%'
|
||||
let metrics = context.measureText(showText)
|
||||
let textX = (compWidth / 2.0) - metrics.width / 2.0
|
||||
let textY = (compHeight / 2.0) + metrics.height * 0.3
|
||||
context.fillText(showText, textX, textY)
|
||||
context.stroke()
|
||||
context.beginPath()
|
||||
context.strokeStyle = gradient
|
||||
context.arc(arcX, arcY, radius, pi * -25, pi * rate)
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -13,17 +13,26 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {AUTOMATIC} from "../cache/diskstrategy/enum/AUTOMATIC"
|
||||
import {DiskStrategy} from "../cache/diskstrategy/DiskStrategy"
|
||||
import {BaseTransform} from "../imageknife/transform/BaseTransform"
|
||||
import {TransformType} from "../imageknife/transform/TransformType"
|
||||
import {CropType} from "../imageknife/transform/CropTransformation"
|
||||
import {AllCacheInfo, IAllCacheInfoCallback} from "../imageknife/interface/IAllCacheInfoCallback"
|
||||
import { AUTOMATIC } from '../cache/diskstrategy/enum/AUTOMATIC'
|
||||
|
||||
import { DiskStrategy } from '../cache/diskstrategy/DiskStrategy'
|
||||
import { BaseTransform } from '../imageknife/transform/BaseTransform'
|
||||
import { TransformType } from '../imageknife/transform/TransformType'
|
||||
import { CropType } from '../imageknife/transform/CropTransformation'
|
||||
import { AllCacheInfo, IAllCacheInfoCallback } from '../imageknife/interface/IAllCacheInfoCallback'
|
||||
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
|
||||
import { ScaleType } from '../imageknife/ImageKnifeComponent'
|
||||
|
||||
export class ImageKnifeOption {
|
||||
// 组件大小
|
||||
size: {
|
||||
width: string,
|
||||
height: string
|
||||
};
|
||||
|
||||
// 主图资源
|
||||
loadSrc: string | PixelMap | Resource;
|
||||
mainScaleType?: ScaleType = ScaleType.FIT_CENTER
|
||||
|
||||
// 磁盘缓存策略
|
||||
strategy?: DiskStrategy = new AUTOMATIC();
|
||||
|
@ -33,59 +42,83 @@ export class ImageKnifeOption {
|
|||
|
||||
// 占位图
|
||||
placeholderSrc?: PixelMap | Resource;
|
||||
placeholderScaleType?: ScaleType = ScaleType.FIT_CENTER
|
||||
|
||||
// 失败占位图
|
||||
errorholderSrc?: PixelMap | Resource;
|
||||
errorholderSrcScaleType?: ScaleType = ScaleType.FIT_CENTER
|
||||
|
||||
// 重试占位图
|
||||
retryholderSrc?: Resource;
|
||||
retryholderScaleType?: ScaleType = ScaleType.FIT_CENTER
|
||||
|
||||
// 缩略图,范围(0,1)
|
||||
thumbSizeMultiplier?: number;
|
||||
// 缩略图展示时间
|
||||
thumbSizeDelay?:number;
|
||||
// 缩略图展示类型
|
||||
thumbSizeMultiplierScaleType?: ScaleType = ScaleType.FIT_CENTER
|
||||
|
||||
// 进度条
|
||||
displayProgress?: boolean;
|
||||
|
||||
// 进度条回调
|
||||
displayProgressListener?;
|
||||
|
||||
// 重试图层
|
||||
retryLoad?: boolean;
|
||||
|
||||
// 动画时长
|
||||
animateDuration?: number = 500;
|
||||
// 重试图层 可点击
|
||||
canRetryClick?: boolean;
|
||||
|
||||
// 仅使用缓存加载数据
|
||||
onlyRetrieveFromCache?: boolean = false;
|
||||
|
||||
// 是否开启第一级内存缓存
|
||||
// 是否开启一级内存缓存
|
||||
isCacheable?: boolean = true;
|
||||
|
||||
// 变换相关
|
||||
transform?:{
|
||||
transformType:number,
|
||||
blur?:number,
|
||||
roundedCorners?:{ top_left: number, top_right: number, bottom_left: number, bottom_right: number }
|
||||
cropCircleWithBorder?:{border:number, obj:{ r_color: number, g_color: number, b_color: number }}
|
||||
crop?:{width: number, height: number, cropType: CropType}
|
||||
brightnessFilter?:number,
|
||||
contrastFilter?:number,
|
||||
pixelationFilter?:number,
|
||||
swirlFilter?:number,
|
||||
mask?:Resource,
|
||||
rotateImage?:number
|
||||
|
||||
// 用户自定义实现 绘制方案
|
||||
drawLifeCycle?: IDrawLifeCycle;
|
||||
|
||||
gif?: {
|
||||
loopFinish?: (loopTime?) => void
|
||||
speedFactory?: number
|
||||
seekTo?: number
|
||||
}
|
||||
|
||||
transformation?:BaseTransform<PixelMap>;
|
||||
|
||||
transformations?:Array<BaseTransform<PixelMap>>;
|
||||
// 变换相关
|
||||
transform?: {
|
||||
transformType: number,
|
||||
blur?: number,
|
||||
roundedCorners?: {
|
||||
top_left: number,
|
||||
top_right: number,
|
||||
bottom_left: number,
|
||||
bottom_right: number
|
||||
}
|
||||
cropCircleWithBorder?: {
|
||||
border: number,
|
||||
obj: {
|
||||
r_color: number,
|
||||
g_color: number,
|
||||
b_color: number
|
||||
}
|
||||
}
|
||||
crop?: {
|
||||
width: number,
|
||||
height: number,
|
||||
cropType: CropType
|
||||
}
|
||||
brightnessFilter?: number,
|
||||
contrastFilter?: number,
|
||||
pixelationFilter?: number,
|
||||
swirlFilter?: number,
|
||||
mask?: Resource,
|
||||
rotateImage?: number
|
||||
}
|
||||
transformation?: BaseTransform<PixelMap>;
|
||||
transformations?: Array<BaseTransform<PixelMap>>;
|
||||
|
||||
// 输出缓存相关内容和信息
|
||||
allCacheInfoCallback?: IAllCacheInfoCallback;
|
||||
size: {
|
||||
width: number,
|
||||
height: number
|
||||
};
|
||||
|
||||
imageFit?: ImageFit;
|
||||
backgroundColor?: Color | number | string | Resource;
|
||||
margin?: {
|
||||
|
@ -95,7 +128,7 @@ export class ImageKnifeOption {
|
|||
left?: number | string | Resource
|
||||
} | number | string | Resource
|
||||
|
||||
|
||||
sizeAnimate?: AnimateParam
|
||||
|
||||
constructor() {
|
||||
|
||||
|
|
|
@ -55,19 +55,19 @@ export class RequestOption {
|
|||
errorholderData: ImageKnifeData;
|
||||
thumbSizeMultiplier: number;
|
||||
|
||||
// 如果存在缩略图,则主图延时3000ms加载
|
||||
thumbDelayTime: number = 3000
|
||||
// 如果存在缩略图,则主图延时1s加载
|
||||
thumbDelayTime: number = 1000
|
||||
thumbHolderFunc: AsyncSuccess<ImageKnifeData>;
|
||||
requestListeners: Array<AsyncCallback<ImageKnifeData>>;
|
||||
|
||||
// 进度条
|
||||
progressFunc: AsyncSuccess<string>;
|
||||
progressFunc: AsyncSuccess<number>;
|
||||
|
||||
// 重试图层
|
||||
retryFunc: AsyncSuccess<ImageKnifeData>
|
||||
retryholderSrc: PixelMap | Resource;
|
||||
retryholderFunc: AsyncSuccess<ImageKnifeData>
|
||||
retryholderData: ImageKnifeData
|
||||
|
||||
// 图层切换时长
|
||||
animateDuration: number = 500;
|
||||
size: {
|
||||
width: number,
|
||||
height: number
|
||||
|
@ -98,12 +98,13 @@ export class RequestOption {
|
|||
loadMainReady = false;
|
||||
|
||||
// 失败占位图展示状态 当true 表示主图加载失败需要展示失败占位图
|
||||
loadErrorReady = false
|
||||
loadErrorReady = false;
|
||||
|
||||
// 重试占位图展示状态 当true 表示主图加载失败需要展示失败占位图
|
||||
loadRetryReady = false;
|
||||
|
||||
// 缩略图展示
|
||||
loadThumbnailReady = false;
|
||||
_svgAndGifFolder: string = "svgAndGifFolder"; // svg和gif的文件路径地址
|
||||
_svgAndGifCommitFile: string = "svgAndGifCommitFile"; // svg和gif提交记录
|
||||
|
||||
constructor() {
|
||||
// 初始化全局监听
|
||||
|
@ -166,21 +167,27 @@ export class RequestOption {
|
|||
return this;
|
||||
}
|
||||
|
||||
thumbnail(sizeMultiplier: number, func?: AsyncSuccess<ImageKnifeData>) {
|
||||
this.thumbSizeMultiplier = sizeMultiplier;
|
||||
this.thumbHolderFunc = func;
|
||||
retryholder(src: PixelMap | Resource, func?: AsyncSuccess<ImageKnifeData>) {
|
||||
this.retryholderSrc = src;
|
||||
this.retryholderFunc = func;
|
||||
return this;
|
||||
}
|
||||
|
||||
addProgressListener(func?: AsyncSuccess<string>) {
|
||||
thumbnail(sizeMultiplier: number, func?: AsyncSuccess<ImageKnifeData>,displayTime?:number) {
|
||||
this.thumbSizeMultiplier = sizeMultiplier;
|
||||
this.thumbHolderFunc = func;
|
||||
if(displayTime){
|
||||
this.thumbDelayTime = displayTime;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
addProgressListener(func?: AsyncSuccess<number>) {
|
||||
this.progressFunc = func;
|
||||
return this;
|
||||
}
|
||||
|
||||
addRetryListener(func?: AsyncSuccess<any>) {
|
||||
this.retryFunc = func;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
addListener(func: AsyncCallback<ImageKnifeData>) {
|
||||
this.requestListeners.push(func);
|
||||
|
@ -322,7 +329,7 @@ export class RequestOption {
|
|||
placeholderOnComplete(imageKnifeData: ImageKnifeData) {
|
||||
console.log("placeholderOnComplete has called!");
|
||||
console.log("Main Image is Ready:" + this.loadMainReady);
|
||||
if (!this.loadMainReady && !this.loadErrorReady && !this.loadThumbnailReady) {
|
||||
if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady) && !this.loadThumbnailReady) {
|
||||
// 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
|
||||
this.placeholderFunc(imageKnifeData)
|
||||
}
|
||||
|
@ -333,9 +340,12 @@ export class RequestOption {
|
|||
console.log("占位图解析失败 error =" + error)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 缩略图解析成功
|
||||
thumbholderOnComplete(imageKnifeData: ImageKnifeData) {
|
||||
if (!this.loadMainReady && !this.loadErrorReady) {
|
||||
if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady)) {
|
||||
//主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
|
||||
this.thumbHolderFunc(imageKnifeData)
|
||||
}
|
||||
|
@ -360,6 +370,17 @@ export class RequestOption {
|
|||
console.log("失败占位图解析失败 error =" + error)
|
||||
}
|
||||
|
||||
retryholderOnComplete(imageKnifeData: ImageKnifeData){
|
||||
this.retryholderData = imageKnifeData;
|
||||
if(this.loadRetryReady){
|
||||
this.retryholderFunc(imageKnifeData)
|
||||
}
|
||||
}
|
||||
|
||||
retryholderOnError(error){
|
||||
console.log("重试占位图解析失败 error ="+ error)
|
||||
}
|
||||
|
||||
loadComplete(imageKnifeData: ImageKnifeData) {
|
||||
this.loadMainReady = true;
|
||||
// 三级缓存数据加载成功
|
||||
|
@ -375,12 +396,17 @@ export class RequestOption {
|
|||
|
||||
loadError(err) {
|
||||
console.log("loadError:"+err);
|
||||
console.log("loadError stack=:"+JSON.stringify(err.stack));
|
||||
//失败占位图展示规则
|
||||
this.loadErrorReady = true;
|
||||
if (this.retryFunc) {
|
||||
if (this.retryholderFunc) {
|
||||
// 重试图层优先于加载失败展示
|
||||
this.retryFunc(err)
|
||||
this.loadRetryReady = true;
|
||||
if(this.retryholderData != null){
|
||||
this.retryholderFunc(this.retryholderData)
|
||||
}
|
||||
} else {
|
||||
// 失败图层标记,如果已经有数据直接展示失败图层
|
||||
this.loadErrorReady = true;
|
||||
if (this.errorholderData != null) {
|
||||
this.errorholderFunc(this.errorholderData)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
import {ImageKnifeData} from '../ImageKnifeData'
|
||||
export interface IDrawExtension{
|
||||
<T>(context: CanvasRenderingContext2D,data: ImageKnifeData, imageKnifeOption:T, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 {ImageKnifeOption} from '../ImageKnifeOption'
|
||||
import {ImageKnifeData} from '../ImageKnifeData'
|
||||
export interface IDrawLifeCycle{
|
||||
|
||||
// 展示占位图
|
||||
displayPlaceholder?: (context: CanvasRenderingContext2D,data: ImageKnifeData, imageKnifeOption:ImageKnifeOption, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)=>boolean
|
||||
|
||||
// 展示加载进度
|
||||
displayProgress?: (context: CanvasRenderingContext2D,progress: number, imageKnifeOption:ImageKnifeOption, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)=>boolean
|
||||
|
||||
// 展示缩略图
|
||||
displayThumbSizeMultiplier?: (context: CanvasRenderingContext2D,data: ImageKnifeData, imageKnifeOption:ImageKnifeOption, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)=>boolean
|
||||
|
||||
// 展示主图
|
||||
displayMainSource?: (context: CanvasRenderingContext2D,data: ImageKnifeData, imageKnifeOption:ImageKnifeOption, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)=>boolean
|
||||
|
||||
// 展示重试图层
|
||||
displayRetryholder?: (context: CanvasRenderingContext2D,data: ImageKnifeData, imageKnifeOption:ImageKnifeOption, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)=>boolean
|
||||
|
||||
// 展示失败占位图
|
||||
displayErrorholder?: (context: CanvasRenderingContext2D,data: ImageKnifeData, imageKnifeOption:ImageKnifeOption, compWidth:number,compHeight:number, setGifTimeId?:(timeId:number)=>void)=>boolean
|
||||
|
||||
}
|
|
@ -46,7 +46,7 @@ export class DownloadClient implements IDataFetch {
|
|||
loadTask = downloadTask;
|
||||
|
||||
loadTask.on('progress', (receivedSize, totalSize) => {
|
||||
let percent = Math.round(((receivedSize * 1.0) / (totalSize * 1.0)) * 100) + "%"
|
||||
let percent = Math.round(((receivedSize * 1.0) / (totalSize * 1.0)) * 100)
|
||||
if (request.progressFunc) {
|
||||
request.progressFunc(percent);
|
||||
}
|
||||
|
|
|
@ -23,11 +23,14 @@ import{DiskCacheProxy} from "../requestmanage/DiskCacheProxy"
|
|||
import{FileTypeUtil} from "../utils/FileTypeUtil"
|
||||
import{IDataFetch} from "../../imageknife/networkmanage/IDataFetch"
|
||||
import{IResourceFetch} from "../../imageknife/resourcemanage/IResourceFetch"
|
||||
import{ImageKnifeData} from "../ImageKnifeData"
|
||||
import{ImageKnifeData,ImageKnifeType} from "../ImageKnifeData"
|
||||
import {AllCacheInfo, IAllCacheInfoCallback} from "../../imageknife/interface/IAllCacheInfoCallback"
|
||||
import{ParseImageUtil} from '../utils/ParseImageUtil'
|
||||
import{IParseImage} from '../interface/IParseImage'
|
||||
import image from "@ohos.multimedia.image"
|
||||
import { SVGParseImpl } from '../utils/svg/SVGParseImpl'
|
||||
import { GIFParseImpl } from '../utils/gif/GIFParseImpl'
|
||||
import { GIFFrame } from '../utils/gif/GIFFrame'
|
||||
|
||||
export interface AsyncString {
|
||||
(data: string): void;
|
||||
|
@ -198,39 +201,24 @@ export class RequestManager {
|
|||
let fileTypeUtil = new FileTypeUtil();
|
||||
let typeValue = fileTypeUtil.getFileType(arrayBuffer)
|
||||
console.log("RequstManager - 文件类型为= " + typeValue)
|
||||
if ((ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag) || ImageKnifeData.SVG == typeValue) {
|
||||
// 将图片资源 转换为文件地址
|
||||
let folderPath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder;
|
||||
let filePath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder + "/"
|
||||
+ Md5.hashStr(this.options.generateDataKey) + "." + typeValue;
|
||||
let filename = Md5.hashStr(this.options.generateDataKey) + "." + typeValue;
|
||||
new Promise((resolve, reject) => {
|
||||
// 存文件至svg目录,并且记录文件名
|
||||
resolve("svg gif 文件开始本地保存!");
|
||||
// gif处理
|
||||
if(ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag){
|
||||
// 处理gif
|
||||
this.gifProcess(onComplete,onError, arrayBuffer,typeValue,(imageKnifeData)=>{
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
|
||||
})
|
||||
.then((res) => {
|
||||
// 创建文件
|
||||
FileUtils.getInstance()
|
||||
.createFileProcess(folderPath, filePath, arrayBuffer);
|
||||
// 写入记录
|
||||
FileUtils.getInstance()
|
||||
.writeData(this.options.getFilesPath() +
|
||||
"/" + this.options._svgAndGifFolder + "/" + this.options._svgAndGifCommitFile, filename + "\n");
|
||||
console.log("svg gif 本地保存成功 输出!");
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.STRING, filePath, typeValue);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
}else if(ImageKnifeData.SVG == typeValue){
|
||||
// 处理svg
|
||||
this.svgProcess(onComplete,onError,arrayBuffer,typeValue,(imageKnifeData)=>{
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey,imageKnifeData)
|
||||
})
|
||||
.catch((err) => {
|
||||
onError(err)
|
||||
})
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (request.transformations[0]) {
|
||||
request.transformations[0].transform(arrayBuffer, request, (error, pixelMap: PixelMap) => {
|
||||
// 输出给Image
|
||||
if (pixelMap) {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue);
|
||||
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
|
||||
this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
} else {
|
||||
|
@ -240,7 +228,7 @@ export class RequestManager {
|
|||
}
|
||||
else {
|
||||
let success = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
}
|
||||
|
@ -310,29 +298,16 @@ export class RequestManager {
|
|||
// 步骤一:文件转为pixelMap 然后变换 给Image组件
|
||||
let fileTypeUtil = new FileTypeUtil();
|
||||
let typeValue = fileTypeUtil.getFileType(source);
|
||||
if (((ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag) || ImageKnifeData.SVG == typeValue)) {
|
||||
// 将图片资源 转换为文件地址
|
||||
let folderPath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder;
|
||||
let filePath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder + "/"
|
||||
+ Md5.hashStr(this.options.generateDataKey) + "." + typeValue;
|
||||
let filename = Md5.hashStr(this.options.generateDataKey) + "." + typeValue;
|
||||
new Promise((resolve, reject) => {
|
||||
// 存文件至svg目录,并且记录文件名
|
||||
resolve("svg gif 文件开始本地保存!");
|
||||
}).then((res) => {
|
||||
FileUtils.getInstance()
|
||||
.createFileProcess(folderPath, filePath, source);
|
||||
FileUtils.getInstance()
|
||||
.writeData(this.options.getFilesPath() +
|
||||
"/" + this.options._svgAndGifFolder + "/" + this.options._svgAndGifCommitFile, filename + "\n");
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.STRING, filePath, typeValue)
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
// 解析磁盘文件 gif 和 svg
|
||||
if(ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag){
|
||||
// 处理gif
|
||||
this.gifProcess(onComplete,onError,source,typeValue, (imageKnifeData)=>{
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
|
||||
})
|
||||
.catch((err) => {
|
||||
onError(err)
|
||||
}else if(ImageKnifeData.SVG == typeValue){
|
||||
this.svgProcess(onComplete,onError, source, typeValue, (imageKnifeData)=>{
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
|
||||
})
|
||||
|
||||
} else {
|
||||
if (this.options.transformations[0]) {
|
||||
if (this.options.thumbSizeMultiplier) {
|
||||
|
@ -345,7 +320,7 @@ export class RequestManager {
|
|||
let thumbError = this.options.thumbholderOnError.bind(this.options);
|
||||
this.options.transformations[0].transform(source, thumbOption, (error, pixelMap: PixelMap) => {
|
||||
if (pixelMap) {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
|
||||
thumbCallback(imageKnifeData);
|
||||
} else {
|
||||
thumbError(error);
|
||||
|
@ -355,7 +330,7 @@ export class RequestManager {
|
|||
this.options.transformations[0].transform(source, request, (error, pixelMap: PixelMap) => {
|
||||
if (pixelMap) {
|
||||
// 保存一份变换后的图片PixelMap到MemoryCache
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
} else {
|
||||
|
@ -368,7 +343,7 @@ export class RequestManager {
|
|||
this.options.transformations[0].transform(source, request, (error, pixelMap: PixelMap) => {
|
||||
if (pixelMap) {
|
||||
// 保存一份变换后的图片PixelMap到MemoryCache
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
} else {
|
||||
|
@ -382,13 +357,13 @@ export class RequestManager {
|
|||
let thumbCallback = this.options.thumbholderOnComplete.bind(this.options);
|
||||
let thumbError = this.options.thumbholderOnError.bind(this.options);
|
||||
let thumbSuccess = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
thumbCallback(imageKnifeData);
|
||||
}
|
||||
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
|
||||
setTimeout(()=>{
|
||||
let success = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
}
|
||||
|
@ -397,7 +372,7 @@ export class RequestManager {
|
|||
}
|
||||
else {
|
||||
let success = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
}
|
||||
|
@ -416,13 +391,13 @@ export class RequestManager {
|
|||
let thumbCallback = this.options.thumbholderOnComplete.bind(this.options);
|
||||
let thumbError = this.options.thumbholderOnError.bind(this.options);
|
||||
let thumbSuccess = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
thumbCallback(imageKnifeData);
|
||||
}
|
||||
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
|
||||
setTimeout(()=>{
|
||||
let success = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
}
|
||||
|
@ -430,7 +405,7 @@ export class RequestManager {
|
|||
},this.options.thumbDelayTime)
|
||||
}else{
|
||||
let success = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, typeValue)
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
}
|
||||
|
@ -456,40 +431,35 @@ export class RequestManager {
|
|||
onError("暂不支持 下载文件类型!类型=" + filetype);
|
||||
return;
|
||||
}
|
||||
if ((ImageKnifeData.GIF == filetype && !this.options.dontAnimateFlag) || ImageKnifeData.SVG == filetype) {
|
||||
// 将图片资源 转换为文件地址
|
||||
let folderPath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder;
|
||||
let filePath = this.options.getFilesPath() + "/" + this.options._svgAndGifFolder + "/"
|
||||
+ Md5.hashStr(this.options.generateDataKey) + "." + filetype;
|
||||
let filename = Md5.hashStr(this.options.generateDataKey) + "." + filetype;
|
||||
// 1.文件保存 2.内存缓存 3.输出结果
|
||||
new Promise((resolve, reject) => {
|
||||
// 存文件至svg目录,并且记录文件名
|
||||
resolve("svg gif 文件开始本地保存!");
|
||||
|
||||
// 解析磁盘文件 gif 和 svg
|
||||
if(ImageKnifeData.GIF == filetype && !this.options.dontAnimateFlag){
|
||||
// 处理gif
|
||||
this.gifProcess(onComplete,onError,source,filetype, (imageKnifeData)=>{
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
|
||||
})
|
||||
.then((res) => {
|
||||
FileUtils.getInstance()
|
||||
.createFileProcess(folderPath, filePath, source);
|
||||
FileUtils.getInstance()
|
||||
.writeData(this.options.getFilesPath() +
|
||||
"/" + this.options._svgAndGifFolder + "/" + this.options._svgAndGifCommitFile, filename + "\n");
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.STRING, filePath, filetype);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
onComplete(imageKnifeData);
|
||||
})
|
||||
.catch((err) => {
|
||||
onError(err)
|
||||
})
|
||||
|
||||
// 保存二级磁盘缓存
|
||||
new Promise((resolve, reject) => {
|
||||
resolve(source)
|
||||
})
|
||||
.then(async (arraybuffer: ArrayBuffer) => {
|
||||
Promise.resolve(source)
|
||||
.then(async (arraybuffer: ArrayBuffer)=>{
|
||||
await this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("save diskLruCache error=" + err);
|
||||
.catch(err=>{
|
||||
console.log('download file is ='+ImageKnifeData.GIF+'and save diskLruCache error ='+ err)
|
||||
})
|
||||
}else if(ImageKnifeData.SVG == filetype){
|
||||
// 处理svg
|
||||
this.svgProcess(onComplete,onError, source, filetype, (imageKnifeData)=>{
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
|
||||
})
|
||||
|
||||
// 保存二级磁盘缓存
|
||||
Promise.resolve(source)
|
||||
.then(async (arraybuffer: ArrayBuffer)=>{
|
||||
await this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
|
||||
})
|
||||
.catch(err=>{
|
||||
console.log('download file is ='+ImageKnifeData.SVG+'and save diskLruCache error ='+ err)
|
||||
})
|
||||
} else {
|
||||
// 进行变换
|
||||
|
@ -512,7 +482,7 @@ export class RequestManager {
|
|||
let thumbCallback = this.options.thumbholderOnComplete.bind(this.options);
|
||||
let thumbError = this.options.thumbholderOnError.bind(this.options);
|
||||
let thumbSuccess = (value: PixelMap) => {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, filetype);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
thumbCallback(imageKnifeData);
|
||||
}
|
||||
this.mParseImageUtil.parseImageThumbnail(this.options.thumbSizeMultiplier, source, thumbSuccess, thumbError);
|
||||
|
@ -532,17 +502,18 @@ export class RequestManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
createImageKnifeData(imageKnifeType:string, imageKnifeValue:PixelMap|string|Resource, imageKnifeSourceType:string):ImageKnifeData{
|
||||
let imageKnifeData = new ImageKnifeData();
|
||||
imageKnifeData.imageKnifeType = imageKnifeType;
|
||||
imageKnifeData.imageKnifeValue = imageKnifeValue;
|
||||
imageKnifeData.imageKnifeSourceType = imageKnifeSourceType;
|
||||
return imageKnifeData;
|
||||
createImagePixelMap(imageKnifeType: ImageKnifeType, imageKnifeValue: PixelMap): ImageKnifeData{
|
||||
return ImageKnifeData.createImagePixelMap(imageKnifeType,imageKnifeValue);
|
||||
}
|
||||
|
||||
createImageGIFFrame(imageKnifeType: ImageKnifeType, imageKnifeValue: GIFFrame[]): ImageKnifeData{
|
||||
return ImageKnifeData.createImageGIFFrame(imageKnifeType,imageKnifeValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private saveCacheAndDisk(value: PixelMap, filetype:string, onComplete, source:ArrayBuffer) {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, value, filetype);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
|
||||
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
|
||||
let save2DiskCache = async (arraybuffer) => {
|
||||
await this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
|
||||
|
@ -565,7 +536,7 @@ export class RequestManager {
|
|||
let thumbError = this.options.thumbholderOnError.bind(this.options);
|
||||
this.options.transformations[0].transform(source, thumbOption, (error, pixelMap: PixelMap) => {
|
||||
if (pixelMap) {
|
||||
let imageKnifeData = this.createImageKnifeData(ImageKnifeData.PIXELMAP, pixelMap, filetype);
|
||||
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
|
||||
thumbCallback(imageKnifeData);
|
||||
} else {
|
||||
thumbError(error);
|
||||
|
@ -581,6 +552,41 @@ export class RequestManager {
|
|||
})
|
||||
}, this.options.thumbDelayTime)
|
||||
}
|
||||
private svgProcess(onComplete, onError, arraybuffer, typeValue, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
|
||||
let svgParseImpl = new SVGParseImpl()
|
||||
let size = { width: this.options.size.width, height: this.options.size.height }
|
||||
svgParseImpl.parseSvg(arraybuffer, size).then((value: PixelMap) => {
|
||||
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
|
||||
if(cacheStrategy){
|
||||
cacheStrategy(imageKnifeData)
|
||||
}
|
||||
onComplete(imageKnifeData)
|
||||
}).catch(err => {
|
||||
onError(err)
|
||||
})
|
||||
}
|
||||
|
||||
private gifProcess(onComplete, onError, arraybuffer, typeValue, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
|
||||
let gifParseImpl = new GIFParseImpl()
|
||||
gifParseImpl.parseGifs(arraybuffer, (data?,err?)=>{
|
||||
if(err){
|
||||
onError(err)
|
||||
}
|
||||
console.log("gifProcess data is null:"+(data == null));
|
||||
if(!!data){
|
||||
let imageKnifeData = this.createImageGIFFrame(ImageKnifeType.GIFFRAME,data)
|
||||
console.log('gifProcess 生成gif 返回数据类型')
|
||||
if(cacheStrategy){
|
||||
console.log('gifProcess 生成gif并且存入了缓存策略')
|
||||
cacheStrategy(imageKnifeData)
|
||||
}
|
||||
onComplete(imageKnifeData)
|
||||
}else{
|
||||
onError('Parse GIF callback data is null, you need check callback data!')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue