1a3e0fd82Sopenharmony_ci/* 2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License. 5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at 6a3e0fd82Sopenharmony_ci * 7a3e0fd82Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8a3e0fd82Sopenharmony_ci * 9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and 13a3e0fd82Sopenharmony_ci * limitations under the License. 14a3e0fd82Sopenharmony_ci */ 15a3e0fd82Sopenharmony_ci 16a3e0fd82Sopenharmony_ci#include "components/ui_qrcode.h" 17a3e0fd82Sopenharmony_ci#include "qrcodegen.hpp" 18a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h" 19a3e0fd82Sopenharmony_ci#include "securec.h" 20a3e0fd82Sopenharmony_ci 21a3e0fd82Sopenharmony_ciusing qrcodegen::QrCode; 22a3e0fd82Sopenharmony_cinamespace OHOS { 23a3e0fd82Sopenharmony_ciUIQrcode::UIQrcode() 24a3e0fd82Sopenharmony_ci : width_(0), needDraw_(false), backgroundColor_(Color::White()), qrColor_(Color::Black()), qrcodeVal_(nullptr) 25a3e0fd82Sopenharmony_ci{ 26a3e0fd82Sopenharmony_ci style_ = &(StyleDefault::GetBackgroundTransparentStyle()); 27a3e0fd82Sopenharmony_ci imageInfo_ = {{0}}; 28a3e0fd82Sopenharmony_ci} 29a3e0fd82Sopenharmony_ci 30a3e0fd82Sopenharmony_ciUIQrcode::~UIQrcode() 31a3e0fd82Sopenharmony_ci{ 32a3e0fd82Sopenharmony_ci if (qrcodeVal_ != nullptr) { 33a3e0fd82Sopenharmony_ci UIFree(qrcodeVal_); 34a3e0fd82Sopenharmony_ci qrcodeVal_ = nullptr; 35a3e0fd82Sopenharmony_ci } 36a3e0fd82Sopenharmony_ci 37a3e0fd82Sopenharmony_ci if (imageInfo_.data != nullptr) { 38a3e0fd82Sopenharmony_ci ImageCacheFree(imageInfo_); 39a3e0fd82Sopenharmony_ci imageInfo_.data = nullptr; 40a3e0fd82Sopenharmony_ci } 41a3e0fd82Sopenharmony_ci} 42a3e0fd82Sopenharmony_ci 43a3e0fd82Sopenharmony_civoid UIQrcode::SetQrcodeInfo(const char* val, ColorType backgroundColor, ColorType qrColor) 44a3e0fd82Sopenharmony_ci{ 45a3e0fd82Sopenharmony_ci if (val == nullptr) { 46a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::SetQrcodeInfo val is null!\n"); 47a3e0fd82Sopenharmony_ci return; 48a3e0fd82Sopenharmony_ci } 49a3e0fd82Sopenharmony_ci uint32_t length = static_cast<uint32_t>(strlen(val)); 50a3e0fd82Sopenharmony_ci if ((length > QRCODE_VAL_MAX) || (length == 0)) { 51a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::SetQrcodeInfo val length is equal 0 or greater than QRCODE_VAL_MAX!\n"); 52a3e0fd82Sopenharmony_ci return; 53a3e0fd82Sopenharmony_ci } 54a3e0fd82Sopenharmony_ci backgroundColor_ = backgroundColor; 55a3e0fd82Sopenharmony_ci qrColor_ = qrColor; 56a3e0fd82Sopenharmony_ci SetQrcodeVal(val, length); 57a3e0fd82Sopenharmony_ci RefreshQrcode(); 58a3e0fd82Sopenharmony_ci} 59a3e0fd82Sopenharmony_ci 60a3e0fd82Sopenharmony_civoid UIQrcode::RefreshQrcode() 61a3e0fd82Sopenharmony_ci{ 62a3e0fd82Sopenharmony_ci Invalidate(); 63a3e0fd82Sopenharmony_ci if (!needDraw_) { 64a3e0fd82Sopenharmony_ci needDraw_ = true; 65a3e0fd82Sopenharmony_ci } 66a3e0fd82Sopenharmony_ci} 67a3e0fd82Sopenharmony_ci 68a3e0fd82Sopenharmony_civoid UIQrcode::SetWidth(int16_t width) 69a3e0fd82Sopenharmony_ci{ 70a3e0fd82Sopenharmony_ci if (GetWidth() != width) { 71a3e0fd82Sopenharmony_ci UIView::SetWidth(width); 72a3e0fd82Sopenharmony_ci RefreshQrcode(); 73a3e0fd82Sopenharmony_ci } 74a3e0fd82Sopenharmony_ci} 75a3e0fd82Sopenharmony_ci 76a3e0fd82Sopenharmony_civoid UIQrcode::SetHeight(int16_t height) 77a3e0fd82Sopenharmony_ci{ 78a3e0fd82Sopenharmony_ci if (GetHeight() != height) { 79a3e0fd82Sopenharmony_ci UIView::SetHeight(height); 80a3e0fd82Sopenharmony_ci RefreshQrcode(); 81a3e0fd82Sopenharmony_ci } 82a3e0fd82Sopenharmony_ci} 83a3e0fd82Sopenharmony_ci 84a3e0fd82Sopenharmony_civoid UIQrcode::ReMeasure() 85a3e0fd82Sopenharmony_ci{ 86a3e0fd82Sopenharmony_ci if (!needDraw_) { 87a3e0fd82Sopenharmony_ci return; 88a3e0fd82Sopenharmony_ci } 89a3e0fd82Sopenharmony_ci needDraw_ = false; 90a3e0fd82Sopenharmony_ci if (qrcodeVal_ == nullptr) { 91a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::ReMeasure qrcodeVal_ is null!\n"); 92a3e0fd82Sopenharmony_ci return; 93a3e0fd82Sopenharmony_ci } 94a3e0fd82Sopenharmony_ci QrCode qr = QrCode::encodeText(qrcodeVal_, QrCode::Ecc::LOW); 95a3e0fd82Sopenharmony_ci SetImageInfo(qr); 96a3e0fd82Sopenharmony_ci SetSrc(&imageInfo_); 97a3e0fd82Sopenharmony_ci} 98a3e0fd82Sopenharmony_ci 99a3e0fd82Sopenharmony_civoid UIQrcode::SetQrcodeVal(const char* qrcodeVal, uint32_t length) 100a3e0fd82Sopenharmony_ci{ 101a3e0fd82Sopenharmony_ci if (qrcodeVal_ != nullptr) { 102a3e0fd82Sopenharmony_ci UIFree(qrcodeVal_); 103a3e0fd82Sopenharmony_ci qrcodeVal_ = nullptr; 104a3e0fd82Sopenharmony_ci } 105a3e0fd82Sopenharmony_ci 106a3e0fd82Sopenharmony_ci uint32_t len = static_cast<uint32_t>(length + 1); 107a3e0fd82Sopenharmony_ci qrcodeVal_ = static_cast<char*>(UIMalloc(len)); 108a3e0fd82Sopenharmony_ci if (qrcodeVal_ != nullptr) { 109a3e0fd82Sopenharmony_ci if (memcpy_s(qrcodeVal_, len, qrcodeVal, len) != EOK) { 110a3e0fd82Sopenharmony_ci UIFree(reinterpret_cast<void*>(qrcodeVal_)); 111a3e0fd82Sopenharmony_ci qrcodeVal_ = nullptr; 112a3e0fd82Sopenharmony_ci } 113a3e0fd82Sopenharmony_ci } 114a3e0fd82Sopenharmony_ci} 115a3e0fd82Sopenharmony_ci 116a3e0fd82Sopenharmony_civoid UIQrcode::SetImageInfo(qrcodegen::QrCode& qrcode) 117a3e0fd82Sopenharmony_ci{ 118a3e0fd82Sopenharmony_ci int16_t width = GetWidth(); 119a3e0fd82Sopenharmony_ci int16_t height = GetHeight(); 120a3e0fd82Sopenharmony_ci width_ = (width >= height) ? height : width; 121a3e0fd82Sopenharmony_ci if (width_ < qrcode.getSize()) { 122a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::SetImageInfo width is less than the minimum qrcode width!\n"); 123a3e0fd82Sopenharmony_ci return; 124a3e0fd82Sopenharmony_ci } 125a3e0fd82Sopenharmony_ci imageInfo_.header.width = width; 126a3e0fd82Sopenharmony_ci imageInfo_.header.height = height; 127a3e0fd82Sopenharmony_ci imageInfo_.header.colorMode = ARGB8888; 128a3e0fd82Sopenharmony_ci width = UI_ALIGN_UP(width); 129a3e0fd82Sopenharmony_ci imageInfo_.dataSize = width * imageInfo_.header.height * QRCODE_FACTOR_NUM; 130a3e0fd82Sopenharmony_ci if (imageInfo_.data != nullptr) { 131a3e0fd82Sopenharmony_ci ImageCacheFree(imageInfo_); 132a3e0fd82Sopenharmony_ci imageInfo_.data = nullptr; 133a3e0fd82Sopenharmony_ci } 134a3e0fd82Sopenharmony_ci imageInfo_.data = reinterpret_cast<uint8_t*>(ImageCacheMalloc(imageInfo_)); 135a3e0fd82Sopenharmony_ci if (imageInfo_.data == nullptr) { 136a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::SetImageInfo imageInfo_.data is null!\n"); 137a3e0fd82Sopenharmony_ci return; 138a3e0fd82Sopenharmony_ci } 139a3e0fd82Sopenharmony_ci GenerateQrCode(qrcode); 140a3e0fd82Sopenharmony_ci} 141a3e0fd82Sopenharmony_ci 142a3e0fd82Sopenharmony_civoid UIQrcode::GenerateQrCode(qrcodegen::QrCode& qrcode) 143a3e0fd82Sopenharmony_ci{ 144a3e0fd82Sopenharmony_ci FillQrCodeBackgroundColor(); 145a3e0fd82Sopenharmony_ci 146a3e0fd82Sopenharmony_ci FillQrCodeColor(qrcode); 147a3e0fd82Sopenharmony_ci} 148a3e0fd82Sopenharmony_ci 149a3e0fd82Sopenharmony_civoid UIQrcode::FillQrCodeColor(qrcodegen::QrCode& qrcode) 150a3e0fd82Sopenharmony_ci{ 151a3e0fd82Sopenharmony_ci int32_t qrWidth = qrcode.getSize(); 152a3e0fd82Sopenharmony_ci if (qrWidth <= 0) { 153a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::FillQrCodeColor generated qrcode size is less or equal 0!\n"); 154a3e0fd82Sopenharmony_ci return; 155a3e0fd82Sopenharmony_ci } 156a3e0fd82Sopenharmony_ci int16_t width = imageInfo_.header.width; 157a3e0fd82Sopenharmony_ci int16_t height = imageInfo_.header.height; 158a3e0fd82Sopenharmony_ci uint16_t outFilePixelPrescaler = width_ / qrWidth; 159a3e0fd82Sopenharmony_ci int32_t offsetX = (width - outFilePixelPrescaler * qrWidth) / 2; // 2: half 160a3e0fd82Sopenharmony_ci int32_t offsetY = (height - outFilePixelPrescaler * qrWidth) / 2; // 2: half 161a3e0fd82Sopenharmony_ci 162a3e0fd82Sopenharmony_ci width = UI_ALIGN_UP(width); 163a3e0fd82Sopenharmony_ci uint8_t* destData = nullptr; 164a3e0fd82Sopenharmony_ci int64_t oneLinePixel = width * QRCODE_FACTOR_NUM * outFilePixelPrescaler; 165a3e0fd82Sopenharmony_ci int64_t oneLineOffsetPixel = (offsetY * width * QRCODE_FACTOR_NUM) + (offsetX * QRCODE_FACTOR_NUM); 166a3e0fd82Sopenharmony_ci for (int32_t y = 0; y < qrWidth; ++y) { 167a3e0fd82Sopenharmony_ci destData = const_cast<uint8_t*>(imageInfo_.data) + (oneLinePixel * y) + oneLineOffsetPixel; 168a3e0fd82Sopenharmony_ci for (int32_t x = 0; x < qrWidth; ++x) { 169a3e0fd82Sopenharmony_ci if (qrcode.getModule(x, y)) { 170a3e0fd82Sopenharmony_ci GetDestData(destData, outFilePixelPrescaler); 171a3e0fd82Sopenharmony_ci } 172a3e0fd82Sopenharmony_ci destData += QRCODE_FACTOR_NUM * outFilePixelPrescaler; 173a3e0fd82Sopenharmony_ci } 174a3e0fd82Sopenharmony_ci } 175a3e0fd82Sopenharmony_ci} 176a3e0fd82Sopenharmony_ci 177a3e0fd82Sopenharmony_civoid UIQrcode::FillQrCodeBackgroundColor() 178a3e0fd82Sopenharmony_ci{ 179a3e0fd82Sopenharmony_ci uint8_t* initColorData = const_cast<uint8_t*>(imageInfo_.data); 180a3e0fd82Sopenharmony_ci *(initColorData + 0) = backgroundColor_.blue; // 0: B channel 181a3e0fd82Sopenharmony_ci *(initColorData + 1) = backgroundColor_.green; // 1: G channel 182a3e0fd82Sopenharmony_ci *(initColorData + 2) = backgroundColor_.red; // 2: R channel 183a3e0fd82Sopenharmony_ci *(initColorData + 3) = OPA_OPAQUE; // 3: Alpha channel 184a3e0fd82Sopenharmony_ci 185a3e0fd82Sopenharmony_ci uint32_t width = imageInfo_.header.width; 186a3e0fd82Sopenharmony_ci width = UI_ALIGN_UP(width); 187a3e0fd82Sopenharmony_ci 188a3e0fd82Sopenharmony_ci uint8_t* tempColorData = initColorData; 189a3e0fd82Sopenharmony_ci for (int16_t col = 1; col < width; ++col) { 190a3e0fd82Sopenharmony_ci initColorData += QRCODE_FACTOR_NUM; 191a3e0fd82Sopenharmony_ci if (memcpy_s(initColorData, QRCODE_FACTOR_NUM, tempColorData, QRCODE_FACTOR_NUM) != EOK) { 192a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::FillQrCodeBackgroundColor memcpy_s failed!\n"); 193a3e0fd82Sopenharmony_ci return; 194a3e0fd82Sopenharmony_ci } 195a3e0fd82Sopenharmony_ci } 196a3e0fd82Sopenharmony_ci initColorData = tempColorData; 197a3e0fd82Sopenharmony_ci int32_t deltaWidth = QRCODE_FACTOR_NUM * width; 198a3e0fd82Sopenharmony_ci for (int16_t row = 1; row < imageInfo_.header.height; ++row) { 199a3e0fd82Sopenharmony_ci initColorData += deltaWidth; 200a3e0fd82Sopenharmony_ci if (memcpy_s(initColorData, deltaWidth, tempColorData, deltaWidth) != EOK) { 201a3e0fd82Sopenharmony_ci GRAPHIC_LOGE("UIQrcode::FillQrCodeBackgroundColor memcpy_s failed!\n"); 202a3e0fd82Sopenharmony_ci return; 203a3e0fd82Sopenharmony_ci } 204a3e0fd82Sopenharmony_ci } 205a3e0fd82Sopenharmony_ci} 206a3e0fd82Sopenharmony_ci 207a3e0fd82Sopenharmony_civoid UIQrcode::GetDestData(uint8_t* destData, int32_t outFilePixelPrescaler) 208a3e0fd82Sopenharmony_ci{ 209a3e0fd82Sopenharmony_ci uint32_t width = imageInfo_.header.width; 210a3e0fd82Sopenharmony_ci width = UI_ALIGN_UP(width); 211a3e0fd82Sopenharmony_ci 212a3e0fd82Sopenharmony_ci for (int32_t x = 0; x < outFilePixelPrescaler; ++x) { 213a3e0fd82Sopenharmony_ci uint8_t* tempData = destData + width * QRCODE_FACTOR_NUM * x; 214a3e0fd82Sopenharmony_ci for (int32_t y = 0; y < outFilePixelPrescaler; ++y) { 215a3e0fd82Sopenharmony_ci *(tempData + 0) = qrColor_.blue; // 0: B channel 216a3e0fd82Sopenharmony_ci *(tempData + 1) = qrColor_.green; // 1: G channel 217a3e0fd82Sopenharmony_ci *(tempData + 2) = qrColor_.red; // 2: R channel 218a3e0fd82Sopenharmony_ci *(tempData + 3) = OPA_OPAQUE; // 3: Alpha channel 219a3e0fd82Sopenharmony_ci tempData += QRCODE_FACTOR_NUM; 220a3e0fd82Sopenharmony_ci } 221a3e0fd82Sopenharmony_ci } 222a3e0fd82Sopenharmony_ci} 223a3e0fd82Sopenharmony_ci} // namespace OHOS 224