Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encapsulating PAL/ImageData #15485

Merged
merged 29 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
861d9ff
Encapsulating PAL/ImageData
qiuguohua Jun 6, 2023
51a2632
Delete unused files
qiuguohua Jun 20, 2023
8c48d24
Add PAL/Image declaration file
qiuguohua Jun 20, 2023
0215a1c
Different platform implementations of ImageData
qiuguohua Jun 20, 2023
b8408b6
Add copyright information
qiuguohua Jun 20, 2023
5c34e5a
fix CI
qiuguohua Jun 21, 2023
641808c
1. Adding the copyImagesToTexture interface;
qiuguohua Jun 27, 2023
ace9911
Rename 'downloadImage' to 'loadImage'.
qiuguohua Jun 27, 2023
29f07a5
Fix ci error
qiuguohua Jun 27, 2023
97a0645
Fix ci warning
qiuguohua Jun 29, 2023
906676c
Merge remote-tracking branch 'origin/develop' into develop-pal-image
qiuguohua Jun 29, 2023
750a332
Merge branch 'develop' of github.com:cocos/cocos-engine into develop-…
qiuguohua Jun 29, 2023
36524ac
Rename 'nativeData' to 'rawData'
qiuguohua Jun 29, 2023
6981e2a
Optimizing the implementation of loadiamge.
qiuguohua Jul 3, 2023
ea77a5d
Submit download-dom-image.ts.
qiuguohua Jul 3, 2023
d9a979f
Modify comments
qiuguohua Jul 4, 2023
2d67b2d
Modify comments
qiuguohua Jul 4, 2023
fb788ad
Merge remote-tracking branch 'origin/develop' into develop-pal-image
qiuguohua Jul 31, 2023
c74993c
Optimize pal/image implementation
qiuguohua Jul 31, 2023
556caee
Optimize the design and deprecate some of dom's interfaces.
qiuguohua Aug 2, 2023
7315c72
(1) Do not use console.log.
qiuguohua Aug 7, 2023
8d4ce62
Modify the comment
qiuguohua Aug 7, 2023
e7bc49f
Remove empty lines
qiuguohua Aug 7, 2023
7ed95d2
Merge remote-tracking branch 'origin/develop' into develop-pal-image
qiuguohua Aug 7, 2023
33eca30
gfx does not rely on imageasset, it relies on imagedata.
qiuguohua Aug 10, 2023
43055bb
Remove redundant comments
qiuguohua Aug 10, 2023
4771e1a
Fix unit test test failures
qiuguohua Aug 11, 2023
2941de2
Change the name of the imageAsset parameter to imageSource.
qiuguohua Aug 14, 2023
432011c
Merge remote-tracking branch 'origin/develop' into develop-pal-image
qiuguohua Aug 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions @types/jsb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ declare namespace jsb {
setVerifyCallback (verifyCallback: (path: string, asset: ManifestAsset) => boolean): void;
setEventCallback (eventCallback: (event: EventAssetsManager) => void): void;
}

export class JSBNativeDataHolder {

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why export it? Does developers need to use it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to declare the type, if the type is not declared, the return would need to be of type any.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we don't want to export it to developers. So should find a way to export internally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The jsb namespace is deprecated and will be used internally as an engine.

}

