import {
componentSnapshot,
promptAction,
SegmentButton,
SegmentButtonItemTuple,
SegmentButtonOptions
} from '@kit.ArkUI';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { common } from '@kit.AbilityKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { image } from '@kit.ImageKit';
import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { detectBarcode, scanBarcode } from '@kit.ScanKit';
@Entry
@Component
struct QrCodeGeneratorAndScanner {
@State private buttonOptions: SegmentButtonOptions = SegmentButtonOptions.capsule({
buttons: [{ text: '生成二维码' }, { text: '识别二维码' }] as SegmentButtonItemTuple,
multiply: false,
fontColor: Color.White,
selectedFontColor: Color.White,
selectedBackgroundColor: Color.Orange,
backgroundColor: "#d5d5d5",
backgroundBlurStyle: BlurStyle.BACKGROUND_THICK
})
@State private sampleText: string = 'hello world';
@State private inputText: string = "";
@State private scanResult: string = "";
@State @Watch('selectIndexChanged') selectIndex: number = 0
@State @Watch('selectedIndexesChanged') selectedIndexes: number[] = [0];
private qrCodeId: string = "qrCodeId"
@State private scanResultObject: scanBarcode.ScanResult = ({} as scanBarcode.ScanResult)
@State private textColor: string = "#2e2e2e";
@State private shadowColor: string = "#d5d5d5";
@State private basePadding: number = 30;
selectedIndexesChanged() {
console.info(`this.selectedIndexes[0]:${this.selectedIndexes[0]}`)
this.selectIndex = this.selectedIndexes[0]
}
selectIndexChanged() {
console.info(`selectIndex:${this.selectIndex}`)
this.selectedIndexes[0] = this.selectIndex
}
private copyToClipboard(text: string): void {
const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
const systemPasteboard = pasteboard.getSystemPasteboard();
systemPasteboard.setData(pasteboardData);
promptAction.showToast({ message: '已复制' });
}
build() {
Column() {
SegmentButton({
options: this.buttonOptions,
selectedIndexes: this.selectedIndexes
}).width('400lpx').margin({ top: 20 })
Tabs({ index: this.selectIndex }) {
TabContent() {
Scroll() {
Column() {
Column() {
Row() {
Text('示例')
.fontColor("#5871ce")
.fontSize(16)
.padding(`${this.basePadding / 2}lpx`)
.backgroundColor("#f2f1fd")
.borderRadius(5)
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 })
.onClick(() => {
this.inputText = this.sampleText;
});
Blank();
Text('清空')
.fontColor("#e48742")
.fontSize(16)
.padding(`${this.basePadding / 2}lpx`)
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 })
.backgroundColor("#ffefe6")
.borderRadius(5)
.onClick(() => {
this.inputText = "";
});
}
.height(45)
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
Divider();
TextArea({ text: $$this.inputText, placeholder: `请输入内容` })
.width(`${650 - this.basePadding * 2}lpx`)
.height(100)
.fontSize(16)
.caretColor(this.textColor)
.fontColor(this.textColor)
.margin({ top: `${this.basePadding}lpx` })
.padding(0)
.backgroundColor(Color.Transparent)
.borderRadius(0)
.textAlign(TextAlign.JUSTIFY);
}
.alignItems(HorizontalAlign.Start)
.width('650lpx')
.padding(`${this.basePadding}lpx`)
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({
radius: 10,
color: this.shadowColor,
offsetX: 0,
offsetY: 0
});
Row() {
QRCode(this.inputText)
.width('300lpx')
.aspectRatio(1)
.id(this.qrCodeId)
SaveButton()
.onClick(async (_event: ClickEvent, result: SaveButtonOnClickResult) => {
if (result === SaveButtonOnClickResult.SUCCESS) {
const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
let helper = photoAccessHelper.getPhotoAccessHelper(context);
try {
let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
let file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
componentSnapshot.get(this.qrCodeId).then((pixelMap) => {
let packOpts: image.PackingOption = { format: 'image/png', quality: 100 }
const imagePacker: image.ImagePacker = image.createImagePacker();
return imagePacker.packToFile(pixelMap, file.fd, packOpts).finally(() => {
imagePacker.release();
fs.close(file.fd);
promptAction.showToast({
message: '图片已保存至相册',
duration: 2000
});
});
})
} catch (error) {
const err: BusinessError = error as BusinessError;
console.error(`Failed to save photo. Code is ${err.code}, message is ${err.message}`);
}
} else {
promptAction.showToast({
message: '设置权限失败!',
duration: 2000
});
}
})
}
.visibility(this.inputText ? Visibility.Visible : Visibility.Hidden)
.justifyContent(FlexAlign.SpaceBetween)
.width('650lpx')
.padding(`${this.basePadding}lpx`)
.margin({ top: `${this.basePadding}lpx` })
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({
radius: 10,
color: this.shadowColor,
offsetX: 0,
offsetY: 0
});
}.padding({ top: 20, bottom: 20 })
.width('100%')
}.scrollBar(BarState.Off)
.align(Alignment.Top)
.height('100%')
}
TabContent() {
Scroll() {
Column() {
Row() {
Text('扫一扫')
.fontSize(20)
.textAlign(TextAlign.Center)
.fontColor("#5871ce")
.backgroundColor("#f2f1fd")
.clickEffect({ scale: 0.8, level: ClickEffectLevel.LIGHT })
.borderRadius(10)
.height('250lpx')
.layoutWeight(1)
.onClick(() => {
if (canIUse('SystemCapability.Multimedia.Scan.ScanBarcode')) {
try {
scanBarcode.startScanForResult(getContext(this), {
enableMultiMode: true,
enableAlbum: true
},
(error: BusinessError, result: scanBarcode.ScanResult) => {
if (error) {
hilog.error(0x0001, '[Scan CPSample]',
`Failed to get ScanResult by callback with options. Code: ${error.code}, message: ${error.message}`);
return;
}
hilog.info(0x0001, '[Scan CPSample]',
`Succeeded in getting ScanResult by callback with options, result is ${JSON.stringify(result)}`);
this.scanResultObject = result;
this.scanResult = result.originalValue ? result.originalValue : '无法识别';
});
} catch (error) {
hilog.error(0x0001, '[Scan CPSample]',
`Failed to start the scanning service. Code:${error.code}, message: ${error.message}`);
}
} else {
promptAction.showToast({ message: '当前设备不支持二维码扫描' });
}
});
Line().width(`${this.basePadding}lpx`).aspectRatio(1);
Text('图库选')
.fontSize(20)
.textAlign(TextAlign.Center)
.fontColor("#e48742")
.backgroundColor("#ffefe6")
.borderRadius(10)
.clickEffect({ scale: 0.8, level: ClickEffectLevel.LIGHT })
.height('250lpx')
.layoutWeight(1)
.onClick(() => {
if (canIUse('SystemCapability.Multimedia.Scan.ScanBarcode')) {
let photoOption = new photoAccessHelper.PhotoSelectOptions();
photoOption.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
photoOption.maxSelectNumber = 1;
let photoPicker = new photoAccessHelper.PhotoViewPicker();
photoPicker.select(photoOption).then((result) => {
let inputImage: detectBarcode.InputImage = { uri: result.photoUris[0] };
try {
detectBarcode.decode(inputImage,
(error: BusinessError, result: Array<scanBarcode.ScanResult>) => {
if (error && error.code) {
hilog.error(0x0001, '[Scan Sample]',
`Failed to get ScanResult by callback. Code: ${error.code}, message: ${error.message}`);
return;
}
hilog.info(0x0001, '[Scan Sample]',
`Succeeded in getting ScanResult by callback, result is ${JSON.stringify(result, null, '\u00A0\u00A0')}`);
if (result.length > 0) {
this.scanResultObject = result[0];
this.scanResult = result[0].originalValue ? result[0].originalValue : '无法识别';
} else {
this.scanResult = '不存在二维码';
}
});
} catch (error) {
hilog.error(0x0001, '[Scan Sample]',
`Failed to detect Barcode. Code: ${error.code}, message: ${error.message}`);
}
});
} else {
promptAction.showToast({ message: '当前设备不支持二维码扫描' });
}
});
}
.justifyContent(FlexAlign.SpaceEvenly)
.width('650lpx')
.padding(`${this.basePadding}lpx`)
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({
radius: 10,
color: this.shadowColor,
offsetX: 0,
offsetY: 0
});
Column() {
Row() {
Text(`解析结果:\n${this.scanResult}`)
.fontColor(this.textColor)
.fontSize(18)
.layoutWeight(1)
Text('复制')
.fontColor(Color.White)
.fontSize(16)
.padding(`${this.basePadding / 2}lpx`)
.backgroundColor("#0052d9")
.borderRadius(5)
.clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.8 })
.onClick(() => {
this.copyToClipboard(this.scanResult);
});
}.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
}
.visibility(this.scanResult ? Visibility.Visible : Visibility.Hidden)
.alignItems(HorizontalAlign.Start)
.width('650lpx')
.padding(`${this.basePadding}lpx`)
.margin({ top: `${this.basePadding}lpx` })
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({
radius: 10,
color: this.shadowColor,
offsetX: 0,
offsetY: 0
});
Column() {
Row() {
Text(`完整结果:`).fontColor(this.textColor).fontSize(18).layoutWeight(1)
}.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
Divider().margin({ top: 2, bottom: 15 });
Row() {
Text(`${JSON.stringify(this.scanResultObject, null, '\u00A0\u00A0')}`)
.fontColor(this.textColor)
.fontSize(18)
.layoutWeight(1)
.copyOption(CopyOptions.LocalDevice);
}.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
}
.visibility(this.scanResult ? Visibility.Visible : Visibility.Hidden)
.alignItems(HorizontalAlign.Start)
.width('650lpx')
.padding(`${this.basePadding}lpx`)
.margin({ top: `${this.basePadding}lpx` })
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({
radius: 10,
color: this.shadowColor,
offsetX: 0,
offsetY: 0
});
}
.padding({ top: 20, bottom: 20 })
.width('100%')
}.scrollBar(BarState.Off)
.align(Alignment.Top)
.height('100%')
}
}
.barHeight(0)
.tabIndex(this.selectIndex)
.width('100%')
.layoutWeight(1)
.onChange((index: number) => {
this.selectIndex = index;
});
}
.height('100%')
.width('100%')
.backgroundColor("#f4f8fb");
}
}