1 /*
2 * Copyright (C) 2024 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 "webp_exif_metadata_accessor.h"
17
18 #include <libexif/exif-data.h>
19
20 #include "file_metadata_stream.h"
21 #include "image_log.h"
22 #include "media_errors.h"
23 #include "tiff_parser.h"
24
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
27
28 #undef LOG_TAG
29 #define LOG_TAG "WebpExifMetadataAccessor"
30
31 namespace OHOS {
32 namespace Media {
33 namespace {
34 byte WEBP_PAD_ODD = 0x00;
35 constexpr auto WEBP_RIFF_SIZE = 4;
36 constexpr auto WEBP_FILE_SIZE_BUFF_SIZE = 4;
37 constexpr auto WEBP_CHUNK_HEAD_SIZE = 12;
38 constexpr auto WEBP_CHUNK_ID_SIZE = 4;
39 constexpr auto WEBP_CHUNK_SIZE = 4;
40 constexpr auto WEBP_CHUNK_VP8X_SIZE = 18;
41 constexpr auto WEBP_EXIF_FLAG_BIT = 0x08;
42 constexpr auto WEBP_BYTE_BITS = 8;
43 constexpr auto WEBP_BUF_SIZE = 2;
44 constexpr auto WEBP_CHUNK_WIDTH_OFFSET = 6;
45 constexpr auto WEBP_CHUNK_HEIGHT_OFFSET = 8;
46 constexpr auto WEBP_VP8L_WIDTH_BIT = 0x3F;
47 constexpr auto WEBP_VP8L_HEIGHT_BIT = 0x3FU;
48 constexpr auto WEBP_VP8L_HEIGHT_BIT1 = 0xFU;
49 constexpr auto WEBP_CHUNK_HEADER_VP8X = "VP8X";
50 constexpr auto WEBP_CHUNK_HEADER_VP8 = "VP8 ";
51 constexpr auto WEBP_CHUNK_HEADER_VP8L = "VP8L";
52 constexpr auto WEBP_CHUNK_HEADER_ANMF = "ANMF";
53 constexpr auto WEBP_CHUNK_HEADER_EXIF = "EXIF";
54 constexpr auto WEBP_CHUNK_OPERATE_FLAG = 0xFF;
55 constexpr auto WEBP_WRITE_BLOCK = 4096 * 32;
56 constexpr auto WEBP_MAX_CHUNKDATA_SIZE = 300 * 1024 * 1024;
57 }
58
WebpExifMetadataAccessor(std::shared_ptr<MetadataStream> & stream)59 WebpExifMetadataAccessor::WebpExifMetadataAccessor(std::shared_ptr<MetadataStream> &stream)
60 : AbstractExifMetadataAccessor(stream)
61 {}
62
~WebpExifMetadataAccessor()63 WebpExifMetadataAccessor::~WebpExifMetadataAccessor() {}
64
Read()65 uint32_t WebpExifMetadataAccessor::Read()
66 {
67 DataBuf dataBuf;
68 if (!ReadBlob(dataBuf)) {
69 IMAGE_LOGD("Image stream does not have dataBuf.");
70 return ERR_IMAGE_SOURCE_DATA;
71 }
72
73 ExifData *exifData;
74 TiffParser::Decode(reinterpret_cast<const unsigned char *>(dataBuf.CData()), dataBuf.Size(), &exifData);
75 if (exifData == nullptr) {
76 IMAGE_LOGD("Image stream does not have exifData.");
77 return ERR_IMAGE_DECODE_FAILED;
78 }
79
80 exifMetadata_ = std::make_shared<OHOS::Media::ExifMetadata>(exifData);
81
82 return SUCCESS;
83 }
84
ReadBlob(DataBuf & blob)85 bool WebpExifMetadataAccessor::ReadBlob(DataBuf &blob)
86 {
87 if (!imageStream_->IsOpen()) {
88 if (!imageStream_->Open(OpenMode::ReadWrite)) {
89 IMAGE_LOGE("Output image stream open failed.");
90 return false;
91 }
92 }
93 imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
94
95 Vp8xAndExifInfo exifFlag = Vp8xAndExifInfo::UNKNOWN;
96 if (!CheckChunkVp8x(exifFlag)) {
97 return false;
98 }
99
100 while (!imageStream_->IsEof()) {
101 DataBuf chunkId(WEBP_CHUNK_ID_SIZE);
102 if (static_cast<size_t>(imageStream_->Read(chunkId.Data(), chunkId.Size())) != chunkId.Size() ||
103 imageStream_->IsEof()) {
104 IMAGE_LOGE("Image stream does not find chunkid.");
105 return false;
106 }
107
108 DataBuf chunkSize(WEBP_CHUNK_SIZE);
109 if (static_cast<size_t>(imageStream_->Read(chunkSize.Data(), chunkSize.Size())) != chunkSize.Size() ||
110 imageStream_->IsEof()) {
111 IMAGE_LOGE("Image stream does not find chunk size.");
112 return false;
113 }
114 const uint32_t size = chunkSize.ReadUInt32(0, littleEndian);
115 const size_t imgSize = static_cast<size_t>(imageStream_->GetSize());
116 if (size > imgSize - imageStream_->Tell()) {
117 IMAGE_LOGE("Read chunk length error.");
118 return false;
119 }
120
121 std::string strChunkId(reinterpret_cast<const char*>(chunkId.CData()), WEBP_CHUNK_ID_SIZE);
122 if (strChunkId != WEBP_CHUNK_HEADER_EXIF) {
123 imageStream_->Seek(size, SeekPos::CURRENT);
124 if (size % WEBP_BUF_SIZE) {
125 imageStream_->Seek(1, SeekPos::CURRENT);
126 }
127 continue;
128 }
129
130 blob.Resize(size);
131 imageStream_->Read(blob.Data(), size);
132 tiffOffset_ = imageStream_->Tell() - static_cast<long>(blob.Size());
133 return true;
134 }
135
136 IMAGE_LOGE("Image stream does not find exif blob.");
137 return false;
138 }
139
CheckChunkVp8x(Vp8xAndExifInfo & exifFlag) const140 bool WebpExifMetadataAccessor::CheckChunkVp8x(Vp8xAndExifInfo &exifFlag) const
141 {
142 DataBuf chunkId(WEBP_CHUNK_ID_SIZE);
143 if (static_cast<size_t>(imageStream_->Read(chunkId.Data(), chunkId.Size())) != chunkId.Size() ||
144 imageStream_->IsEof()) {
145 IMAGE_LOGD("Image stream does not find vp8x.");
146 return false;
147 }
148
149 std::string strChunkId(reinterpret_cast<const char *>(chunkId.CData()), WEBP_CHUNK_ID_SIZE);
150 if (strChunkId != WEBP_CHUNK_HEADER_VP8X) {
151 exifFlag = Vp8xAndExifInfo::VP8X_NOT_EXIST;
152 IMAGE_LOGD("Image stream does not find vp8x.");
153 return false;
154 }
155
156 byte chunkSize[WEBP_CHUNK_ID_SIZE];
157 if (static_cast<size_t>(imageStream_->Read(chunkSize, WEBP_CHUNK_SIZE)) != WEBP_CHUNK_SIZE ||
158 imageStream_->IsEof()) {
159 IMAGE_LOGE("Image stream does not find vp8x size.");
160 return false;
161 }
162 const uint32_t size = GetULong(chunkSize, littleEndian);
163 if (size > WEBP_MAX_CHUNKDATA_SIZE) {
164 IMAGE_LOGE("Image stream chunkdata size is too large.");
165 return false;
166 }
167 DataBuf chunkData(size);
168 if (size == 0 || chunkData.Empty() || chunkData.Data() == nullptr) {
169 IMAGE_LOGE("Image stream does not find vp8x data.");
170 return false;
171 }
172
173 if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size() ||
174 imageStream_->IsEof()) {
175 IMAGE_LOGE("Image stream does not find vp8x data.");
176 return false;
177 }
178
179 byte reserved = chunkData.Data()[0];
180 if (!(reserved & WEBP_EXIF_FLAG_BIT)) {
181 exifFlag = Vp8xAndExifInfo::EXIF_NOT_EXIST;
182 IMAGE_LOGD("Image stream does not have exifData.");
183 return false;
184 }
185 exifFlag = Vp8xAndExifInfo::EXIF_EXIST;
186 return true;
187 }
188
Write()189 uint32_t WebpExifMetadataAccessor::Write()
190 {
191 uint8_t *dataBlob = nullptr;
192 uint32_t size = 0;
193 if (!GetExifEncodeBlob(&dataBlob, size)) {
194 IMAGE_LOGE("Encode Metadata failed.");
195 return ERR_MEDIA_VALUE_INVALID;
196 }
197
198 uint32_t result = UpdateData(dataBlob, size);
199
200 if (dataBlob != nullptr) {
201 free(dataBlob);
202 dataBlob = nullptr;
203 }
204
205 return result;
206 }
207
GetExifEncodeBlob(uint8_t ** dataBlob,uint32_t & size)208 bool WebpExifMetadataAccessor::GetExifEncodeBlob(uint8_t **dataBlob, uint32_t &size)
209 {
210 if (this->Get() == nullptr) {
211 IMAGE_LOGE("Exif blob empty.");
212 return false;
213 }
214
215 ExifData *exifData = this->Get()->GetExifData();
216 TiffParser::Encode(dataBlob, size, exifData);
217
218 if (dataBlob == nullptr || *dataBlob == nullptr) {
219 IMAGE_LOGE("Encode webp data failed.");
220 return false;
221 }
222
223 return (size > 0);
224 }
225
WriteBlob(DataBuf & blob)226 uint32_t WebpExifMetadataAccessor::WriteBlob(DataBuf &blob)
227 {
228 byte *dataBlob = nullptr;
229 uint32_t size = 0;
230 if (!GetExifBlob(blob, &dataBlob, size)) {
231 IMAGE_LOGE("Blob data empty.");
232 return ERR_MEDIA_VALUE_INVALID;
233 }
234
235 return UpdateData(dataBlob, size);
236 }
237
GetExifBlob(const DataBuf & blob,uint8_t ** dataBlob,uint32_t & size)238 bool WebpExifMetadataAccessor::GetExifBlob(const DataBuf &blob, uint8_t **dataBlob, uint32_t &size)
239 {
240 if (blob.Empty()) {
241 IMAGE_LOGE("Image exif blob data empty.");
242 return false;
243 }
244
245 *dataBlob = const_cast<byte *>(blob.CData());
246 size = blob.Size();
247
248 return true;
249 }
250
UpdateData(uint8_t * dataBlob,uint32_t size)251 uint32_t WebpExifMetadataAccessor::UpdateData(uint8_t *dataBlob, uint32_t size)
252 {
253 BufferMetadataStream tmpBufStream;
254 if (!tmpBufStream.Open(OpenMode::ReadWrite)) {
255 IMAGE_LOGE("Image temp stream open failed.");
256 return ERR_IMAGE_SOURCE_DATA;
257 }
258
259 if (!imageStream_->IsOpen()) {
260 IMAGE_LOGE("Output image stream not open.");
261 return ERR_IMAGE_SOURCE_DATA;
262 }
263
264 if (!UpdateExifMetadata(tmpBufStream, dataBlob, size)) {
265 IMAGE_LOGE("Image temp stream write failed.");
266 return ERROR;
267 }
268
269 imageStream_->Seek(0, SeekPos::BEGIN);
270 if (!imageStream_->CopyFrom(tmpBufStream)) {
271 IMAGE_LOGE("Copy from temp stream failed");
272 return ERR_MEDIA_INVALID_OPERATION;
273 }
274 return SUCCESS;
275 }
276
UpdateExifMetadata(BufferMetadataStream & bufStream,uint8_t * dataBlob,uint32_t size)277 bool WebpExifMetadataAccessor::UpdateExifMetadata(BufferMetadataStream &bufStream, uint8_t *dataBlob, uint32_t size)
278 {
279 Vp8xAndExifInfo exifFlag = Vp8xAndExifInfo::UNKNOWN;
280 if (!WriteHeader(bufStream, size, exifFlag)) {
281 IMAGE_LOGE("Output image stream write header failed.");
282 return false;
283 }
284
285 imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
286 if (!WirteChunkVp8x(bufStream, exifFlag)) {
287 IMAGE_LOGE("Output image stream write vp8x failed.");
288 return false;
289 }
290
291 if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST || exifFlag == Vp8xAndExifInfo::EXIF_NOT_EXIST) {
292 return InsertExifMetadata(bufStream, dataBlob, size);
293 }
294
295 while (!imageStream_->IsEof()) {
296 DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
297 if (static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size() ||
298 imageStream_->IsEof()) {
299 IMAGE_LOGE("Failed to read image chunk header information.");
300 return false;
301 }
302
303 uint32_t chunkSize = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
304 const ssize_t imgSize = imageStream_->GetSize();
305 if (chunkSize > imgSize - imageStream_->Tell()) {
306 IMAGE_LOGE("Read chunk length error.");
307 return false;
308 }
309
310 if (chunkSize % WEBP_BUF_SIZE) {
311 ++chunkSize;
312 }
313
314 DataBuf chunkData(chunkSize);
315 if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
316 IMAGE_LOGE("Failed to read image chunk data.");
317 return false;
318 }
319
320 std::string strChunkId(reinterpret_cast<const char *>(chunkHead.CData()), WEBP_CHUNK_ID_SIZE);
321 if (strChunkId == WEBP_CHUNK_HEADER_EXIF) {
322 UL2Data(chunkHead.Data(WEBP_FILE_SIZE_BUFF_SIZE), size, littleEndian);
323 bufStream.Write(chunkHead.Data(), chunkHead.Size());
324 bufStream.Write(dataBlob, size);
325 if (chunkData.Size() % WEBP_BUF_SIZE) {
326 bufStream.Write(&WEBP_PAD_ODD, 1);
327 }
328 break;
329 }
330
331 bufStream.Write(chunkHead.Data(), chunkHead.Size());
332 bufStream.Write(chunkData.Data(), chunkData.Size());
333 }
334
335 return CopyRestData(bufStream);
336 }
337
InsertExifMetadata(BufferMetadataStream & bufStream,uint8_t * dataBlob,uint32_t size)338 bool WebpExifMetadataAccessor::InsertExifMetadata(BufferMetadataStream &bufStream, uint8_t *dataBlob, uint32_t size)
339 {
340 if (!CopyRestData(bufStream)) {
341 return false;
342 }
343
344 static byte exifChunckId[] = { 0x45, 0x58, 0x49, 0x46 };
345 if (bufStream.Write(exifChunckId, WEBP_CHUNK_ID_SIZE) != WEBP_CHUNK_ID_SIZE) {
346 IMAGE_LOGE("BufStream tell: %{public}lu", bufStream.Tell());
347 return false;
348 }
349 DataBuf exifChunckSize(WEBP_CHUNK_SIZE);
350 UL2Data(exifChunckSize.Data(), size, littleEndian);
351 if (bufStream.Write(exifChunckSize.Data(), exifChunckSize.Size()) != (ssize_t)exifChunckSize.Size() ||
352 bufStream.Write(dataBlob, size) != size) {
353 return false;
354 }
355 if (size % WEBP_BUF_SIZE) {
356 bufStream.Write(&WEBP_PAD_ODD, 1);
357 }
358 return true;
359 }
360
GetImageWidthAndHeight()361 std::tuple<uint32_t, uint32_t> WebpExifMetadataAccessor::GetImageWidthAndHeight()
362 {
363 while (!imageStream_->IsEof()) {
364 DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
365 if (static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size() ||
366 imageStream_->IsEof()) {
367 IMAGE_LOGE("Failed to read image chunk header information.");
368 return std::make_tuple(0, 0);
369 }
370
371 const uint32_t size = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
372 const ssize_t imgSize = imageStream_->GetSize();
373 if (size > imgSize - imageStream_->Tell()) {
374 IMAGE_LOGE("Read chunk length error.");
375 return std::make_tuple(0, 0);
376 }
377
378 DataBuf chunkData(size);
379 if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
380 IMAGE_LOGE("Failed to read image chunk data.");
381 return std::make_tuple(0, 0);
382 }
383
384 std::string strChunkId(reinterpret_cast<const char *>(chunkHead.CData()), WEBP_CHUNK_ID_SIZE);
385 if (strChunkId == WEBP_CHUNK_HEADER_VP8 || strChunkId == WEBP_CHUNK_HEADER_VP8L ||
386 strChunkId == WEBP_CHUNK_HEADER_ANMF) {
387 return GetWidthAndHeightFormChunk(strChunkId, chunkData);
388 }
389 }
390 return std::make_tuple(0, 0);
391 }
392
GetWidthAndHeightFormChunk(const std::string & strChunkId,const DataBuf & chunkData)393 std::tuple<uint32_t, uint32_t> WebpExifMetadataAccessor::GetWidthAndHeightFormChunk(const std::string &strChunkId,
394 const DataBuf &chunkData)
395 {
396 uint32_t width = 0;
397 uint32_t height = 0;
398 static const uint32_t bitOperVp8 = 0x3fff;
399 static const byte offset3 = 3;
400 static const byte offset2 = 2;
401 if (strChunkId == WEBP_CHUNK_HEADER_VP8 && chunkData.Size() >= (WEBP_CHUNK_HEIGHT_OFFSET + WEBP_BUF_SIZE)) {
402 byte sizeBuf[WEBP_BUF_SIZE];
403
404 (void)memcpy_s(&sizeBuf, WEBP_BUF_SIZE, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET), WEBP_BUF_SIZE);
405 width = GetUShort(sizeBuf, littleEndian) & bitOperVp8;
406 (void)memcpy_s(&sizeBuf, WEBP_BUF_SIZE, chunkData.CData(WEBP_CHUNK_HEIGHT_OFFSET), WEBP_BUF_SIZE);
407 height = GetUShort(sizeBuf, littleEndian) & bitOperVp8;
408 return std::make_tuple(width, height);
409 }
410
411 if (strChunkId == WEBP_CHUNK_HEADER_VP8L && chunkData.Size() >= (WEBP_BUF_SIZE + WEBP_BUF_SIZE + 1)) {
412 byte bufWidth[WEBP_BUF_SIZE];
413 byte bufHeight[WEBP_BUF_SIZE + 1];
414
415 (void)memcpy_s(&bufWidth, WEBP_BUF_SIZE, chunkData.CData(1), WEBP_BUF_SIZE);
416 bufWidth[1] &= WEBP_VP8L_WIDTH_BIT;
417 width = GetUShort(bufWidth, littleEndian) + 1;
418 (void)memcpy_s(&bufHeight, WEBP_BUF_SIZE + 1, chunkData.CData(WEBP_BUF_SIZE), WEBP_BUF_SIZE + 1);
419 bufHeight[0] = ((bufHeight[0] >> WEBP_CHUNK_WIDTH_OFFSET) & offset3) |
420 ((bufHeight[1] & WEBP_VP8L_HEIGHT_BIT) << offset2);
421 bufHeight[1] = ((bufHeight[1] >> WEBP_CHUNK_WIDTH_OFFSET) & offset3) |
422 ((bufHeight[WEBP_BUF_SIZE] & WEBP_VP8L_HEIGHT_BIT1) << offset2);
423 height = GetUShort(bufHeight, littleEndian) + 1;
424 return std::make_tuple(width, height);
425 }
426
427 if (strChunkId == WEBP_CHUNK_HEADER_ANMF && chunkData.Size() >= (WEBP_CHUNK_WIDTH_OFFSET + offset3 + offset3)) {
428 byte sizeBuf[WEBP_CHUNK_SIZE];
429
430 (void)memcpy_s(&sizeBuf, offset3, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET), offset3);
431 sizeBuf[offset3] = 0;
432 width = GetULong(sizeBuf, littleEndian) + 1;
433 (void)memcpy_s(&sizeBuf, offset3, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET + offset3), offset3);
434 sizeBuf[offset3] = 0;
435 height = GetULong(sizeBuf, littleEndian) + 1;
436 return std::make_tuple(width, height);
437 }
438 return std::make_tuple(width, height);
439 }
440
CopyRestData(BufferMetadataStream & bufStream)441 bool WebpExifMetadataAccessor::CopyRestData(BufferMetadataStream &bufStream)
442 {
443 DataBuf buf(WEBP_WRITE_BLOCK);
444 ssize_t readSize = imageStream_->Read(buf.Data(), buf.Size());
445 while (readSize > 0) {
446 if (bufStream.Write(buf.Data(), readSize) != readSize) {
447 IMAGE_LOGE("Write block data to temp stream failed.");
448 return false;
449 }
450 readSize = imageStream_->Read(buf.Data(), buf.Size());
451 }
452
453 return true;
454 }
455
WriteHeader(BufferMetadataStream & bufStream,uint32_t size,Vp8xAndExifInfo & exifFlag)456 bool WebpExifMetadataAccessor::WriteHeader(BufferMetadataStream &bufStream, uint32_t size, Vp8xAndExifInfo &exifFlag)
457 {
458 DataBuf headInfo(WEBP_CHUNK_HEAD_SIZE);
459 imageStream_->Seek(0, SeekPos::BEGIN);
460 if (static_cast<size_t>(imageStream_->Read(headInfo.Data(), headInfo.Size())) != headInfo.Size() ||
461 imageStream_->IsEof()) {
462 return false;
463 }
464 uint32_t fileSize = GetULong(headInfo.Data(WEBP_RIFF_SIZE), littleEndian) + size;
465 if (size % WEBP_BUF_SIZE) {
466 ++fileSize;
467 }
468
469 if (!CheckChunkVp8x(exifFlag) && exifFlag == Vp8xAndExifInfo::UNKNOWN) {
470 return false;
471 }
472
473 if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST || exifFlag == Vp8xAndExifInfo::EXIF_NOT_EXIST) {
474 fileSize += exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST ? WEBP_CHUNK_VP8X_SIZE : 0;
475 fileSize += WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE;
476 UL2Data(headInfo.Data(WEBP_FILE_SIZE_BUFF_SIZE), fileSize, littleEndian);
477 IMAGE_LOGD("Write webp file size: %{public}u, new exif size: %{public}u", fileSize, size);
478 return bufStream.Write(headInfo.Data(), headInfo.Size()) == (ssize_t)headInfo.Size();
479 }
480
481 DataBuf exifData;
482 if (!ReadBlob(exifData)) {
483 return false;
484 }
485
486 fileSize -= (exifData.Size() % WEBP_BUF_SIZE) ? (exifData.Size() + 1) : exifData.Size();
487 UL2Data(headInfo.Data(WEBP_FILE_SIZE_BUFF_SIZE), fileSize, littleEndian);
488 IMAGE_LOGD("Write webp file size: %{public}u, old exif size: %{public}u, new exif size: %{public}lu",
489 fileSize, size, static_cast<unsigned long>(exifData.Size()));
490 return bufStream.Write(headInfo.Data(), headInfo.Size()) == (ssize_t)headInfo.Size();
491 }
492
WirteChunkVp8x(BufferMetadataStream & bufStream,const Vp8xAndExifInfo & exifFlag)493 bool WebpExifMetadataAccessor::WirteChunkVp8x(BufferMetadataStream &bufStream, const Vp8xAndExifInfo &exifFlag)
494 {
495 if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST) {
496 auto [width, height] = GetImageWidthAndHeight();
497 imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
498 if (width <= 0 || height <= 0) {
499 return false;
500 }
501 static byte chunckHeader[] = { 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x08,
502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
503 size_t offset = WEBP_CHUNK_HEAD_SIZE;
504 uint32_t w = width - 1;
505 chunckHeader[offset] = w & WEBP_CHUNK_OPERATE_FLAG;
506 chunckHeader[++offset] = (w >> WEBP_BYTE_BITS) & WEBP_CHUNK_OPERATE_FLAG;
507 chunckHeader[++offset] = (w >> (WEBP_BYTE_BITS + WEBP_BYTE_BITS)) & WEBP_CHUNK_OPERATE_FLAG;
508
509 uint32_t h = height - 1;
510 chunckHeader[++offset] = h & WEBP_CHUNK_OPERATE_FLAG;
511 chunckHeader[++offset] = (h >> WEBP_BYTE_BITS) & WEBP_CHUNK_OPERATE_FLAG;
512 chunckHeader[++offset] = (h >> (WEBP_BYTE_BITS + WEBP_BYTE_BITS)) & WEBP_CHUNK_OPERATE_FLAG;
513 return bufStream.Write(chunckHeader, WEBP_CHUNK_VP8X_SIZE) == WEBP_CHUNK_VP8X_SIZE;
514 }
515
516 DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
517 if (static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size()) {
518 return false;
519 }
520 if (bufStream.Write(chunkHead.Data(), chunkHead.Size()) != (ssize_t)chunkHead.Size()) {
521 return false;
522 }
523
524 const uint32_t size = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
525 DataBuf chunkData(size);
526 if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
527 return false;
528 }
529 if (chunkData.Data() == nullptr) {
530 return false;
531 }
532 chunkData.Data()[0] |= WEBP_EXIF_FLAG_BIT;
533 return bufStream.Write(chunkData.Data(), chunkData.Size()) == (ssize_t)chunkData.Size();
534 }
535 } // namespace Media
536 } // namespace OHOS