UNPKG

@nativescript-community/ui-image

Version:

Advanced and efficient image display plugin which uses Fresco (Android) and SDWebImage (iOS) to implement caching, placeholders, image effects, and much more.

422 lines 16.7 kB
export * from './image-common'; import { ImageAsset, ImageSource, Screen, Trace, knownFolders, path } from '@nativescript/core'; import { isString } from '@nativescript/core/utils/types'; import { RESOURCE_PREFIX, isFileOrResourcePath, isFontIconURI, layout } from '@nativescript/core/utils/utils'; import { CLog, CLogTypes, ImageBase, ScaleType } from './image-common'; var SDImageRoundAsCircleTransformer = /** @class */ (function (_super) { __extends(SDImageRoundAsCircleTransformer, _super); function SDImageRoundAsCircleTransformer() { return _super !== null && _super.apply(this, arguments) || this; } SDImageRoundAsCircleTransformer.transformer = function () { var transformer = SDImageRoundAsCircleTransformer.alloc().init(); return transformer; }; Object.defineProperty(SDImageRoundAsCircleTransformer.prototype, "transformerKey", { get: function () { return 'SDImageRoundAsCircleTransformer'; }, enumerable: true, configurable: true }); SDImageRoundAsCircleTransformer.prototype.transformedImageWithImageForKey = function (image, key) { if (!image) { return null; } var width = image.size.width; var height = image.size.height; var minwidth = Math.min(width, height); var cornerRadius = minwidth / 2; var result = image .sd_resizedImageWithSizeScaleMode(CGSizeMake(minwidth, minwidth), SDImageScaleMode.AspectFill) .sd_roundedCornerImageWithRadiusCornersBorderWidthBorderColor(cornerRadius, UIRectCorner.BottomLeft | UIRectCorner.BottomRight | UIRectCorner.TopLeft | UIRectCorner.TopRight, 0, null) .sd_resizedImageWithSizeScaleMode(CGSizeMake(width, height), SDImageScaleMode.AspectFit); return result; }; SDImageRoundAsCircleTransformer.ObjCProtocols = [SDImageTransformer]; return SDImageRoundAsCircleTransformer; }(NSObject)); export class ImageInfo { constructor(width, height) { this.width = width; this.height = height; } getHeight() { return this.height; } getWidth() { return this.width; } } const supportedLocalFormats = ['png', 'jpg', 'gif', 'jpeg', 'webp']; let screenScale = -1; function getScaleType(scaleType) { if (isString(scaleType)) { switch (scaleType) { case ScaleType.Center: case ScaleType.CenterCrop: case ScaleType.AspectFill: return 2; case ScaleType.CenterInside: case ScaleType.FitCenter: case ScaleType.FitEnd: case ScaleType.FitStart: case ScaleType.AspectFit: return 1; case ScaleType.FitXY: case ScaleType.FocusCrop: case ScaleType.Fill: return 0; default: break; } } return null; } function getUIImageScaleType(scaleType) { if (isString(scaleType)) { switch (scaleType) { case ScaleType.Center: return 4; case ScaleType.FocusCrop: case ScaleType.CenterCrop: case ScaleType.AspectFill: return 2; case ScaleType.AspectFit: case ScaleType.CenterInside: case ScaleType.FitCenter: return 1; case ScaleType.FitEnd: return 8; case ScaleType.FitStart: return 7; case ScaleType.Fill: case ScaleType.FitXY: return 0; case ScaleType.None: return 9; default: break; } } return null; } export function initialize(config) { SDImageLoadersManager.sharedManager.loaders = NSArray.arrayWithArray([SDWebImageDownloader.sharedDownloader, SDImagePhotosLoader.sharedLoader]); } export function shutDown() { } export class ImagePipeline { constructor() { this._ios = SDImageCache.sharedImageCache; } isInDiskCache(uri) { return this._ios.diskImageDataExistsWithKey(getUri(uri).absoluteString); } isInBitmapMemoryCache(uri) { return this._ios.imageFromMemoryCacheForKey(getUri(uri).absoluteString) !== null; } evictFromMemoryCache(uri) { this._ios.removeImageFromMemoryForKey(getUri(uri).absoluteString); } evictFromDiskCache(uri) { this._ios.removeImageFromDiskForKey(getUri(uri).absoluteString); } evictFromCache(uri) { this._ios.removeImageForKeyWithCompletion(getUri(uri).absoluteString, null); } clearCaches() { this._ios.clearMemory(); this._ios.clearDiskOnCompletion(null); } clearMemoryCaches() { this._ios.clearMemory(); } clearDiskCaches() { this._ios.clearDiskOnCompletion(null); } prefetchToDiskCache(uri) { return this.prefetchToCacheType(uri, 1); } prefetchToMemoryCache(uri) { return this.prefetchToCacheType(uri, 2); } prefetchToCacheType(uri, cacheType) { return new Promise((resolve, reject) => { const context = NSMutableDictionary.alloc().initWithCapacity(1); context.setObjectForKey(cacheType, SDWebImageContextStoreCacheType); SDWebImagePrefetcher.sharedImagePrefetcher.context = context; SDWebImagePrefetcher.sharedImagePrefetcher.prefetchURLsProgressCompleted([getUri(uri)], null, (finished, skipped) => { if (finished && !skipped) { resolve(); } else { reject(`prefetch failed for URI: ${uri}`); } }); }); } get ios() { return this._ios; } } export function getImagePipeline() { const imagePineLine = new ImagePipeline(); return imagePineLine; } function getUri(src) { let uri = src; if (src instanceof ImageAsset) { return NSURL.sd_URLWithAsset(src.ios); } if (uri.indexOf(RESOURCE_PREFIX) === 0) { const resName = uri.substr(RESOURCE_PREFIX.length); if (screenScale === -1) { screenScale = Screen.mainScreen.scale; } const found = supportedLocalFormats.some((v) => { for (let i = screenScale; i >= 1; i--) { uri = NSBundle.mainBundle.URLForResourceWithExtension(i > 1 ? `${resName}@${i}x` : resName, v); if (uri) { return true; } } return false; }); if (found) { return uri; } } else if (uri.indexOf('~/') === 0) { return NSURL.fileURLWithPath(`${path.join(knownFolders.currentApp().path, uri.replace('~/', ''))}`); } else if (uri.indexOf('/') === 0) { return NSURL.fileURLWithPath(uri); } return NSURL.URLWithString(uri); } export class Img extends ImageBase { constructor() { super(...arguments); this.isLoading = false; this._imageSourceAffectsLayout = true; this.handleImageLoaded = (image, error, cacheType) => { this.isLoading = false; const animate = (this.alwaysFade || cacheType !== 2) && this.fadeDuration > 0; if (image) { this._setNativeImage(image, animate); } if (!this.autoPlayAnimations) { this.nativeViewProtected.stopAnimating(); } if (error) { const args = { eventName: Img.failureEvent, object: this, error, }; this.notify(args); if (this.failureImageUri) { image = this.getUIImage(this.failureImageUri); this._setNativeImage(image, animate); } } else if (image) { const args = { eventName: ImageBase.finalImageSetEvent, object: this, imageInfo: new ImageInfo(image.size.width, image.size.height), ios: image, }; this.notify(args); } this.handleImageProgress(1); }; this.onLoadProgress = (currentSize, totalSize) => { this.handleImageProgress(totalSize > 0 ? currentSize / totalSize : -1, totalSize); }; } createNativeView() { const result = SDAnimatedImageView.new(); result.contentMode = 1; result.clipsToBounds = true; result.userInteractionEnabled = true; result.tintColor = null; return result; } _setNativeClipToBounds() { this.nativeViewProtected.clipsToBounds = true; } onMeasure(widthMeasureSpec, heightMeasureSpec) { const width = layout.getMeasureSpecSize(widthMeasureSpec); const widthMode = layout.getMeasureSpecMode(widthMeasureSpec); const height = layout.getMeasureSpecSize(heightMeasureSpec); const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); const image = this.nativeViewProtected.image; const finiteWidth = widthMode === layout.EXACTLY; const finiteHeight = heightMode === layout.EXACTLY; this._imageSourceAffectsLayout = !finiteWidth || !finiteHeight; if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onMeasure', this.src, widthMeasureSpec, heightMeasureSpec, width, height, this.aspectRatio, image && image.imageOrientation); } if (image || this.aspectRatio > 0) { const nativeWidth = image ? layout.toDevicePixels(image.size.width) : 0; const nativeHeight = image ? layout.toDevicePixels(image.size.height) : 0; const imgRatio = nativeWidth / nativeHeight; const ratio = this.aspectRatio || imgRatio; if (!finiteWidth) { widthMeasureSpec = layout.makeMeasureSpec(height * ratio, layout.EXACTLY); } if (!finiteHeight) { heightMeasureSpec = layout.makeMeasureSpec(width / ratio, layout.EXACTLY); } if (Trace.isEnabled()) { CLog(CLogTypes.info, 'onMeasure scale', this.src, this.aspectRatio, finiteWidth, finiteHeight, width, height, nativeWidth, nativeHeight, widthMeasureSpec, heightMeasureSpec); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } updateImageUri() { const imagePipeLine = getImagePipeline(); const src = this.src; if (!(src instanceof ImageSource)) { const uri = getUri(src).absoluteString; const isInCache = imagePipeLine.isInBitmapMemoryCache(uri); if (isInCache) { imagePipeLine.evictFromCache(uri); } } this.src = null; this.src = src; } _setNativeImage(nativeImage, animated = true) { if (animated) { this.nativeViewProtected.alpha = 0.0; this.nativeViewProtected.image = nativeImage; UIView.animateWithDurationAnimations(this.fadeDuration / 1000, () => { this.nativeViewProtected.alpha = this.opacity; }); } else { this.nativeViewProtected.image = nativeImage; } if (this._imageSourceAffectsLayout) { this._imageSourceAffectsLayout = false; this.requestLayout(); } } getUIImage(imagePath) { if (!path) { return null; } let image; if (typeof imagePath === 'string') { if (isFontIconURI(imagePath)) { const fontIconCode = (imagePath).split('//')[1]; if (fontIconCode !== undefined) { const font = this.style.fontInternal; const color = this.style.color; image = (ImageSource.fromFontIconCodeSync(fontIconCode, font, color).ios); } } if (!image && isFileOrResourcePath(imagePath)) { image = ImageSource.fromFileOrResourceSync(imagePath); } } else { image = imagePath; } if (image) { image = image.ios; } return image; } initImage() { if (this.nativeViewProtected) { const src = this.src; if (src) { const animate = this.fadeDuration > 0; if (src instanceof ImageSource) { this._setNativeImage(src.ios, animate); return; } else if (typeof src === 'string') { if (isFontIconURI(src)) { const fontIconCode = (src).split('//')[1]; if (fontIconCode !== undefined) { const font = this.style.fontInternal; const color = this.style.color; this._setNativeImage(ImageSource.fromFontIconCodeSync(fontIconCode, font, color).ios, animate); } return; } } const uri = getUri(src); if (this.noCache) { const key = uri.absoluteString; const imagePipeLine = getImagePipeline(); const isInCache = imagePipeLine.isInBitmapMemoryCache(key); if (isInCache) { imagePipeLine.evictFromCache(key); } } this.isLoading = true; let options = 2048 | 1024; if (this.alwaysFade === true) { options |= 131072; } const context = NSMutableDictionary.dictionary(); const transformers = []; if (this.progressiveRenderingEnabled === true) { options = options | 4; } if (this.decodeWidth && this.decodeHeight) { transformers.push(NSImageDecodeSizeTransformer.transformerWithDecodeWidthDecodeHeight(this.decodeWidth, this.decodeHeight)); } if (this.tintColor) { transformers.push(SDImageTintTransformer.transformerWithColor(this.tintColor.ios)); } if (this.blurRadius) { transformers.push(SDImageBlurTransformer.transformerWithRadius(this.blurRadius)); } if (this.roundAsCircle === true) { transformers.push(SDImageRoundAsCircleTransformer.new()); } if (this.roundBottomLeftRadius || this.roundBottomRightRadius || this.roundTopLeftRadius || this.roundTopRightRadius) { transformers.push(NSImageRoundCornerTransformer.transformerWithTopLefRadiusTopRightRadiusBottomRightRadiusBottomLeftRadius(layout.toDeviceIndependentPixels(this.roundTopLeftRadius), layout.toDeviceIndependentPixels(this.roundTopRightRadius), layout.toDeviceIndependentPixels(this.roundBottomRightRadius), layout.toDeviceIndependentPixels(this.roundBottomLeftRadius))); } if (transformers.length > 0) { context.setValueForKey(SDImagePipelineTransformer.transformerWithTransformers(transformers), SDWebImageContextImageTransformer); } this.nativeViewProtected.sd_setImageWithURLPlaceholderImageOptionsContextProgressCompleted(uri, this.placeholderImage, options, context, this.onLoadProgress, this.handleImageLoaded); } else if (this.placeholderImage) { this._setNativeImage(this.placeholderImage); } else { this._setNativeImage(null); } } } [ImageBase.srcProperty.setNative](value) { this.initImage(); } [ImageBase.placeholderImageUriProperty.setNative]() { this.placeholderImage = this.getUIImage(this.placeholderImageUri); this.initImage(); } [ImageBase.failureImageUriProperty.setNative]() { } [ImageBase.stretchProperty.setNative](value) { if (!this.nativeView) { return; } this.nativeViewProtected.contentMode = getUIImageScaleType(value); } startAnimating() { this.nativeViewProtected.startAnimating(); } stopAnimating() { this.nativeViewProtected.stopAnimating(); } } //# sourceMappingURL=image.ios.js.map