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     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 
GenerateQrCode(qrcodegen::QrCode & qrcode)142 void UIQrcode::GenerateQrCode(qrcodegen::QrCode& qrcode)
143 {
144     FillQrCodeBackgroundColor();
145 
146     FillQrCodeColor(qrcode);
147 }
148 
FillQrCodeColor(qrcodegen::QrCode & qrcode)149 void 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 
FillQrCodeBackgroundColor()177 void 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 
GetDestData(uint8_t * destData,int32_t outFilePixelPrescaler)207 void 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