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
6#include <QtCore/private/qohoslogger_p.h>
7#include <QtCore/qspan.h>
8#include <QtCore/qsysinfo.h>
9#include <cstring>
10#include <qarkui/qarkuiutils.h>
11#include <qohosimageformat.h>
12
14
15namespace
16{
17
24
26{
27 return pixelFormat.alphaUsage() == QPixelFormat::UsesAlpha
28 ? pixelFormat.premultiplied() == QPixelFormat::Premultiplied
29 ? ::PIXELMAP_ALPHA_TYPE::PIXELMAP_ALPHA_TYPE_PREMULTIPLIED
30 : ::PIXELMAP_ALPHA_TYPE::PIXELMAP_ALPHA_TYPE_UNPREMULTIPLIED
31 : ::PIXELMAP_ALPHA_TYPE::PIXELMAP_ALPHA_TYPE_OPAQUE;
32}
33
35{
36 ::OH_Pixelmap_InitializationOptions *initOptionsPtr {};
37
38 QArkUi::callArkUiOrFailOnErrorResult(
39 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_Create),
40 &initOptionsPtr);
41
42 return std::shared_ptr<::OH_Pixelmap_InitializationOptions>(
43 initOptionsPtr,
44 [](auto *initOptionsPtr) {
45 if (initOptionsPtr != nullptr) {
46 QArkUi::callArkUiOrFailOnErrorResult(
47 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_Release),
48 initOptionsPtr);
49 }
50 });
51}
52
54 std::uint32_t width, std::uint32_t height, ::PIXEL_FORMAT pixelFormat,
55 ::PIXELMAP_ALPHA_TYPE alphaType)
56{
57 auto initOptions = createOhPixelmapInitializationOptions();
58
59 QArkUi::callArkUiOrFailOnErrorResult(
60 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_SetWidth),
61 initOptions.get(), width);
62
63 QArkUi::callArkUiOrFailOnErrorResult(
64 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_SetHeight),
65 initOptions.get(), height);
66
67 QArkUi::callArkUiOrFailOnErrorResult(
68 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_SetSrcPixelFormat),
69 initOptions.get(), static_cast<int>(pixelFormat));
70
71 QArkUi::callArkUiOrFailOnErrorResult(
72 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_SetPixelFormat),
73 initOptions.get(), static_cast<int>(pixelFormat));
74
75 QArkUi::callArkUiOrFailOnErrorResult(
76 Q_OHOS_NAMED_FUNC(::OH_PixelmapInitializationOptions_SetAlphaType),
77 initOptions.get(), static_cast<int>(alphaType));
78
79 return initOptions;
80}
81
82QOhosPixelMapInfo getPixelMapInfo(::OH_PixelmapNative *pixelMap)
83{
84 ::OH_Pixelmap_ImageInfo *imageInfoPtr;
85 QArkUi::callArkUiOrFailOnErrorResult(
86 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_Create),
87 &imageInfoPtr);
88
89 auto imageInfo = std::shared_ptr<::OH_Pixelmap_ImageInfo>(
90 imageInfoPtr,
91 [](::OH_Pixelmap_ImageInfo *imageInfoPtr) {
92 QArkUi::callArkUiOrFailOnErrorResult(
93 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_Release),
94 imageInfoPtr);
95 });
96
97 QArkUi::callArkUiOrFailOnErrorResult(
98 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_GetImageInfo),
99 pixelMap, imageInfo.get());
100
101 std::uint32_t width;
102 QArkUi::callArkUiOrFailOnErrorResult(
103 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetWidth),
104 imageInfo.get(), &width);
105
106 std::uint32_t height;
107 QArkUi::callArkUiOrFailOnErrorResult(
108 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetHeight),
109 imageInfo.get(), &height);
110
111 int pixelFormat;
112 QArkUi::callArkUiOrFailOnErrorResult(
113 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetPixelFormat),
114 imageInfo.get(), &pixelFormat);
115
116 return {
117 .width = width,
118 .height = height,
119 .pixelFormat = static_cast<::PIXEL_FORMAT>(pixelFormat),
120 };
121}
122
123void readPixelMapData(::OH_PixelmapNative *pixelMap, QSpan<std::uint8_t> output)
124{
125 std::size_t bufferSize = output.size();
126 QArkUi::callArkUiOrFailOnErrorResult(
127 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_ReadPixels),
128 pixelMap, output.data(), &bufferSize);
129}
130
131void readPixelMapDataAsArgb(::OH_PixelmapNative *pixelMap, QSpan<std::uint8_t> output)
132{
133 std::size_t bufferSize = output.size();
134 QArkUi::callArkUiOrFailOnErrorResult(
135 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_GetArgbPixels),
136 pixelMap, output.data(), &bufferSize);
137}
138
139}
140
142{
143 ::OH_PixelmapNative *pixelMap {};
144
145 QImage effectiveImage =
146 tryMapQtPixelFormatToOhosPixelFormat(qImage.format()).hasValue()
147 ? qImage
148 : qImage.convertToFormat(QImage::Format_RGBA8888);
149 auto optOhosPixelFormat = tryMapQtPixelFormatToOhosPixelFormat(effectiveImage.format());
150 Q_ASSERT(optOhosPixelFormat.hasValue());
151 auto ohosPixelFormat = optOhosPixelFormat.value();
152
153 auto initOptions = makeNativePixelMapInitializationOptions(
154 static_cast<std::uint32_t>(effectiveImage.width()),
155 static_cast<std::uint32_t>(effectiveImage.height()), ohosPixelFormat,
156 mapQtPixelFormatToOhosPixelMapAlphaType(effectiveImage.pixelFormat()));
157
158 QArkUi::callArkUiOrFailOnErrorResult(
159 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_CreatePixelmap),
160 effectiveImage.bits(), effectiveImage.sizeInBytes(), initOptions.get(), &pixelMap);
161
162 return std::shared_ptr<::OH_PixelmapNative>(
163 pixelMap,
164 [](::OH_PixelmapNative *pixelMap) {
165 if (pixelMap != nullptr) {
166 int res = QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_Release), pixelMap);
167 if (res != ::Image_ErrorCode::IMAGE_SUCCESS) {
168 qOhosPrintfError(
169 "%s: cannot release the pixel map (error code: %d).",
170 Q_FUNC_INFO, res);
171 }
172 }
173 });
174}
175
176void readPixelMapDataAsRgba(::OH_PixelmapNative *pixelMap, QSpan<std::uint8_t> output)
177{
178 readPixelMapDataAsArgb(pixelMap, output);
179
180 for (qsizetype pixelOffset = 0; pixelOffset < output.size(); pixelOffset += 4) {
181 std::uint8_t *pixelPtr = &output[pixelOffset];
182 std::uint8_t a = pixelPtr[0];
183 std::uint8_t r = pixelPtr[1];
184 std::uint8_t g = pixelPtr[2];
185 std::uint8_t b = pixelPtr[3];
186 pixelPtr[0] = r;
187 pixelPtr[1] = g;
188 pixelPtr[2] = b;
189 pixelPtr[3] = a;
190 }
191
192 for (unsigned i = 0; i < output.size(); ++i)
193 qOhosPrintfDebug("%s: pixelMap[%d]: %02x", Q_FUNC_INFO, i, output[i]);
194}
195
196QImage createQImageFromNativePixelMap(::OH_PixelmapNative *pixelMap)
197{
198 auto pixelMapInfo = getPixelMapInfo(pixelMap);
199
200 QImage::Format qImagePixelFormat;
201 void (*readPixelMapDataFunc)(::OH_PixelmapNative *, QSpan<std::uint8_t>);
202 std::uint32_t pixelMapBytesPerPixel;
203 switch (pixelMapInfo.pixelFormat) {
204 case ::PIXEL_FORMAT::PIXEL_FORMAT_RGBA_8888:
205 qImagePixelFormat = QImage::Format_RGBA8888;
206 readPixelMapDataFunc = &readPixelMapData;
207 pixelMapBytesPerPixel = 4;
208 break;
209 case ::PIXEL_FORMAT::PIXEL_FORMAT_RGB_888:
210 qImagePixelFormat = QImage::Format_RGB888;
211 readPixelMapDataFunc = &readPixelMapData;
212 pixelMapBytesPerPixel = 3;
213 break;
214 case ::PIXEL_FORMAT::PIXEL_FORMAT_ALPHA_8:
215 qImagePixelFormat = QImage::Format_Alpha8;
216 readPixelMapDataFunc = &readPixelMapData;
217 pixelMapBytesPerPixel = 1;
218 break;
219 case ::PIXEL_FORMAT::PIXEL_FORMAT_BGRA_8888:
220 if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
221 qImagePixelFormat = QImage::Format_ARGB32;
222 readPixelMapDataFunc = &readPixelMapData;
223 } else {
224 qImagePixelFormat = QImage::Format_RGBA8888;
225 readPixelMapDataFunc = &readPixelMapDataAsRgba;
226 }
227 pixelMapBytesPerPixel = 4;
228 break;
229 default:
230 qImagePixelFormat = QImage::Format_RGBA8888;
231 readPixelMapDataFunc = &readPixelMapDataAsRgba;
232 pixelMapBytesPerPixel = 4;
233 break;
234 }
235
236 QImage resultImage(
237 QSize {static_cast<int>(pixelMapInfo.width), static_cast<int>(pixelMapInfo.height)},
238 qImagePixelFormat);
239
240 auto pixelMapDataBytesPerLine = pixelMapInfo.width * pixelMapBytesPerPixel;
241 auto pixelMapDataSize = pixelMapInfo.height * pixelMapDataBytesPerLine;
242
243 if (resultImage.sizeInBytes() >= pixelMapDataSize) {
244 auto *pixelMapDataBufferStart = resultImage.bits() + (resultImage.sizeInBytes() - pixelMapDataSize);
245 readPixelMapDataFunc(pixelMap, QSpan(pixelMapDataBufferStart, pixelMapDataSize));
246 if (pixelMapDataBufferStart > resultImage.bits()) {
247 for (std::uint32_t row = 0; row < pixelMapInfo.height; ++row) {
248 std::memmove(
249 resultImage.scanLine(row),
250 pixelMapDataBufferStart + row * pixelMapDataBytesPerLine,
251 pixelMapDataBytesPerLine);
252 }
253 }
254 } else {
255 std::vector<std::uint8_t> pixelMapData(pixelMapDataSize);
256 readPixelMapDataFunc(pixelMap, QSpan(pixelMapData.data(), pixelMapData.size()));
257 for (std::uint32_t row = 0; row < pixelMapInfo.height; ++row) {
258 std::memcpy(
259 resultImage.scanLine(row),
260 pixelMapData.data() + row * pixelMapDataBytesPerLine,
261 resultImage.bytesPerLine());
262 }
263 }
264
265 return resultImage;
266}
267
268std::shared_ptr<::OH_PixelmapNative> wrapNativePixelMapPtr(::OH_PixelmapNative *pixelMap)
269{
270 return std::shared_ptr<::OH_PixelmapNative>(
271 pixelMap,
272 [](::OH_PixelmapNative *pixelMap) {
273 if (pixelMap != nullptr) {
274 int res = QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_Release), pixelMap);
275 if (res != ::Image_ErrorCode::IMAGE_SUCCESS) {
276 qOhosPrintfError(
277 "%s: cannot release the pixel map (error code: %d).",
278 Q_FUNC_INFO, res);
279 }
280 }
281 });
282}
283
285{
286 constexpr auto pixelFormat = ::PIXEL_FORMAT::PIXEL_FORMAT_RGBA_8888;
287 constexpr auto alphaType = ::PIXELMAP_ALPHA_TYPE::PIXELMAP_ALPHA_TYPE_OPAQUE;
288
289 auto initOptions = makeNativePixelMapInitializationOptions(1, 1, pixelFormat, alphaType);
290
291 ::OH_PixelmapNative *pixelMap = {};
292 QArkUi::callArkUiOrFailOnErrorResult(
293 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_CreateEmptyPixelmap),
294 initOptions.get(), &pixelMap);
295
296 return wrapNativePixelMapPtr(pixelMap);
297}
298
300{
301 QImage effectiveImage =
302 tryMapQtPixelFormatToOhosPixelFormat(image.format()).hasValue()
303 ? image
304 : image.convertToFormat(QImage::Format_RGBA8888);
305 auto optOhosPixelFormat = tryMapQtPixelFormatToOhosPixelFormat(effectiveImage.format());
306 Q_ASSERT(optOhosPixelFormat.hasValue());
307 auto ohosPixelFormat = optOhosPixelFormat.value();
308
309 auto *env = jsState.env();
310
311 auto destBytesPerLine = effectiveImage.bytesPerLine();
312 auto arrayBuffer = QNapi::ArrayBuffer::New(env, effectiveImage.height() * destBytesPerLine);
313
314 for (int y = 0; y < effectiveImage.height(); ++y) {
315 std::memcpy(
316 static_cast<uchar *>(arrayBuffer.Data()) + y * destBytesPerLine, effectiveImage.scanLine(y), destBytesPerLine);
317 }
318
319 const auto options = QNapi::makeObject(
320 env,
321 {
322 {
323 "size",
324 QNapi::makeObject(
325 env,
326 {
327 {"width", effectiveImage.size().width()},
328 {"height", effectiveImage.size().height()},
329 })
330 },
331 {"pixelFormat", static_cast<int>(ohosPixelFormat)},
332 {"srcPixelFormat", static_cast<int>(ohosPixelFormat)},
333 });
334
335 return jsState.eval<QNapi::Object>("@ohos.multimedia.image.createPixelMapSync(*)", {arrayBuffer, options});
336}
337
338QT_END_NAMESPACE
Combined button and popup list for selecting options.
void readPixelMapDataAsArgb(::OH_PixelmapNative *pixelMap, QSpan< std::uint8_t > output)
::PIXELMAP_ALPHA_TYPE mapQtPixelFormatToOhosPixelMapAlphaType(const QPixelFormat &pixelFormat)
std::shared_ptr<::OH_Pixelmap_InitializationOptions > createOhPixelmapInitializationOptions()
std::shared_ptr<::OH_Pixelmap_InitializationOptions > makeNativePixelMapInitializationOptions(std::uint32_t width, std::uint32_t height, ::PIXEL_FORMAT pixelFormat, ::PIXELMAP_ALPHA_TYPE alphaType)
QOhosPixelMapInfo getPixelMapInfo(::OH_PixelmapNative *pixelMap)
void readPixelMapData(::OH_PixelmapNative *pixelMap, QSpan< std::uint8_t > output)
void readPixelMapDataAsRgba(::OH_PixelmapNative *pixelMap, QSpan< std::uint8_t > output)
QNapi::Object createNapiPixelMapFromQImage(QtOhos::JsState &jsState, const QImage &image)
std::shared_ptr<::OH_PixelmapNative > makeEmptyNativePixelMap()
QImage createQImageFromNativePixelMap(::OH_PixelmapNative *pixelMap)
std::shared_ptr<::OH_PixelmapNative > wrapNativePixelMapPtr(::OH_PixelmapNative *pixelMap)
QT_BEGIN_NAMESPACE std::shared_ptr<::OH_PixelmapNative > createNativePixelMapFromQImage(QImage qImage)