declare namespace ns {
Expand Down
47 changes: 47 additions & 0 deletions @types/pal/image.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
declare module 'pal/image' {
Copy link
Contributor

@PPpro PPpro Jun 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's better we add more comment on every 'pal/image' public interface
it's OK to only have en version of comment

the comment sometimes is necessary like what's the difference between data and nativeData
what is format, what number it may returns, what each number represents, is it better to be an enum ?
when to use static method downloadImage, why not to set src directly, or why not use reset instead of setting src

image.d.ts is a design about pal/image, some usage and behavior of interfaces can be fixed in the form of documents to avoid abuse.


export type ImageSource = import('pal/image/types').ImageSource;
export type IMemoryImageSource = import('pal/image/types').IMemoryImageSource;
export type PixelFormat = import('cocos/asset/assets/asset-enum').PixelFormat;
export type RawDataType = import('pal/image/types').RawDataType;
export class ImageData {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not call it Image directly? ImageData seems just raw data like https://developer.mozilla.org/en-US/docs/Web/API/ImageData .
Image includes data property is fine. But ImageData also contains data property which is confused in my opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
They are defined in Dom.

There are currently two types of data, one is imagesource (HtmlImageElement) and the other is Raw image data, both of which currently need to exist.

The data attribute prefers to be compatible, and I understand that it should be named source would be better.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DOM's Image is in global namespace, but our encapsulated Image could be in engine's namespace, for example cc. Will the class names in different namespace cause conflict?

constructor (imageAsset?: ImageSource | ArrayBufferView);
/**
* Destroy resources.
*/
destroy (): void;

/**
* Get and set image data source.
* @param value Image data source.
*/
get source(): ImageSource;
set source(value: ImageSource);

/**
* Get image width.
*/
get width(): number;

/**
* Get image height.
*/
get height(): number;

/**
* Load image via local url or web url.
*/
static loadImage (urlAndBase64: string): Promise<ImageData>

/**
* Get raw image data, in web platform is image source(like data interface), in native platform is image raw data.
*/
getRawData (): RawDataType | null;

/**
* Set image data source.
* @param data Image data source.
*/
reset(data?: ImageSource | ArrayBufferView): void;
}
}
12 changes: 8 additions & 4 deletions cc.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,8 @@
"pal/input": "pal/input/web/index.ts",
"pal/env": "pal/env/web/env.ts",
"pal/pacer": "pal/pacer/pacer-web.ts",
"pal/wasm": "pal/wasm/wasm-web.ts"
"pal/wasm": "pal/wasm/wasm-web.ts",
"pal/image":"pal/image/web/image-data.ts"
}
},
{
Expand All @@ -314,7 +315,8 @@
"pal/input": "pal/input/native/index.ts",
"pal/env": "pal/env/native/env.ts",
"pal/pacer": "pal/pacer/pacer-native.ts",
"pal/wasm": "pal/wasm/wasm-native.ts"
"pal/wasm": "pal/wasm/wasm-native.ts",
"pal/image":"pal/image/native/image-data.ts"
}
},
{
Expand All @@ -328,7 +330,8 @@
"pal/input": "pal/input/minigame/index.ts",
"pal/env": "pal/env/minigame/env.ts",
"pal/pacer": "pal/pacer/pacer-minigame.ts",
"pal/wasm": "pal/wasm/wasm-minigame.ts"
"pal/wasm": "pal/wasm/wasm-minigame.ts",
"pal/image":"pal/image/minigame/image-data.ts"
}
},
{
Expand All @@ -342,7 +345,8 @@
"pal/input": "pal/input/minigame/index.ts",
"pal/env": "pal/env/runtime/env.ts",
"pal/pacer": "pal/pacer/pacer-minigame.ts",
"pal/wasm": "pal/wasm/wasm-minigame.ts"
"pal/wasm": "pal/wasm/wasm-minigame.ts",
"pal/image":"pal/image/minigame/image-data.ts"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion cocos/2d/assembler/label/font-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export class LetterRenderTexture extends Texture2D {
region.texOffset.y = y;
region.texExtent.width = image.width;
region.texExtent.height = image.height;
gfxDevice.copyTexImagesToTexture([image.data as HTMLCanvasElement], gfxTexture, [region]);
gfxDevice.copyImagesToTexture([image], gfxTexture, [region]);
}
}

Expand Down
17 changes: 14 additions & 3 deletions cocos/2d/assets/sprite-frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@

