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