Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohospixelmapconversions.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qohospixelmapconversions.h>
5
7#include <QtCore/private/qohoslogger_p.h>
8#include <QtCore/qspan.h>
9#include <QtCore/qsysinfo.h>
10#include <QtGui/private/qohosimageconversions_p.h>
11#include <cmath>
12#include <cstring>
13#include <qarkui/qarkuiutils.h>
14
16
17namespace
18{
19
26
27QOhosPixelMapInfo getPixelMapInfo(::OH_PixelmapNative *pixelMap)
28{
29 ::OH_Pixelmap_ImageInfo *imageInfoPtr;
30 QArkUi::callArkUiOrFailOnErrorResult(
31 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_Create),
32 &imageInfoPtr);
33
34 auto imageInfo = std::shared_ptr<::OH_Pixelmap_ImageInfo>(
35 imageInfoPtr,
36 [](::OH_Pixelmap_ImageInfo *imageInfoPtr) {
37 QArkUi::callArkUiOrFailOnErrorResult(
38 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_Release),
39 imageInfoPtr);
40 });
41
42 QArkUi::callArkUiOrFailOnErrorResult(
43 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_GetImageInfo),
44 pixelMap, imageInfo.get());
45
46 std::uint32_t width;
47 QArkUi::callArkUiOrFailOnErrorResult(
48 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetWidth),
49 imageInfo.get(), &width);
50
51 std::uint32_t height;
52 QArkUi::callArkUiOrFailOnErrorResult(
53 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetHeight),
54 imageInfo.get(), &height);
55
56 int pixelFormat;
57 QArkUi::callArkUiOrFailOnErrorResult(
58 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetPixelFormat),
59 imageInfo.get(), &pixelFormat);
60
61 return {
62 .width = width,
63 .height = height,
64 .pixelFormat = static_cast<::PIXEL_FORMAT>(pixelFormat),
65 };
66}
67
68void readPixelMapData(::OH_PixelmapNative *pixelMap, QSpan<std::uint8_t> output)
69{
70 std::size_t bufferSize = output.size();
71 QArkUi::callArkUiOrFailOnErrorResult(
72 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_ReadPixels),
73 pixelMap, output.data(), &bufferSize);
74}
75
76void readPixelMapDataAsArgb(::OH_PixelmapNative *pixelMap, QSpan<std::uint8_t> output)
77{
78 std::size_t bufferSize = output.size();
79 QArkUi::callArkUiOrFailOnErrorResult(
80 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_GetArgbPixels),
81 pixelMap, output.data(), &bufferSize);
82}
83
84}
85
86void readPixelMapDataAsRgba(::OH_PixelmapNative *pixelMap, QSpan<std::uint8_t> output)
87{
88 readPixelMapDataAsArgb(pixelMap, output);
89
90 for (qsizetype pixelOffset = 0; pixelOffset < output.size(); pixelOffset += 4) {
91 std::uint8_t *pixelPtr = &output[pixelOffset];
92 std::uint8_t a = pixelPtr[0];
93 std::uint8_t r = pixelPtr[1];
94 std::uint8_t g = pixelPtr[2];
95 std::uint8_t b = pixelPtr[3];
96 pixelPtr[0] = r;
97 pixelPtr[1] = g;
98 pixelPtr[2] = b;
99 pixelPtr[3] = a;
100 }
101
102 for (unsigned i = 0; i < output.size(); ++i)
103 qOhosPrintfDebug("%s: pixelMap[%d]: %02x", Q_FUNC_INFO, i, output[i]);
104}
105
106QImage createQImageFromNativePixelMap(::OH_PixelmapNative *pixelMap)
107{
108 auto pixelMapInfo = getPixelMapInfo(pixelMap);
109
110 QImage::Format qImagePixelFormat;
111 void (*readPixelMapDataFunc)(::OH_PixelmapNative *, QSpan<std::uint8_t>);
112 std::uint32_t pixelMapBytesPerPixel;
113 switch (pixelMapInfo.pixelFormat) {
114 case ::PIXEL_FORMAT::PIXEL_FORMAT_RGBA_8888:
115 qImagePixelFormat = QImage::Format_RGBA8888;
116 readPixelMapDataFunc = &readPixelMapData;
117 pixelMapBytesPerPixel = 4;
118 break;
119 case ::PIXEL_FORMAT::PIXEL_FORMAT_RGB_888:
120 qImagePixelFormat = QImage::Format_RGB888;
121 readPixelMapDataFunc = &readPixelMapData;
122 pixelMapBytesPerPixel = 3;
123 break;
124 case ::PIXEL_FORMAT::PIXEL_FORMAT_ALPHA_8:
125 qImagePixelFormat = QImage::Format_Alpha8;
126 readPixelMapDataFunc = &readPixelMapData;
127 pixelMapBytesPerPixel = 1;
128 break;
129 case ::PIXEL_FORMAT::PIXEL_FORMAT_BGRA_8888:
130 if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
131 qImagePixelFormat = QImage::Format_ARGB32;
132 readPixelMapDataFunc = &readPixelMapData;
133 } else {
134 qImagePixelFormat = QImage::Format_RGBA8888;
135 readPixelMapDataFunc = &readPixelMapDataAsRgba;
136 }
137 pixelMapBytesPerPixel = 4;
138 break;
139 default:
140 qImagePixelFormat = QImage::Format_RGBA8888;
141 readPixelMapDataFunc = &readPixelMapDataAsRgba;
142 pixelMapBytesPerPixel = 4;
143 break;
144 }
145
146 QImage resultImage(
147 QSize {static_cast<int>(pixelMapInfo.width), static_cast<int>(pixelMapInfo.height)},
148 qImagePixelFormat);
149
150 auto pixelMapDataBytesPerLine = pixelMapInfo.width * pixelMapBytesPerPixel;
151 auto pixelMapDataSize = pixelMapInfo.height * pixelMapDataBytesPerLine;
152
153 if (resultImage.sizeInBytes() >= pixelMapDataSize) {
154 auto *pixelMapDataBufferStart = resultImage.bits() + (resultImage.sizeInBytes() - pixelMapDataSize);
155 readPixelMapDataFunc(pixelMap, QSpan(pixelMapDataBufferStart, pixelMapDataSize));
156 if (pixelMapDataBufferStart > resultImage.bits()) {
157 for (std::uint32_t row = 0; row < pixelMapInfo.height; ++row) {
158 std::memmove(
159 resultImage.scanLine(row),
160 pixelMapDataBufferStart + row * pixelMapDataBytesPerLine,
161 pixelMapDataBytesPerLine);
162 }
163 }
164 } else {
165 std::vector<std::uint8_t> pixelMapData(pixelMapDataSize);
166 readPixelMapDataFunc(pixelMap, QSpan(pixelMapData.data(), pixelMapData.size()));
167 for (std::uint32_t row = 0; row < pixelMapInfo.height; ++row) {
168 std::memcpy(
169 resultImage.scanLine(row),
170 pixelMapData.data() + row * pixelMapDataBytesPerLine,
171 resultImage.bytesPerLine());
172 }
173 }
174
175 return resultImage;
176}
177
179{
180 constexpr auto fallbackDisplayDensity = 1.0;
181
182 auto primaryDisplay = jsState.eval<QNapi::Object>("@ohos.display.getPrimaryDisplaySync()");
183 auto displayInfo = QOhosDisplayInfo::makeFromOhosDisplayObject(jsState, primaryDisplay);
184
185 double density;
186 if (displayInfo.densityPixels > 0.0) {
187 density = std::lround(displayInfo.densityPixels);
188 } else {
189 qOhosPrintfDebug("%s: invalid display densityPixels: %.3f", Q_FUNC_INFO, displayInfo.densityPixels);
190 density = 0.0;
191 }
192
193 return density > 0.0 ? density : fallbackDisplayDensity;
194}
195
197{
198 qOhosPrintfDebug(
199 "%s: image dimensions: %dx%d, format: %d, bytes: %lld",
200 Q_FUNC_INFO, image.width(), image.height(), static_cast<int>(image.format()), image.sizeInBytes());
201
202 const int sourceWidth = image.width();
203 const int sourceHeight = image.height();
204
205 double density = getPrimaryDisplayPixelDensity(jsState);
206
207 const double widthVp = std::lround(sourceWidth / density);
208 const double heightVp = std::lround(sourceHeight / density);
209
210 QImage newImage = image.scaled(widthVp, heightVp, Qt::KeepAspectRatio, Qt::SmoothTransformation);
211
212 const int width = newImage.width();
213 const int height = newImage.height();
214 const double finalWidthVp = width / density;
215 const double finalHeightVp = height / density;
216
217 qOhosPrintfDebug(
218 "%s: density=%.3f, vp %.2f x %.2f -> %.2f x %.2f, px %dx%d -> %dx%d",
219 Q_FUNC_INFO, density, widthVp, heightVp, finalWidthVp, finalHeightVp, sourceWidth, sourceHeight, width, height);
220
221 return makeOhosNapiPixelMapFromQImage(jsState, newImage);
222}
223
224static QImage convertToMonochromeIconImage(const QImage &sourceImage, bool useWhite)
225{
226 QImage monochromeImage = sourceImage.copy();
227 const int colorValue = useWhite ? 255 : 0;
228
229 for (int y = 0; y < monochromeImage.height(); ++y) {
230 for (int x = 0; x < monochromeImage.width(); ++x) {
231 const QRgb pixel = monochromeImage.pixel(x, y);
232 const int alpha = qAlpha(pixel);
233
234 if (alpha > 0)
235 monochromeImage.setPixel(x, y, qRgba(colorValue, colorValue, colorValue, alpha));
236 }
237 }
238
239 return monochromeImage;
240}
241
243 QtOhos::JsState &jsState, const QImage &iconImage, bool isWhiteIcon)
244{
245 if (iconImage.isNull())
246 return std::nullopt;
247
248 qOhosPrintfDebug(
249 "%s: original Icon dimensions: %dx%d, format: %d, bytes: %lld",
250 Q_FUNC_INFO, iconImage.width(), iconImage.height(),
251 static_cast<int>(iconImage.format()), iconImage.sizeInBytes());
252
253 return makeDisplayDensityScaledJsPixelMapFromQImage(
254 jsState, convertToMonochromeIconImage(iconImage, isWhiteIcon));
255}
256
257QT_END_NAMESPACE
Combined button and popup list for selecting options.
void readPixelMapDataAsArgb(::OH_PixelmapNative *pixelMap, QSpan< std::uint8_t > output)
QOhosPixelMapInfo getPixelMapInfo(::OH_PixelmapNative *pixelMap)
void readPixelMapData(::OH_PixelmapNative *pixelMap, QSpan< std::uint8_t > output)
static double getPrimaryDisplayPixelDensity(QtOhos::JsState &jsState)
QImage createQImageFromNativePixelMap(::OH_PixelmapNative *pixelMap)
static QImage convertToMonochromeIconImage(const QImage &sourceImage, bool useWhite)
void readPixelMapDataAsRgba(::OH_PixelmapNative *pixelMap, QSpan< std::uint8_t > output)
QNapi::Object makeDisplayDensityScaledJsPixelMapFromQImage(QtOhos::JsState &jsState, const QImage &image)
std::optional< QNapi::Object > createDisplayDensityScaledJsMonochromePixelMapFromIconImage(QtOhos::JsState &jsState, const QImage &iconImage, bool isWhiteIcon)