Skip to content

Commit c2bf9c0

Browse files
committed
fix(ios): improved colorMatrix handling. Should be faster
1 parent ae8d3a7 commit c2bf9c0

File tree

5 files changed

+133
-100
lines changed

5 files changed

+133
-100
lines changed

src/image-colorfilter/index.ios.ts

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,44 @@
11
import { Img } from '@nativescript-community/ui-image';
22
import { applyMixins, colorMatrixProperty, cssProperty } from './index-common';
3-
import { Image } from '@nativescript/core';
43

54
declare module '@nativescript-community/ui-image' {
6-
interface Img {}
7-
}
8-
9-
interface ImgAugmented extends Img {
10-
colorMatrix: number[];
11-
applyColorFilter();
5+
interface Img {
6+
mCIFilter: CIFilter;
7+
initImage();
8+
}
129
}
1310

1411
const FloatConstructor = interop.sizeof(interop.types.id) === 4 ? Float32Array : Float64Array;
1512

1613
class ImgExtended {
1714
nativeImageViewProtected: SDAnimatedImageView | UIImageView;
1815
@cssProperty colorMatrix: number[];
19-
_filter: CIFilter;
16+
mCIFilter: CIFilter;
17+
mCanRequestImage: boolean;
18+
mNeedRequestImage: boolean;
2019
[colorMatrixProperty.setNative](value: number[]) {
2120
if (value) {
22-
if (!this._filter) {
23-
this._filter = CIFilter.filterWithName('CIColorMatrix');
21+
if (!this.mCIFilter) {
22+
this.mCIFilter = CIFilter.filterWithName('CIColorMatrix');
2423
}
25-
this._filter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(0, 4)).buffer as any, 4), 'inputRVector');
26-
this._filter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(5, 9)).buffer as any, 4), 'inputGVector');
27-
this._filter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(10, 14)).buffer as any, 4), 'inputBVector');
28-
this._filter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(15, 19)).buffer as any, 4), 'inputAVector');
29-
this._filter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor([value[4], value[9], value[14], value[19]]).buffer as any, 4), 'inputBiasVector');
24+
this.mCIFilter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(0, 4)).buffer as any, 4), 'inputRVector');
25+
this.mCIFilter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(5, 9)).buffer as any, 4), 'inputGVector');
26+
this.mCIFilter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(10, 14)).buffer as any, 4), 'inputBVector');
27+
this.mCIFilter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor(value.slice(15, 19)).buffer as any, 4), 'inputAVector');
28+
this.mCIFilter.setValueForKey(CIVector.vectorWithValuesCount(new FloatConstructor([value[4], value[9], value[14], value[19]]).buffer as any, 4), 'inputBiasVector');
29+
this.mCIFilter.setName(JSON.stringify(value));
3030
} else {
31-
this._filter = null;
31+
this.mCIFilter = null;
32+
}
33+
if (this instanceof Img) {
34+
if (!this.mCanRequestImage) {
35+
this.mNeedRequestImage = true;
36+
} else {
37+
(this as Img).initImage();
38+
}
39+
} else {
40+
(this as any as ImgExtended3).applyColorFilter();
3241
}
33-
this['applyColorFilter']();
3442
}
3543
}
3644
class ImgExtended2 {
@@ -43,12 +51,13 @@ class ImgExtended3 {
4351
nativeImageViewProtected: SDAnimatedImageView | UIImageView;
4452
nativeViewProtected: SDAnimatedImageView | UIImageView;
4553
_oldImage: UIImage;
46-
_filter: CIFilter;
54+
mCIFilter: CIFilter;
4755

4856
filteredImage(image: UIImage, filter: CIFilter) {
57+
console.log('filteredImage', image, filter);
4958
if (image !== null && filter !== null) {
5059
const tmp = CIImage.alloc().initWithImage(image);
51-
this._filter.setValueForKey(tmp, 'inputImage');
60+
this.mCIFilter.setValueForKey(tmp, 'inputImage');
5261

5362
const outputRect = tmp.extent;
5463
const context = CIContext.contextWithOptions(null);
@@ -64,36 +73,46 @@ class ImgExtended3 {
6473
if (!this._oldImage) {
6574
this._oldImage = image;
6675
}
67-
return this.filteredImage(this._oldImage, this._filter);
76+
return this.filteredImage(this._oldImage, this.mCIFilter);
6877
}
6978
return null;
7079
}
7180
applyColorFilter() {
7281
const nativeView = this.nativeImageViewProtected || this.nativeViewProtected;
73-
nativeView.image = this._applyColorFilter(nativeView.image);
82+
if (nativeView.image) {
83+
nativeView.image = this._applyColorFilter(nativeView.image);
84+
}
7485
}
7586
public _setNativeImage(superCall, ...args) {
87+
// we only need to do that with N Image, Img will use a transformer
88+
if (this instanceof Img) {
89+
superCall.apply(this, args);
90+
return;
91+
}
7692
this._oldImage = args[0];
77-
if (this._filter) {
93+
if (this.mCIFilter) {
7894
args[0] = this._applyColorFilter(args[0]);
7995
}
8096
superCall.apply(this, args);
8197
}
8298
}
8399

84100
let mixinInstalled = false;
85-
export function overrideImgBase() {
101+
export function overrideImgBase(overrideNImage = true) {
86102
applyMixins(Img, [ImgExtended], { override: true });
87103
applyMixins(Img, [ImgExtended2]);
88104
applyMixins(Img, [ImgExtended3], { callWithSuper: true });
89-
applyMixins(Image, [ImgExtended], { override: true });
90-
applyMixins(Image, [ImgExtended2]);
91-
applyMixins(Image, [ImgExtended3], { callWithSuper: true });
105+
if (overrideNImage) {
106+
const Image = require('@nativescript/core').Image;
107+
applyMixins(Image, [ImgExtended], { override: true });
108+
applyMixins(Image, [ImgExtended2]);
109+
applyMixins(Image, [ImgExtended3], { callWithSuper: true });
110+
}
92111
}
93112

94-
export function installMixins() {
113+
export function installMixins(overrideNImage = true) {
95114
if (!mixinInstalled) {
96115
mixinInstalled = true;
97-
overrideImgBase();
116+
overrideImgBase(overrideNImage);
98117
}
99118
}

src/image/index-common.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,18 @@ export const loadModeProperty = new Property<ImageBase, 'sync' | 'async'>({
219219
export const clipToBoundsProperty = new Property<ImageBase, boolean>({ name: 'clipToBounds', defaultValue: true, valueConverter: booleanConverter });
220220
export const animatedImageViewProperty = new Property<ImageBase, boolean>({ name: 'animatedImageView', defaultValue: false, valueConverter: booleanConverter });
221221

222-
export class ImageBase extends View {
222+
export const needRequestImage = function (target: any, propertyKey: string | Symbol, descriptor: PropertyDescriptor) {
223+
const originalMethod = descriptor.value;
224+
descriptor.value = function (...args: any[]) {
225+
if (!this.mCanRequestImage) {
226+
this.mNeedRequestImage = true;
227+
return;
228+
}
229+
return originalMethod.apply(this, args);
230+
};
231+
};
232+
233+
export abstract class ImageBase extends View {
223234
public static finalImageSetEvent: string = 'finalImageSet';
224235
public static failureEvent: string = 'failure';
225236
public static intermediateImageFailedEvent: string = 'intermediateImageFailed';
@@ -265,6 +276,21 @@ export class ImageBase extends View {
265276
return this.nativeViewProtected;
266277
}
267278

279+
mCanRequestImage = true;
280+
mNeedRequestImage = false;
281+
protected abstract initImage();
282+
public onResumeNativeUpdates(): void {
283+
// {N} suspends properties update on `_suspendNativeUpdates`. So we only need to do this in onResumeNativeUpdates
284+
this.mCanRequestImage = false;
285+
super.onResumeNativeUpdates();
286+
this.mCanRequestImage = true;
287+
288+
if (this.mNeedRequestImage) {
289+
this.mNeedRequestImage = false;
290+
this.initImage();
291+
}
292+
}
293+
268294
protected handleImageProgress(value: number, totalSize?: number) {}
269295
private static needsSizeAdjustment(scaleType: ScaleType) {
270296
if (scaleType === undefined) {

src/image/index.android.ts

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
failureImageUriProperty,
2020
imageRotationProperty,
2121
lowerResSrcProperty,
22+
needRequestImage,
2223
placeholderImageUriProperty,
2324
progressBarColorProperty,
2425
roundAsCircleProperty,
@@ -344,24 +345,11 @@ export class FailureEventData extends EventData {
344345
}
345346
}
346347

347-
export const needRequestImage = function (target: any, propertyKey: string | Symbol, descriptor: PropertyDescriptor) {
348-
const originalMethod = descriptor.value;
349-
descriptor.value = function (...args: any[]) {
350-
if (!this._canRequestImage) {
351-
this._needRequestImage = true;
352-
// we need to ensure a hierarchy is set or the default aspect ratio wont be set
353-
// because aspectFit is the default (wanted) but then we wont go into stretchProperty.setNative
354-
// this._needUpdateHierarchy = true;
355-
return;
356-
}
357-
return originalMethod.apply(this, args);
358-
};
359-
};
360348
export const needUpdateHierarchy = function (target: any, propertyKey: string | Symbol, descriptor: PropertyDescriptor) {
361349
const originalMethod = descriptor.value;
362350
descriptor.value = function (...args: any[]) {
363-
if (!this._canUpdateHierarchy) {
364-
this._needUpdateHierarchy = true;
351+
if (!this.mCanUpdateHierarchy) {
352+
this.mNeedUpdateHierarchy = true;
365353
return;
366354
}
367355
return originalMethod.apply(this, args);
@@ -374,25 +362,17 @@ export class Img extends ImageBase {
374362
nativeImageViewProtected: com.nativescript.image.DraweeView;
375363
isLoading = false;
376364

377-
_canRequestImage = true;
378-
_canUpdateHierarchy = true;
379-
_needUpdateHierarchy = false;
380-
_needRequestImage = false;
365+
mCanUpdateHierarchy = true;
366+
mNeedUpdateHierarchy = false;
381367
public onResumeNativeUpdates(): void {
382368
// {N} suspends properties update on `_suspendNativeUpdates`. So we only need to do this in onResumeNativeUpdates
383-
this._canRequestImage = false;
384-
this._canUpdateHierarchy = false;
369+
this.mCanUpdateHierarchy = false;
385370
super.onResumeNativeUpdates();
386-
this._canUpdateHierarchy = true;
387-
this._canRequestImage = true;
388-
if (this._needUpdateHierarchy) {
389-
this._needUpdateHierarchy = false;
371+
this.mCanUpdateHierarchy = true;
372+
if (this.mNeedUpdateHierarchy) {
373+
this.mNeedUpdateHierarchy = false;
390374
this.updateHierarchy();
391375
}
392-
if (this._needRequestImage) {
393-
this._needRequestImage = false;
394-
this.initImage();
395-
}
396376
}
397377
public createNativeView() {
398378
if (!initialized) {
@@ -548,7 +528,6 @@ export class Img extends ImageBase {
548528
}
549529

550530
// [ImageBase.blendingModeProperty.setNative](value: string) {
551-
// console.log('blendingModeProperty', value);
552531
// switch (value) {
553532
// case 'multiply':
554533
// (this.nativeImageViewProtected as any).setXfermode(android.graphics.PorterDuff.Mode.MULTIPLY);
@@ -565,7 +544,7 @@ export class Img extends ImageBase {
565544

566545
controllerListener: com.facebook.drawee.controller.ControllerListener<com.facebook.imagepipeline.image.ImageInfo>;
567546

568-
private async initImage() {
547+
protected async initImage() {
569548
const view = this.nativeViewProtected;
570549
if (view) {
571550
// this.nativeImageViewProtected.setImageURI(null);
@@ -770,8 +749,8 @@ export class Img extends ImageBase {
770749
}
771750

772751
private updateHierarchy() {
773-
if (!this._canUpdateHierarchy) {
774-
this._needUpdateHierarchy = true;
752+
if (!this.mCanUpdateHierarchy) {
753+
this.mNeedUpdateHierarchy = true;
775754
return;
776755
}
777756
if (this.nativeImageViewProtected) {
@@ -830,7 +809,7 @@ export class Img extends ImageBase {
830809
}
831810

832811
this.nativeImageViewProtected.setHierarchy(builder.build());
833-
if (!this._needRequestImage) {
812+
if (!this.mNeedRequestImage) {
834813
this.nativeImageViewProtected.setController(this.nativeImageViewProtected.getController());
835814
}
836815
}

0 commit comments

Comments
 (0)