import { ccclass } from 'cc.decorator';
import { EDITOR, TEST, BUILD } from 'internal:constants';
import { IMemoryImageSource } from '../../../pal/image/types';
import { Mat4, Rect, Size, Vec2, Vec3, Vec4, cclegacy, errorID, warnID, js } from '../../core';
import { Asset } from '../../asset/assets/asset';
import { TextureBase } from '../../asset/assets/texture-base';
import { ImageAsset, ImageSource } from '../../asset/assets/image-asset';
import { ImageAsset } from '../../asset/assets/image-asset';
import { Texture2D } from '../../asset/assets/texture-2d';
import { dynamicAtlasManager } from '../utils/dynamic-atlas/atlas-manager';
import { Mesh } from '../../3d/assets/mesh';
Expand Down Expand Up @@ -248,9 +249,19 @@ export class SpriteFrame extends Asset {
* @param imageSourceOrImageAsset @en ImageAsset or ImageSource, ImageSource could be HTMLCanvasElement, HTMLImageElement, IMemoryImageSource.
* @zh 图像资源或图像原始图像源,图像原始图像源支持 HTMLCanvasElement HTMLImageElement IMemoryImageSource 三种资源。
* @returns @en SpriteFrame asset. @zh 精灵资源。
* @deprecated @en Recommended use of the ImageAsset object. @zh 推荐使用ImageAsset对象
*/
public static createWithImage (imageSourceOrImageAsset: ImageSource | ImageAsset): SpriteFrame {
const img = imageSourceOrImageAsset instanceof ImageAsset ? imageSourceOrImageAsset : new ImageAsset(imageSourceOrImageAsset);
public static createWithImage (imageSourceOrImageAsset: HTMLCanvasElement | HTMLImageElement | ImageBitmap): SpriteFrame;
/**
* @en Create a SpriteFrame object by an image asset or an native image asset.
* @zh 通过 Image 资源或者平台相关 Image 对象创建一个 SpriteFrame 资源。
* @param imageSourceOrImageAsset @en ImageAsset or ImageSource, ImageSource could be HTMLCanvasElement, HTMLImageElement, IMemoryImageSource.
* @zh 图像资源或图像原始图像源,图像原始图像源支持 HTMLCanvasElement HTMLImageElement IMemoryImageSource 三种资源。
* @returns @en SpriteFrame asset. @zh 精灵资源。
*/
public static createWithImage (imageSourceOrImageAsset: ImageAsset | IMemoryImageSource): SpriteFrame;
public static createWithImage (imageSourceOrImageAsset: ImageAsset | IMemoryImageSource | HTMLCanvasElement | HTMLImageElement | ImageBitmap): SpriteFrame {
const img = imageSourceOrImageAsset instanceof ImageAsset ? imageSourceOrImageAsset : new ImageAsset(imageSourceOrImageAsset as IMemoryImageSource);
const tex = new Texture2D();
tex.image = img;
const spf = new SpriteFrame();
Expand Down
2 changes: 1 addition & 1 deletion cocos/2d/utils/dynamic-atlas/atlas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,6 @@ export class DynamicAtlasTexture extends Texture2D {
region.texOffset.y = y;
region.texExtent.width = image.width;
region.texExtent.height = image.height;
gfxDevice.copyTexImagesToTexture([image.data as HTMLCanvasElement], gfxTexture, [region]);
gfxDevice.copyImagesToTexture([image], gfxTexture, [region]);
}
}
17 changes: 5 additions & 12 deletions cocos/3d/skinned-mesh-renderer/skinned-mesh-batch-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { CCString, Mat4, Vec2, Vec3, cclegacy, warn } from '../../core';
import { AttributeName, FormatInfos, Format, Type, Attribute, BufferTextureCopy } from '../../gfx';
import { mapBuffer, readBuffer, writeBuffer } from '../misc/buffer';
import { SkinnedMeshRenderer } from './skinned-mesh-renderer';
import { ImageAsset } from '../../asset/assets';

const repeat = (n: number): number => n - Math.floor(n);
const batch_id: Attribute = new Attribute(AttributeName.ATTR_BATCH_ID, Format.R32F);
Expand Down Expand Up @@ -453,9 +454,8 @@ export class SkinnedMeshBatchRenderer extends SkinnedMeshRenderer {
}

protected cookTextures (target: Texture2D, prop: string, passIdx: number): void {
const texImages: TexImageSource[] = [];
const texImages: ImageAsset[] = [];
const texImageRegions: BufferTextureCopy[] = [];
const texBuffers: ArrayBufferView[] = [];
const texBufferRegions: BufferTextureCopy[] = [];
for (let u = 0; u < this.units.length; u++) {
const unit = this.units[u];
Expand All @@ -467,20 +467,13 @@ export class SkinnedMeshBatchRenderer extends SkinnedMeshRenderer {
region.texOffset.y = unit.offset.y * this.atlasSize;
region.texExtent.width = unit.size.x * this.atlasSize;
region.texExtent.height = unit.size.y * this.atlasSize;
const { data } = partial.image;
if (!ArrayBuffer.isView(data)) {
texImages.push(data);
texImageRegions.push(region);
} else {
texBuffers.push(data);
texBufferRegions.push(region);
}
texImages.push(partial.image);
texImageRegions.push(region);
}
}
const gfxTex = target.getGFXTexture()!;
const { device } = cclegacy.director.root!;
if (texBuffers.length > 0) { device.copyBuffersToTexture(texBuffers, gfxTex, texBufferRegions); }
if (texImages.length > 0) { device.copyTexImagesToTexture(texImages, gfxTex, texImageRegions); }
if (texImages.length > 0) { device.copyImagesToTexture(texImages, gfxTex, texImageRegions); }
}

protected createTexture (prop: string): Texture2D {
Expand Down
4 changes: 2 additions & 2 deletions cocos/asset/asset-manager/builtin-res-mgr.jsb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import { TEST, EDITOR, EDITOR_NOT_IN_PREVIEW } from 'internal:constants';
import { SpriteFrame } from '../../2d/assets/sprite-frame';
import type { ImageSource } from '../assets/image-asset';
import type { IMemoryImageSource } from '../../../pal/image/types';
import assetManager from '../asset-manager/asset-manager';
import { BuiltinBundleName } from '../asset-manager/shared';
import Bundle from '../asset-manager/bundle';
Expand Down Expand Up @@ -56,7 +56,7 @@ builtinResMgrProto.init = function () {
blackValueView[offset + 3] = 255;
}

const blackMemImageSource: ImageSource = {
const blackMemImageSource: IMemoryImageSource = {
width: len,
height: len,
_data: blackValueView,
Expand Down
15 changes: 8 additions & 7 deletions cocos/asset/asset-manager/builtin-res-mgr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
*/

import { EDITOR, EDITOR_NOT_IN_PREVIEW, TEST } from 'internal:constants';
import { IMemoryImageSource } from '../../../pal/image/types';
import { Asset } from '../assets/asset';
import { ImageAsset, ImageSource } from '../assets/image-asset';
import { ImageAsset } from '../assets/image-asset';
import { SpriteFrame } from '../../2d/assets/sprite-frame';
import { Texture2D } from '../assets/texture-2d';
import { TextureCube } from '../assets/texture-cube';
Expand Down Expand Up @@ -119,47 +120,47 @@ export class BuiltinResMgr {
offset += halfDefaultSize * numChannels;
}

const blackMemImageSource: ImageSource = {
const blackMemImageSource: IMemoryImageSource = {
width: len,
height: len,
_data: blackValueView,
_compressed: false,
format: Texture2D.PixelFormat.RGBA8888,
};

const emptyMemImageSource: ImageSource = {
const emptyMemImageSource: IMemoryImageSource = {
width: len,
height: len,
_data: emptyValueView,
_compressed: false,
format: Texture2D.PixelFormat.RGBA8888,
};

const greyMemImageSource: ImageSource = {
const greyMemImageSource: IMemoryImageSource = {
width: len,
height: len,
_data: greyValueView,
_compressed: false,
format: Texture2D.PixelFormat.RGBA8888,
};

const whiteMemImageSource: ImageSource = {
const whiteMemImageSource: IMemoryImageSource = {
width: len,
height: len,
_data: whiteValueView,
_compressed: false,
format: Texture2D.PixelFormat.RGBA8888,
};

const normalMemImageSource: ImageSource = {
const normalMemImageSource: IMemoryImageSource = {
width: len,
height: len,
_data: normalValueView,
_compressed: false,
format: Texture2D.PixelFormat.RGBA8888,
};

const defaultMemImageSource: ImageSource = {
const defaultMemImageSource: IMemoryImageSource = {
width: defaultSize,
height: defaultSize,
_data: defaultValueView,
Expand Down
36 changes: 8 additions & 28 deletions cocos/asset/asset-manager/download-dom-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,16 @@
THE SOFTWARE.
*/

import { XIAOMI } from 'internal:constants';
import { getError } from '../../core';
import { ccwindow } from '../../core/global-exports';
import { ImageData } from 'pal/image';

export default function downloadDomImage (
url: string,
options: Record<string, any>,
onComplete: ((err: Error | null, data?: HTMLImageElement | null) => void),
): HTMLImageElement {
const img = new ccwindow.Image();

// NOTE: on xiaomi platform, we need to force setting img.crossOrigin as 'anonymous'
if (ccwindow.location.protocol !== 'file:' || XIAOMI) {
img.crossOrigin = 'anonymous';
}

function loadCallback (): void {
img.removeEventListener('load', loadCallback);
img.removeEventListener('error', errorCallback);
if (onComplete) { onComplete(null, img); }
}

function errorCallback (): void {
img.removeEventListener('load', loadCallback);
img.removeEventListener('error', errorCallback);
if (onComplete) { onComplete(new Error(getError(4930, url))); }
}

img.addEventListener('load', loadCallback);
img.addEventListener('error', errorCallback);
img.src = url;
return img;
onComplete: ((err: Error | null, data?: ImageData | null) => void),
): void {
ImageData.loadImage(url).then((imageData) => {
onComplete(null, imageData);
}).catch((err: Error) => {
onComplete(err);
});
}
4 changes: 2 additions & 2 deletions cocos/asset/asset-manager/downloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
import { BUILD, EDITOR, EDITOR_NOT_IN_PREVIEW } from 'internal:constants';
import { sys, js, misc, path, cclegacy } from '../../core';
import Cache from './cache';
import downloadDomImage from './download-dom-image';
import downloadFile from './download-file';
import downloadScript from './download-script';
import { files } from './shared';
import { retry, RetryFunction, urlAppendTimestamp } from './utilities';
import { IConfigOption } from './config';
import { CCON, parseCCONJson, decodeCCONBinary } from '../../serialization/ccon';
import downloadDomImage from './download-dom-image';

export type DownloadHandler = (url: string, options: Record<string, any>, onComplete: ((err: Error | null, data?: any | null) => void)) => void;

Expand All @@ -47,7 +47,7 @@ interface IDownloadRequest {
const REGEX = /^(?:\w+:\/\/|\.+\/).+/;

const downloadImage = (url: string, options: Record<string, any>, onComplete: ((err: Error | null, data?: any | null) => void)): void => {
// if createImageBitmap is valid, we can transform blob to ImageBitmap. Otherwise, just use HTMLImageElement to load
// if createImageBitmap is valid, we can transform blob to ImageBitmap. Otherwise, just use ImageData to load
const func = sys.hasFeature(sys.Feature.IMAGE_BITMAP) && cclegacy.assetManager.allowImageBitmap ? downloadBlob : downloadDomImage;
func(url, options, onComplete);
};
Expand Down
5 changes: 3 additions & 2 deletions cocos/asset/asset-manager/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

import { EDITOR } from 'internal:constants';
import { ImageData } from 'pal/image';
import { ImageAsset } from '../assets/image-asset';
import JsonAsset from '../assets/json-asset';
import { TextAsset } from '../assets/text-asset';
Expand All @@ -39,13 +40,13 @@ import { js } from '../../core';

export type CreateHandler = (id: string, data: any, options: Record<string, any>, onComplete: ((err: Error | null, data?: Asset | Bundle | null) => void)) => void;

function createImageAsset (id: string, data: HTMLImageElement, options: Record<string, any>, onComplete: ((err: Error | null, data?: ImageAsset | null) => void)): void {
function createImageAsset (id: string, imageData: ImageData, options: Record<string, any>, onComplete: ((err: Error | null, data?: ImageAsset | null) => void)): void {
let out: ImageAsset | null = null;
let err: Error | null = null;
try {
out = new ImageAsset();
out._nativeUrl = id;
out._nativeAsset = data;
out._nativeAsset = imageData;
} catch (e) {
err = e as Error;
}
Expand Down
12 changes: 7 additions & 5 deletions cocos/asset/asset-manager/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
THE SOFTWARE.
*/

import { ImageAsset, IMemoryImageSource } from '../assets/image-asset';
import { ImageData } from 'pal/image';
import { IMemoryImageSource } from '../../../pal/image/types';
import { ImageAsset } from '../assets/image-asset';
import { js, warn } from '../../core';
import Cache from './cache';
import deserialize from './deserialize';
Expand Down Expand Up @@ -80,14 +82,14 @@ export class Parser {
/**
* @engineInternal
*/
public parseImage (file: HTMLImageElement | Blob, options: Record<string, any>, onComplete: ((err: Error | null, data?: HTMLImageElement | ImageBitmap | null) => void)): void {
if (file instanceof HTMLImageElement) {
public parseImage (file: ImageData | Blob, options: Record<string, any>, onComplete: ((err: Error | null, data?: ImageData | null) => void)): void {
if (file instanceof ImageData) {
onComplete(null, file);
return;
}
createImageBitmap(file, { premultiplyAlpha: 'none' }).then((result): void => {
minggo marked this conversation as resolved.
Show resolved Hide resolved
onComplete(null, result);
}, (err): void => {
minggo marked this conversation as resolved.
Show resolved Hide resolved
onComplete(null, new ImageData(result));
}, (err: Error): void => {
onComplete(err, null);
});
}
Expand Down
Loading