/*
* Copyright (C) 2024 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 { PixelMapTransformation } from './PixelMapTransformation';
import { Size } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { resourceManager } from '@kit.LocalizationKit';
import { CalculatePixelUtils } from '../utils/CalculatePixelUtils';
import { ColorUtils } from '../utils/ColorUtils';
import { PixelEntry } from './entry/PixelEntry';
import { application } from '@kit.AbilityKit';
/**
* 图片变换:遮罩效果
*/
@Sendable
export class MaskTransformation extends PixelMapTransformation {
private mResourceId: number;
private mResourceModuleName: string;
constructor(resource: Resource) {
super();
this.mResourceId = resource.id;
this.mResourceModuleName = resource.moduleName;
}
getName(): string {
return this.constructor.name + ';resourceId:' + this.mResourceId + ';resourceModuleName:' + this.mResourceModuleName;
}
async transform(context: Context, toTransform: PixelMap, width: number, height: number): Promise<PixelMap> {
let imageInfo = await toTransform.getImageInfo();
let size: Size = {
width: imageInfo.size.width,
height: imageInfo.size.height
};
if (!size) {
console.error('MaskTransformation The image size does not exist.');
return toTransform;
}
let pixelMapWidth: number = size.width;
let pixelMapHeight: number = size.height;
let targetWidth: number = width;
let targetHeight: number = height;
if (pixelMapWidth > targetWidth && pixelMapHeight > targetHeight) {
let scale = Math.max(targetWidth / pixelMapWidth, targetHeight / pixelMapHeight);
await toTransform.scale(scale, scale);
return await this.openInternal(context, toTransform, scale * pixelMapWidth, scale * pixelMapHeight);
}
return await this.openInternal(context, toTransform, size.width, size.height);
}
private async openInternal(context: Context, bitmap: PixelMap, width: number, height: number): Promise<PixelMap> {
if (context == undefined) {
console.error('MaskTransformation openInternal the context is undefined.');
return bitmap;
}
let moduleContext = await application.createModuleContext(context,this.mResourceModuleName);
if (moduleContext == undefined) {
console.error('MaskTransformation openInternal the moduleContext is undefined.');
return bitmap;
}
let resourceManager = moduleContext.resourceManager as resourceManager.ResourceManager;
if (resourceManager == undefined) {
console.error('MaskTransformation openInternal the resourceManager is undefined.');
return bitmap;
}
let array: Uint8Array = await resourceManager.getMediaContent(this.mResourceId);
let buffer = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset);
let imageSource: image.ImageSource = image.createImageSource(buffer);
let options: image.DecodingOptions = {
editable: true,
desiredSize: {
width: width,
height: height
}
};
let maskBitmap: PixelMap = await imageSource.createPixelMap(options);
imageSource.release()
return await this.mask(bitmap, maskBitmap);
}
async mask(bitmap: PixelMap, maskBitmap: PixelMap): Promise<PixelMap> {
let imageInfo = await bitmap.getImageInfo();
let size: Size = {
width: imageInfo.size.width,
height: imageInfo.size.height
};
if (!size) {
console.error('MaskTransformation mask the image size does not exist.');
return bitmap;
}
let width = size.width;
let height = size.height;
let rgbData = CalculatePixelUtils.createInt2DArray(height, width);
let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());
await bitmap.readPixelsToBuffer(bufferData);
let dataArray = new Uint8Array(bufferData);
let ph = 0;
let pw = 0;
for (let index = 0; index < dataArray.length; index += 4) {
const r = dataArray[index];
const g = dataArray[index+1];
const b = dataArray[index+2];
const f = dataArray[index+3];
let entry = new PixelEntry();
entry.a = 0;
entry.b = b;
entry.g = g;
entry.r = r;
entry.f = f;
entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b);
rgbData[ph][pw] = ColorUtils.rgb(entry.r, entry.g, entry.b);
if (pw == width - 1) {
pw = 0;
ph++;
} else {
pw++;
}
}
let imageInfoMask = await maskBitmap.getImageInfo();
let sizeMask: Size = {
width: imageInfoMask.size.width,
height: imageInfoMask.size.height
};
if (!sizeMask) {
console.error('MaskTransformation mask the sizeMask size does not exist.');
return bitmap;
}
let widthMask = sizeMask.width;
let heightMask = sizeMask.height;
let rgbDataMask = CalculatePixelUtils.createInt2DArray(heightMask, widthMask);
let pixEntry: Array<PixelEntry> = new Array();
let bufferDataM = new ArrayBuffer(maskBitmap.getPixelBytesNumber());
await maskBitmap.readPixelsToBuffer(bufferDataM);
let dataArrayM = new Uint8Array(bufferDataM);
let phM = 0;
let pwM = 0;
for (let index = 0; index < dataArrayM.length; index += 4) {
const r = dataArrayM[index];
const g = dataArrayM[index+1];
const b = dataArrayM[index+2];
const f = dataArrayM[index+3];
let entry = new PixelEntry();
entry.a = 0;
entry.b = b;
entry.g = g;
entry.r = r;
entry.f = f;
entry.pixel = ColorUtils.rgb(entry.r, entry.g, entry.b);
pixEntry.push(entry);
if (entry.r == 0 && entry.g == 0 && entry.b == 0) {
rgbDataMask[phM][pwM] = rgbData[phM][pwM];
} else {
rgbDataMask[phM][pwM] = ColorUtils.rgb(entry.r, entry.g, entry.b);
}
if (pwM == widthMask - 1) {
pwM = 0;
phM++;
} else {
pwM++;
}
}
let bufferNewData = new ArrayBuffer(maskBitmap.getPixelBytesNumber());
let dataNewArray = new Uint8Array(bufferNewData);
let index = 0;
let mh = 0;
let nw = 0;
for (let i = 0; i < dataNewArray.length; i += 4) {
let pixel1 = rgbDataMask[mh][nw];
if (nw == widthMask - 1) {
nw = 0;
mh++;
} else {
nw++;
}
let pR = ColorUtils.red(pixel1);
let pG = ColorUtils.green(pixel1);
let pB = ColorUtils.blue(pixel1);
dataNewArray[i] = pR;
dataNewArray[i+1] = pG;
dataNewArray[i+2] = pB;
dataNewArray[i+3] = pixEntry[index].f;
index++;
}
await maskBitmap.writeBufferToPixels(bufferNewData);
return maskBitmap;
}
}