HarmonyOS NEXT Practical: Save Network Images
Objective: Display network images, download them by clicking the save button, and save them locally. Prerequisite: ohos.permission.INTERNET Permission application required Implementation idea: Display images through Image. Obtain operational permissions through SaveButton. Download images through request.downloadFile. Copy images locally through fileIo. Specific implementation import { http } from '@kit.NetworkKit'; import { image } from '@kit.ImageKit'; import { BusinessError, request } from '@kit.BasicServicesKit'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; import { promptAction } from '@kit.ArkUI'; import { fileIo, fileIo as fs, fileUri } from '@kit.CoreFileKit'; import { common } from '@kit.AbilityKit'; @Entry @Component struct SaveImageDemoPage { imgUrl:string = 'https://pic1.zhimg.com/70/v2-88fd131a2081f6880036682526e40f4b_1440w.avis?source=172ae18b&biz_tag=Post' @State pixelMap: PixelMap | undefined = undefined; loadImageWithUrl(url: string) { let responseCode = http.ResponseCode; let OutData: http.HttpResponse; let imagePackerApi = image.createImagePacker(); let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 }; // 确保网络正常 http.createHttp().request(url, { method: http.RequestMethod.GET, connectTimeout: 60000, readTimeout: 60000 }, async (error: BusinessError, data: http.HttpResponse) => { if (error) { console.error(`http request failed with. Code: ${error.code}, message: ${error.message}`); } else { OutData = data; let code: http.ResponseCode | number = OutData.responseCode; if (responseCode.OK === code) { let imageData: ArrayBuffer = OutData.result as ArrayBuffer; let imageSource: image.ImageSource = image.createImageSource(imageData); class tmp { height: number = 100 width: number = 100 }; let options: Record = { 'alphaType': 0, // 透明度 'editable': false, // 是否可编辑 'pixelFormat': 3, // 像素格式 'scaleMode': 1, // 缩略值 'size': { height: 100, width: 100 } }; // 创建图片大小 imageSource.createPixelMap(options).then((pixelMap: PixelMap) => { this.pixelMap = pixelMap; this.pixelMap.getImageInfo().then((info: image.ImageInfo) => { console.info('info.width = ' + info.size.width); }).catch((err: BusinessError) => { console.error('Failed ' + err); }) imagePackerApi.packing(pixelMap, packOpts).then(async (buffer: ArrayBuffer) => { try { const context = getContext(this); let helper = photoAccessHelper.getPhotoAccessHelper(context); let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png'); let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // 写入文件 await fs.write(file.fd, buffer); promptAction.showToast({ message: '已保存至相册!' }); // 关闭文件 await fs.close(file.fd); } catch (error) { console.error('error is ' + JSON.stringify(error)); } }).catch((error: BusinessError) => { console.error('Failed to pack the image. And the error is: ' + error); }) pixelMap.release(); }) } } } ) } build() { Row() { Column({ space: 10 }) { Image(this.imgUrl) .width('80%') SaveButton().onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => { if (result === SaveButtonOnClickResult.SUCCESS) { this.loadImageWithUrl(this.imgUrl); } else { promptAction.showToast({ message: '设置权限失败!' }); } }) } .width('100%') } .height('100%') .backgroundColor(0xF1F3F5) } /** * 保存图片 * @param url */ async saveImage(imageUrl: string) { try { let fileNameExtension = this.getFileNameExtension(imageUrl) fileNameExtension = (fileNameExtension == '' || fileNameExtension == 'jfif') ? 'jpg' : fileNameExtension let context = getContext(this) as common.UIAbilityContext; let dirPath = context.filesDir + '/article_images_preview' let fileName = new Date().getTime().toString() if (!fileIo.accessSync(dirPath)) { fileIo.mkdirSync(dirPath) } //下载网络图片,并保存到沙箱 request.downloadFile(context, { url: imageUrl, filePath: `${dirPath}/${fileName}.${fileNameExtension}` }) .then((downloadTask) => { downloadTask.on('complete', async () => { try { // 位于应用沙箱的图片uri let srcFileUri = `${dirPath}/${fileName}.${fileNameExtension}`

Objective: Display network images, download them by clicking the save button, and save them locally.
Prerequisite: ohos.permission.INTERNET Permission application required
Implementation idea:
- Display images through Image.
- Obtain operational permissions through SaveButton.
- Download images through request.downloadFile.
- Copy images locally through fileIo.
Specific implementation
import { http } from '@kit.NetworkKit';
import { image } from '@kit.ImageKit';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { promptAction } from '@kit.ArkUI';
import { fileIo, fileIo as fs, fileUri } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct SaveImageDemoPage {
imgUrl:string = 'https://pic1.zhimg.com/70/v2-88fd131a2081f6880036682526e40f4b_1440w.avis?source=172ae18b&biz_tag=Post'
@State pixelMap: PixelMap | undefined = undefined;
loadImageWithUrl(url: string) {
let responseCode = http.ResponseCode;
let OutData: http.HttpResponse;
let imagePackerApi = image.createImagePacker();
let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 };
// 确保网络正常
http.createHttp().request(url, {
method: http.RequestMethod.GET,
connectTimeout: 60000,
readTimeout: 60000
},
async (error: BusinessError, data: http.HttpResponse) => {
if (error) {
console.error(`http request failed with. Code: ${error.code}, message: ${error.message}`);
} else {
OutData = data;
let code: http.ResponseCode | number = OutData.responseCode;
if (responseCode.OK === code) {
let imageData: ArrayBuffer = OutData.result as ArrayBuffer;
let imageSource: image.ImageSource = image.createImageSource(imageData);
class tmp {
height: number = 100
width: number = 100
};
let options: Record = {
'alphaType': 0, // 透明度
'editable': false, // 是否可编辑
'pixelFormat': 3, // 像素格式
'scaleMode': 1, // 缩略值
'size': { height: 100, width: 100 }
}; // 创建图片大小
imageSource.createPixelMap(options).then((pixelMap: PixelMap) => {
this.pixelMap = pixelMap;
this.pixelMap.getImageInfo().then((info: image.ImageInfo) => {
console.info('info.width = ' + info.size.width);
}).catch((err: BusinessError) => {
console.error('Failed ' + err);
})
imagePackerApi.packing(pixelMap, packOpts).then(async (buffer: ArrayBuffer) => {
try {
const context = getContext(this);
let helper = photoAccessHelper.getPhotoAccessHelper(context);
let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png');
let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
// 写入文件
await fs.write(file.fd, buffer);
promptAction.showToast({ message: '已保存至相册!' });
// 关闭文件
await fs.close(file.fd);
} catch (error) {
console.error('error is ' + JSON.stringify(error));
}
}).catch((error: BusinessError) => {
console.error('Failed to pack the image. And the error is: ' + error);
})
pixelMap.release();
})
}
}
}
)
}
build() {
Row() {
Column({ space: 10 }) {
Image(this.imgUrl)
.width('80%')
SaveButton().onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
if (result === SaveButtonOnClickResult.SUCCESS) {
this.loadImageWithUrl(this.imgUrl);
} else {
promptAction.showToast({ message: '设置权限失败!' });
}
})
}
.width('100%')
}
.height('100%')
.backgroundColor(0xF1F3F5)
}
/**
* 保存图片
* @param url
*/
async saveImage(imageUrl: string) {
try {
let fileNameExtension = this.getFileNameExtension(imageUrl)
fileNameExtension = (fileNameExtension == '' || fileNameExtension == 'jfif') ? 'jpg' : fileNameExtension
let context = getContext(this) as common.UIAbilityContext;
let dirPath = context.filesDir + '/article_images_preview'
let fileName = new Date().getTime().toString()
if (!fileIo.accessSync(dirPath)) {
fileIo.mkdirSync(dirPath)
}
//下载网络图片,并保存到沙箱
request.downloadFile(context, { url: imageUrl, filePath: `${dirPath}/${fileName}.${fileNameExtension}` })
.then((downloadTask) => {
downloadTask.on('complete', async () => {
try {
// 位于应用沙箱的图片uri
let srcFileUri = `${dirPath}/${fileName}.${fileNameExtension}`
let srcFileUris: Array = [fileUri.getUriFromPath(srcFileUri)];
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
// 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选
let photoCreationConfigs: Array = [
{
title: fileName, // 可选
fileNameExtension: fileNameExtension,
photoType: photoAccessHelper.PhotoType.IMAGE,
subtype: photoAccessHelper.PhotoSubtype.DEFAULT, // 可选
}
];
// 基于弹窗授权的方式获取媒体库的目标uri
let desFileUris: Array =
await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);
if (desFileUris.length > 0) {
let desFile: fileIo.File = await fileIo.open(desFileUris[0], fileIo.OpenMode.WRITE_ONLY);
let srcFile: fileIo.File = await fileIo.open(srcFileUri, fileIo.OpenMode.READ_ONLY);
await fileIo.copyFile(srcFile.fd, desFile.fd);
fileIo.closeSync(srcFile);
fileIo.closeSync(desFile);
promptAction.showToast({ message: '已保存!' });
} else {
promptAction.showToast({ message: '保存失败!' });
}
fs.rmdir(dirPath);
} catch (error) {
promptAction.showToast({ message: '保存失败!' });
}
})
downloadTask.on('fail', (err: number) => {
//下载失败
promptAction.showToast({ message: '保存失败!' });
})
})
.catch((err: BusinessError) => {
promptAction.showToast({ message: '保存失败!' });
})
} catch (err) {
promptAction.showToast({ message: '保存失败!' });
}
}
/**
* 获取文件拓展名
* @param url
* @returns 文件扩展名,没有则返回空字符串
*/
getFileNameExtension(url: string): string {
// 查找最后一个点(.)的位置
const lastIndex = url.lastIndexOf('.');
let fileNameExtension = ''
if (lastIndex === -1 || lastIndex === url.length - 1) {
fileNameExtension = ''
} else {
// 提取从最后一个点到字符串末尾的子字符串
let subStr = url.substring(lastIndex);
// 使用正则表达式匹配文件后缀名
const extensionMatch = subStr.match(/\.([a-zA-Z0-9]+)(?:[\?#]|$)/);
// 如果匹配到后缀名,则返回(去掉点号)
fileNameExtension = extensionMatch ? extensionMatch[1].toLowerCase() : '';
}
return fileNameExtension
}
}