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
21 using qrcodegen::QrCode;
22 namespace OHOS {
UIQrcode()23 UIQrcode::UIQrcode()
24 : width_(0), needDraw_(false), backgroundColor_(Color::White()), qrColor_(Color::Black()), qrcodeVal_(nullptr)
25 {
26 style_ = &(StyleDefault::GetBackgroundTransparentStyle());
27 imageInfo_ = {{0}};
28 }
29
~UIQrcode()30 UIQrcode::~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
SetQrcodeInfo(const char * val,ColorType backgroundColor,ColorType qrColor)43 void 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
RefreshQrcode()60 void UIQrcode::RefreshQrcode()
61 {
62 Invalidate();
63 if (!needDraw_) {
64 needDraw_ = true;
65 }
66 }
67
SetWidth(int16_t width)68 void UIQrcode::SetWidth(int16_t width)
69 {
70 if (GetWidth() != width) {
71 UIView::SetWidth(width);
72 RefreshQrcode();
73 }
74 }
75
SetHeight(int16_t height)76 void UIQrcode::SetHeight(int16_t height)
77 {
78 if (GetHeight() != height) {
79 UIView::SetHeight(height);
80 RefreshQrcode();
81 }
82 }
83
ReMeasure()84 void 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
SetQrcodeVal(const char * qrcodeVal,uint32_t length)99 void 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
SetImageInfo(qrcodegen::QrCode & qrcode)116 void 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 imageInfo_.dataSize = imageInfo_.header.width * imageInfo_.header.height * QRCODE_FACTOR_NUM;
129 if (imageInfo_.data != nullptr) {
130 ImageCacheFree(imageInfo_);
131 imageInfo_.data = nullptr;
132 }
133 imageInfo_.data = reinterpret_cast<uint8_t*>(ImageCacheMalloc(imageInfo_));
134 if (imageInfo_.data == nullptr) {
135 GRAPHIC_LOGE("UIQrcode::SetImageInfo imageInfo_.data is null!\n");
136 return;
137 }
138 GenerateQrCode(qrcode);
139 }
140
GenerateQrCode(qrcodegen::QrCode & qrcode)141 void UIQrcode::GenerateQrCode(qrcodegen::QrCode& qrcode)
142 {
143 FillQrCodeBackgroundColor();
144
145 FillQrCodeColor(qrcode);
146 }
147
FillQrCodeColor(qrcodegen::QrCode & qrcode)148 void UIQrcode::FillQrCodeColor(qrcodegen::QrCode& qrcode)
149 {
150 int32_t qrWidth = qrcode.getSize();
151 if (qrWidth <= 0) {
152 GRAPHIC_LOGE("UIQrcode::FillQrCodeColor generated qrcode size is less or equal 0!\n");
153 return;
154 }
155 int16_t width = imageInfo_.header.width;
156 int16_t height = imageInfo_.header.height;
157 uint16_t outFilePixelPrescaler = width_ / qrWidth;
158 int32_t offsetX = (width - outFilePixelPrescaler * qrWidth) / 2; // 2: half
159 int32_t offsetY = (height - outFilePixelPrescaler * qrWidth) / 2; // 2: half
160
161 uint8_t* destData = nullptr;
162 int64_t oneLinePixel = width * QRCODE_FACTOR_NUM * outFilePixelPrescaler;
163 int64_t oneLineOffsetPixel = (offsetY * width * QRCODE_FACTOR_NUM) + (offsetX * QRCODE_FACTOR_NUM);
164 for (int32_t y = 0; y < qrWidth; ++y) {
165 destData = const_cast<uint8_t*>(imageInfo_.data) + (oneLinePixel * y) + oneLineOffsetPixel;
166 for (int32_t x = 0; x < qrWidth; ++x) {
167 if (qrcode.getModule(x, y)) {
168 GetDestData(destData, outFilePixelPrescaler);
169 }
170 destData += QRCODE_FACTOR_NUM * outFilePixelPrescaler;
171 }
172 }
173 }
174
FillQrCodeBackgroundColor()175 void UIQrcode::FillQrCodeBackgroundColor()
176 {
177 uint8_t* initColorData = const_cast<uint8_t*>(imageInfo_.data);
178 *(initColorData + 0) = backgroundColor_.blue; // 0: B channel
179 *(initColorData + 1) = backgroundColor_.green; // 1: G channel
180 *(initColorData + 2) = backgroundColor_.red; // 2: R channel
181 *(initColorData + 3) = OPA_OPAQUE; // 3: Alpha channel
182
183 uint8_t* tempColorData = initColorData;
184 for (int16_t col = 1; col < imageInfo_.header.width; ++col) {
185 initColorData += QRCODE_FACTOR_NUM;
186 if (memcpy_s(initColorData, QRCODE_FACTOR_NUM, tempColorData, QRCODE_FACTOR_NUM) != EOK) {
187 GRAPHIC_LOGE("UIQrcode::FillQrCodeBackgroundColor memcpy_s failed!\n");
188 return;
189 }
190 }
191 initColorData = tempColorData;
192 int32_t deltaWidth = QRCODE_FACTOR_NUM * imageInfo_.header.width;
193 for (int16_t row = 1; row < imageInfo_.header.height; ++row) {
194 initColorData += deltaWidth;
195 if (memcpy_s(initColorData, deltaWidth, tempColorData, deltaWidth) != EOK) {
196 GRAPHIC_LOGE("UIQrcode::FillQrCodeBackgroundColor memcpy_s failed!\n");
197 return;
198 }
199 }
200 }
201
GetDestData(uint8_t * destData,int32_t outFilePixelPrescaler)202 void UIQrcode::GetDestData(uint8_t* destData, int32_t outFilePixelPrescaler)
203 {
204 for (int32_t x = 0; x < outFilePixelPrescaler; ++x) {
205 uint8_t* tempData = destData + imageInfo_.header.width * QRCODE_FACTOR_NUM * x;
206 for (int32_t y = 0; y < outFilePixelPrescaler; ++y) {
207 *(tempData + 0) = qrColor_.blue; // 0: B channel
208 *(tempData + 1) = qrColor_.green; // 1: G channel
209 *(tempData + 2) = qrColor_.red; // 2: R channel
210 *(tempData + 3) = OPA_OPAQUE; // 3: Alpha channel
211 tempData += QRCODE_FACTOR_NUM;
212 }
213 }
214 }
215 } // namespace OHOS
216