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 "heif_parser.h"
17 #include "box/item_property_aux_box.h"
18 #include "box/item_property_basic_box.h"
19 #include "box/item_property_display_box.h"
20 #include "box/item_property_transform_box.h"
21 #include "securec.h"
22
23 #include <algorithm>
24 #include <limits>
25 #include <cstring>
26 #include <set>
27
28 namespace OHOS {
29 namespace ImagePlugin {
30
31 const auto EXIF_ID = "Exif\0\0";
32 const auto HEIF_AUXTTYPE_ID_FRAGMENT_MAP = "urn:com:huawei:photo:5:0:0:aux:fragmentmap";
33 const std::set<std::string> INFE_ITEM_TYPE = {
34 "hvc1", "grid", "tmap", "iden", "mime"
35 };
36
37 HeifParser::HeifParser() = default;
38
39 HeifParser::~HeifParser() = default;
40
MakeFromMemory(const void * data,size_t size,bool isNeedCopy,std::shared_ptr<HeifParser> * out)41 heif_error HeifParser::MakeFromMemory(const void *data, size_t size, bool isNeedCopy, std::shared_ptr<HeifParser> *out)
42 {
43 if (data == nullptr) {
44 return heif_error_no_data;
45 }
46 auto input_stream = std::make_shared<HeifBufferInputStream>((const uint8_t *) data, size, isNeedCopy);
47 return MakeFromStream(input_stream, out);
48 }
49
MakeFromStream(const std::shared_ptr<HeifInputStream> & stream,std::shared_ptr<HeifParser> * out)50 heif_error HeifParser::MakeFromStream(const std::shared_ptr<HeifInputStream> &stream, std::shared_ptr<HeifParser> *out)
51 {
52 if (stream == nullptr) {
53 return heif_error_no_data;
54 }
55 std::shared_ptr<HeifParser> file = std::make_shared<HeifParser>(stream);
56
57 auto maxSize = static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
58 HeifStreamReader reader(stream, 0, maxSize);
59
60 heif_error errorBox = file->AssembleBoxes(reader);
61 if (errorBox != heif_error_ok) {
62 return errorBox;
63 }
64
65 heif_error errorImage = file->AssembleImages();
66 if (errorImage != heif_error_ok) {
67 return errorImage;
68 }
69
70 *out = std::move(file);
71 return errorBox;
72 }
73
Write(HeifStreamWriter & writer)74 void HeifParser::Write(HeifStreamWriter &writer)
75 {
76 CheckExtentData();
77 for (auto &box: topBoxes_) {
78 box->InferAllFullBoxVersion();
79 box->Write(writer);
80 }
81
82 ilocBox_->WriteMdatBox(writer);
83 }
84
GetPrimaryItemId() const85 heif_item_id HeifParser::GetPrimaryItemId() const
86 {
87 return pitmBox_->GetItemId();
88 }
89
GetAllItemId(std::vector<heif_item_id> & itemIdList) const90 void HeifParser::GetAllItemId(std::vector<heif_item_id> &itemIdList) const
91 {
92 for (const auto &infeBox: infeBoxes_) {
93 itemIdList.push_back(infeBox.second->GetItemId());
94 }
95 }
96
AssembleBoxes(HeifStreamReader & reader)97 heif_error HeifParser::AssembleBoxes(HeifStreamReader &reader)
98 {
99 while (true) {
100 std::shared_ptr<HeifBox> box;
101 uint32_t recursionCount = 0;
102 heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
103 if (reader.IsAtEnd() || error == heif_error_eof) {
104 break;
105 }
106 if (error != heif_error_ok) {
107 return error;
108 }
109 topBoxes_.push_back(box);
110 if (box->GetBoxType() == BOX_TYPE_META) {
111 metaBox_ = std::dynamic_pointer_cast<HeifMetaBox>(box);
112 }
113 if (box->GetBoxType() == BOX_TYPE_FTYP) {
114 ftypBox_ = std::dynamic_pointer_cast<HeifFtypBox>(box);
115 }
116 }
117
118 if (!ftypBox_) {
119 return heif_error_no_ftyp;
120 }
121
122 if (!metaBox_) {
123 return heif_error_no_meta;
124 }
125
126 hdlrBox_ = metaBox_->GetChild<HeifHdlrBox>(BOX_TYPE_HDLR);
127 if (!hdlrBox_ || (hdlrBox_ && hdlrBox_->GetHandlerType() != HANDLER_TYPE_PICT)) {
128 return heif_error_invalid_handler;
129 }
130
131 pitmBox_ = metaBox_->GetChild<HeifPtimBox>(BOX_TYPE_PITM);
132 if (!pitmBox_) {
133 return heif_error_no_pitm;
134 }
135
136 iinfBox_ = metaBox_->GetChild<HeifIinfBox>(BOX_TYPE_IINF);
137 if (!iinfBox_) {
138 return heif_error_no_iinf;
139 }
140 std::vector<std::shared_ptr<HeifInfeBox>> infes = iinfBox_->GetChildren<HeifInfeBox>(BOX_TYPE_INFE);
141 for (auto &infe: infes) {
142 infeBoxes_.insert(std::make_pair(infe->GetItemId(), infe));
143 }
144
145 irefBox_ = metaBox_->GetChild<HeifIrefBox>(BOX_TYPE_IREF);
146
147 iprpBox_ = metaBox_->GetChild<HeifIprpBox>(BOX_TYPE_IPRP);
148 if (!iprpBox_) {
149 return heif_error_no_iprp;
150 }
151
152 ipcoBox_ = iprpBox_->GetChild<HeifIpcoBox>(BOX_TYPE_IPCO);
153 if (!ipcoBox_) {
154 return heif_error_no_ipco;
155 }
156
157 std::vector<std::shared_ptr<HeifIpmaBox>> ipmas = iprpBox_->GetChildren<HeifIpmaBox>(BOX_TYPE_IPMA);
158 if (ipmas.empty()) {
159 return heif_error_no_ipma;
160 }
161 ipmaBox_ = std::make_shared<HeifIpmaBox>();
162 for (auto &ipma : ipmas) {
163 ipmaBox_->MergeImpaBoxes(*ipma);
164 }
165 idatBox_ = metaBox_->GetChild<HeifIdatBox>(BOX_TYPE_IDAT);
166
167 ilocBox_ = metaBox_->GetChild<HeifIlocBox>(BOX_TYPE_ILOC);
168 if (!ilocBox_) {
169 return heif_error_no_iloc;
170 }
171 return heif_error_ok;
172 }
173
HasItemId(heif_item_id itemId) const174 bool HeifParser::HasItemId(heif_item_id itemId) const
175 {
176 return infeBoxes_.find(itemId) != infeBoxes_.end();
177 }
178
GetItemType(heif_item_id itemId) const179 std::string HeifParser::GetItemType(heif_item_id itemId) const
180 {
181 auto infe_box = GetInfeBox(itemId);
182 if (!infe_box) {
183 return "";
184 }
185 return infe_box->GetItemType();
186 }
187
GetItemContentType(heif_item_id itemId) const188 std::string HeifParser::GetItemContentType(heif_item_id itemId) const
189 {
190 auto infe_box = GetInfeBox(itemId);
191 if (!infe_box) {
192 return "";
193 }
194 return infe_box->GetContentType();
195 }
196
GetItemUriType(heif_item_id itemId) const197 std::string HeifParser::GetItemUriType(heif_item_id itemId) const
198 {
199 auto infe_box = GetInfeBox(itemId);
200 if (!infe_box) {
201 return "";
202 }
203 return infe_box->GetItemUriType();
204 }
205
206
GetAllProperties(heif_item_id itemId,std::vector<std::shared_ptr<HeifBox>> & properties) const207 heif_error HeifParser::GetAllProperties(heif_item_id itemId, std::vector<std::shared_ptr<HeifBox>> &properties) const
208 {
209 if (!ipcoBox_) {
210 return heif_error_no_ipco;
211 }
212 if (!ipmaBox_) {
213 return heif_error_no_ipma;
214 }
215 return ipcoBox_->GetProperties(itemId, ipmaBox_, properties);
216 }
217
GetGridLength(heif_item_id itemId,size_t & length)218 heif_error HeifParser::GetGridLength(heif_item_id itemId, size_t &length)
219 {
220 if (!HasItemId(itemId)) {
221 return heif_error_item_not_found;
222 }
223 auto items = ilocBox_->GetItems();
224 const HeifIlocBox::Item *ilocItem = nullptr;
225 auto iter = std::find_if(items.begin(), items.end(), [&itemId](const auto &item) {
226 return item.itemId == itemId;
227 });
228 if (iter != items.end()) {
229 ilocItem = &*iter;
230 } else {
231 return heif_error_item_data_not_found;
232 }
233 return ilocBox_->GetIlocDataLength(*ilocItem, length);
234 }
235
GetItemData(heif_item_id itemId,std::vector<uint8_t> * out,heif_header_option option) const236 heif_error HeifParser::GetItemData(heif_item_id itemId, std::vector<uint8_t> *out, heif_header_option option) const
237 {
238 if (!HasItemId(itemId)) {
239 return heif_error_item_not_found;
240 }
241
242 auto infe_box = GetInfeBox(itemId);
243 if (!infe_box) {
244 return heif_error_item_not_found;
245 }
246
247 std::string item_type = infe_box->GetItemType();
248 auto items = ilocBox_->GetItems();
249 const HeifIlocBox::Item *ilocItem = nullptr;
250 for (const auto &item: items) {
251 if (item.itemId == itemId) {
252 ilocItem = &item;
253 break;
254 }
255 }
256 if (!ilocItem) {
257 return heif_error_item_data_not_found;
258 }
259
260 heif_error error;
261 if (item_type == "hvc1") {
262 auto hvcc = GetProperty<HeifHvccBox>(itemId);
263 if (!hvcc) {
264 return heif_error_no_hvcc;
265 }
266 if (option != heif_no_header && !hvcc->GetHeaders(out)) {
267 return heif_error_item_data_not_found;
268 }
269 if (option != heif_only_header) {
270 error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
271 } else {
272 error = heif_error_ok;
273 }
274 } else {
275 error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
276 }
277
278 return error;
279 }
280
GetTileImages(heif_item_id gridItemId,std::vector<std::shared_ptr<HeifImage>> & out)281 void HeifParser::GetTileImages(heif_item_id gridItemId, std::vector<std::shared_ptr<HeifImage>> &out)
282 {
283 auto infe = GetInfeBox(gridItemId);
284 if (!infe || infe->GetItemType() != "grid") {
285 return;
286 }
287 if (!irefBox_) {
288 return;
289 }
290 auto toItemIds = irefBox_->GetReferences(gridItemId, BOX_TYPE_DIMG);
291 for (heif_item_id toItemId: toItemIds) {
292 auto tileImage = GetImage(toItemId);
293 if (tileImage) {
294 out.push_back(tileImage);
295 }
296 }
297 }
298
GetIdenImage(heif_item_id itemId,std::shared_ptr<HeifImage> & out)299 void HeifParser::GetIdenImage(heif_item_id itemId, std::shared_ptr<HeifImage> &out)
300 {
301 auto infe = GetInfeBox(itemId);
302 if (!infe || infe->GetItemType() != "iden") {
303 return;
304 }
305 if (!irefBox_) {
306 return;
307 }
308 auto toItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
309 for (heif_item_id toItemId: toItemIds) {
310 auto idenImage = GetImage(toItemId);
311 if (idenImage) {
312 out = idenImage;
313 return;
314 }
315 }
316 }
317
GetInfeBox(heif_item_id itemId) const318 std::shared_ptr<HeifInfeBox> HeifParser::GetInfeBox(heif_item_id itemId) const
319 {
320 auto iter = infeBoxes_.find(itemId);
321 if (iter == infeBoxes_.end()) {
322 return nullptr;
323 }
324 return iter->second;
325 }
326
AssembleImages()327 heif_error HeifParser::AssembleImages()
328 {
329 images_.clear();
330 primaryImage_.reset();
331
332 std::vector<heif_item_id> allItemIds;
333 GetAllItemId(allItemIds);
334
335 for (heif_item_id itemId: allItemIds) {
336 // extract Image Item
337 auto infe = GetInfeBox(itemId);
338 if (!infe) {
339 continue;
340 }
341 const std::string& itemType = infe->GetItemType();
342 if (INFE_ITEM_TYPE.find(itemType) == INFE_ITEM_TYPE.end()) {
343 continue;
344 }
345 auto image = std::make_shared<HeifImage>(itemId);
346 if (itemType == "tmap") {
347 tmapImage_ = image;
348 ExtractImageProperties(tmapImage_);
349 continue;
350 }
351 images_.insert(std::make_pair(itemId, image));
352 if (!infe->IsHidden() && itemId == GetPrimaryItemId()) {
353 image->SetPrimaryImage(true);
354 primaryImage_ = image;
355 }
356
357 ExtractImageProperties(image);
358 }
359
360 if (!primaryImage_) {
361 return heif_error_primary_item_not_found;
362 }
363
364 ExtractGainmap(allItemIds);
365 ExtractDerivedImageProperties();
366 ExtractNonMasterImages();
367 ExtractMetadata(allItemIds);
368 return heif_error_ok;
369 }
370
ExtractIT35Metadata(const heif_item_id & metadataItemId)371 void HeifParser::ExtractIT35Metadata(const heif_item_id& metadataItemId)
372 {
373 if (GetItemType(metadataItemId) != "it35") {
374 return;
375 }
376 std::vector<uint8_t> extendInfo;
377 heif_error err = GetItemData(metadataItemId, &(extendInfo));
378 if (err != heif_error_ok || extendInfo.empty()) {
379 return;
380 }
381 primaryImage_->SetUWAInfo(extendInfo);
382 }
383
ExtractISOMetadata(const heif_item_id & itemId)384 void HeifParser::ExtractISOMetadata(const heif_item_id& itemId)
385 {
386 if (GetItemType(itemId) != "tmap") {
387 return;
388 }
389 std::vector<uint8_t> extendInfo;
390 heif_error err = GetItemData(itemId, &extendInfo);
391 if (err != heif_error_ok || extendInfo.empty()) {
392 return ;
393 }
394 primaryImage_->SetISOMetadata(extendInfo);
395 }
396
ExtractFragmentMetadata(const heif_item_id & itemId)397 void HeifParser::ExtractFragmentMetadata(const heif_item_id& itemId)
398 {
399 HeifFragmentMetadata extendInfo;
400 auto ispe = GetProperty<HeifIspeBox>(itemId);
401 if (ispe) {
402 extendInfo.width = ispe->GetWidth();
403 extendInfo.height = ispe->GetHeight();
404 }
405 auto rloc = GetProperty<HeifRlocBox>(itemId);
406 if (rloc) {
407 extendInfo.horizontalOffset = rloc->GetX();
408 extendInfo.verticalOffset = rloc->GetY();
409 }
410 primaryImage_->SetFragmentMetadata(extendInfo);
411 }
412
ExtractDisplayData(std::shared_ptr<HeifImage> & image,heif_item_id & itemId)413 void HeifParser::ExtractDisplayData(std::shared_ptr<HeifImage>& image, heif_item_id& itemId)
414 {
415 auto mdcv = GetProperty<HeifMdcvBox>(itemId);
416 auto clli = GetProperty<HeifClliBox>(itemId);
417 if (mdcv == nullptr && clli == nullptr) {
418 return;
419 }
420 DisplayColourVolume displayColourVolume{};
421 ContentLightLevelInfo lightInfo{};
422 uint32_t displaySize = sizeof(DisplayColourVolume);
423 std::vector<uint8_t> displayVec(displaySize);
424 if (mdcv) {
425 displayColourVolume = mdcv->GetColourVolume();
426 if (memcpy_s(displayVec.data(), displaySize, &displayColourVolume, displaySize) != EOK) {
427 displayVec.resize(0);
428 }
429 }
430
431 uint32_t lightInfoSize = sizeof(ContentLightLevelInfo);
432 std::vector<uint8_t> lightInfoVec(lightInfoSize);
433 if (clli) {
434 lightInfo = clli->GetLightLevel();
435 if (memcpy_s(lightInfoVec.data(), lightInfoSize, &lightInfo, lightInfoSize) != EOK) {
436 lightInfoVec.resize(0);
437 }
438 }
439
440 image->SetStaticMetadata(displayVec, lightInfoVec);
441 }
442
ExtractGainmap(const std::vector<heif_item_id> & allItemIds)443 void HeifParser::ExtractGainmap(const std::vector<heif_item_id>& allItemIds)
444 {
445 for (heif_item_id itemId: allItemIds) {
446 // extract Image Item
447 auto infe = GetInfeBox(itemId);
448 if (!infe) {
449 continue;
450 }
451 const std::string& itemType = infe->GetItemType();
452 if (itemType == "it35") {
453 ExtractIT35Metadata(itemId);
454 }
455 if (itemType == "tmap") {
456 ExtractISOMetadata(itemId);
457 ExtractGainmapImage(itemId);
458 }
459 }
460 }
461
ExtractImageProperties(std::shared_ptr<HeifImage> & image)462 void HeifParser::ExtractImageProperties(std::shared_ptr<HeifImage> &image)
463 {
464 heif_item_id itemId = image->GetItemId();
465
466 auto ispe = GetProperty<HeifIspeBox>(itemId);
467 if (ispe) {
468 uint32_t width = ispe->GetWidth();
469 uint32_t height = ispe->GetHeight();
470 image->SetOriginalSize(width, height);
471 }
472
473 auto irot = GetProperty<HeifIrotBox>(itemId);
474 if (irot) {
475 image->SetRotateDegrees(irot->GetRotDegree());
476 }
477
478 auto imir = GetProperty<HeifImirBox>(itemId);
479 if (imir) {
480 image->SetMirrorDirection(imir->GetDirection());
481 }
482
483 auto colr = GetProperty<HeifColrBox>(itemId);
484 if (colr) {
485 auto profile = colr->GetColorProfile();
486 image->SetColorProfile(profile);
487 }
488
489 auto pixi = GetProperty<HeifPixiBox>(itemId);
490 if (pixi && pixi->GetChannelNum() == 1) {
491 image->SetDefaultColorFormat(HeifColorFormat::MONOCHROME);
492 image->SetDefaultPixelFormat(HeifPixelFormat::MONOCHROME);
493 } else {
494 image->SetDefaultColorFormat(HeifColorFormat::YCBCR);
495 image->SetDefaultPixelFormat(HeifPixelFormat::UNDEFINED);
496 }
497
498 auto hvcc = GetProperty<HeifHvccBox>(itemId);
499 if (hvcc) {
500 auto hvccConfig = hvcc->GetConfig();
501 image->SetLumaBitNum(hvccConfig.bitDepthLuma);
502 image->SetChromaBitNum(hvccConfig.bitDepthChroma);
503 image->SetDefaultPixelFormat((HeifPixelFormat) hvccConfig.chromaFormat);
504
505 auto nalArrays = hvcc->GetNalArrays();
506 hvcc->ParserHvccColorRangeFlag(nalArrays);
507 auto spsConfig = hvcc->GetSpsConfig();
508 image->SetColorRangeFlag(static_cast<int>(spsConfig.videoRangeFlag));
509 }
510 ExtractDisplayData(image, itemId);
511 }
512
ExtractDerivedImageProperties()513 void HeifParser::ExtractDerivedImageProperties()
514 {
515 for (auto &pair: images_) {
516 heif_item_id itemId = pair.first;
517 auto infe = GetInfeBox(itemId);
518 if (!infe || (infe->GetItemType() != "grid" && infe->GetItemType() != "iden")) {
519 continue;
520 }
521 auto &image = pair.second;
522 if (!irefBox_) {
523 return;
524 }
525 auto tileItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
526 if (tileItemIds.empty()) {
527 continue;
528 }
529 auto tileImage = GetImage(tileItemIds[0]);
530 if (tileImage == nullptr) {
531 continue;
532 }
533 if (image->GetLumaBitNum() < 0) {
534 image->SetLumaBitNum(tileImage->GetLumaBitNum());
535 }
536 if (image->GetChromaBitNum() < 0) {
537 image->SetChromaBitNum(tileImage->GetChromaBitNum());
538 }
539 if (image->GetDefaultPixelFormat() == HeifPixelFormat::UNDEFINED) {
540 image->SetDefaultPixelFormat(tileImage->GetDefaultPixelFormat());
541 }
542 if (image->GetDefaultColorFormat() == HeifColorFormat::UNDEDEFINED) {
543 image->SetDefaultColorFormat(tileImage->GetDefaultColorFormat());
544 }
545 }
546 }
547
ExtractThumbnailImage(std::shared_ptr<HeifImage> & thumbnailImage,const HeifIrefBox::Reference & ref)548 void HeifParser::ExtractThumbnailImage(std::shared_ptr<HeifImage> &thumbnailImage, const HeifIrefBox::Reference &ref)
549 {
550 std::vector<heif_item_id> toItemIds = ref.toItemIds;
551 if (toItemIds.empty()) {
552 return;
553 }
554 heif_item_id masterItemId = toItemIds[0];
555 if (masterItemId == thumbnailImage->GetItemId()) {
556 return;
557 }
558 auto masterImage = GetImage(masterItemId);
559 if (!masterImage) {
560 return;
561 }
562
563 thumbnailImage->SetThumbnailImage(masterItemId);
564 masterImage->AddThumbnailImage(thumbnailImage);
565 }
566
ExtractAuxImage(std::shared_ptr<HeifImage> & auxImage,const HeifIrefBox::Reference & ref)567 void HeifParser::ExtractAuxImage(std::shared_ptr<HeifImage> &auxImage, const HeifIrefBox::Reference &ref)
568 {
569 std::vector<heif_item_id> toItemIds = ref.toItemIds;
570 if (toItemIds.empty()) {
571 return;
572 }
573 heif_item_id masterItemId = toItemIds[0];
574 heif_item_id auxItemId = auxImage->GetItemId();
575 if (masterItemId == auxItemId) {
576 return;
577 }
578 auto masterImage = GetImage(masterItemId);
579 if (!masterImage) {
580 return;
581 }
582 std::shared_ptr<HeifAuxcBox> auxc = GetProperty<HeifAuxcBox>(auxItemId);
583 if (!auxc) {
584 return;
585 }
586
587 if (auxc->GetAuxType() == HEIF_AUXTTYPE_ID_FRAGMENT_MAP) {
588 ExtractFragmentMetadata(auxItemId);
589 }
590 auxImage->SetAuxImage(masterItemId, auxc->GetAuxType());
591 masterImage->AddAuxImage(auxImage);
592 }
593
ExtractGainmapImage(const heif_item_id & tmapId)594 void HeifParser::ExtractGainmapImage(const heif_item_id& tmapId)
595 {
596 if (!irefBox_) {
597 return;
598 }
599 std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(tmapId);
600 for (const HeifIrefBox::Reference &ref : references) {
601 uint32_t type = ref.box.GetBoxType();
602 if (type != BOX_TYPE_DIMG) {
603 continue;
604 }
605 heif_item_id fromItemId = ref.fromItemId;
606 auto fromItemInfeBox = GetInfeBox(fromItemId);
607 if (fromItemInfeBox == nullptr) {
608 continue;
609 }
610 if (fromItemInfeBox->GetItemType() != "tmap") {
611 return;
612 }
613 std::vector<heif_item_id> toItemIds = ref.toItemIds;
614 const size_t tmapToItemSize = 2;
615 if (toItemIds.size() != tmapToItemSize) {
616 return;
617 }
618 const uint8_t baseIndex = 0;
619 const uint8_t gainmapIndex = 1;
620 heif_item_id baseId = toItemIds[baseIndex];
621 if (baseId != primaryImage_->GetItemId()) {
622 return;
623 }
624 heif_item_id gainmapId = toItemIds[gainmapIndex];
625 auto gainmapImage = GetImage(gainmapId);
626 if (gainmapImage == nullptr) {
627 return;
628 }
629 gainmapImage->SetGainmapMasterImage(baseId);
630 gainmapImage->SetTmapBoxId(tmapId);
631 primaryImage_->AddGainmapImage(gainmapImage);
632 primaryImage_->SetTmapBoxId(tmapId);
633 }
634 }
635
ExtractNonMasterImages()636 void HeifParser::ExtractNonMasterImages()
637 {
638 if (!irefBox_) {
639 return;
640 }
641 for (auto &pair: images_) {
642 auto &image = pair.second;
643 std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(image->GetItemId());
644 for (const HeifIrefBox::Reference &ref: references) {
645 uint32_t type = ref.box.GetBoxType();
646 if (type == BOX_TYPE_THMB) {
647 ExtractThumbnailImage(image, ref);
648 } else if (type == BOX_TYPE_AUXL) {
649 ExtractAuxImage(image, ref);
650 }
651 }
652 }
653 }
654
ExtractMetadata(const std::vector<heif_item_id> & allItemIds)655 void HeifParser::ExtractMetadata(const std::vector<heif_item_id> &allItemIds)
656 {
657 if (!irefBox_) {
658 return;
659 }
660
661 for (heif_item_id metadataItemId: allItemIds) {
662 std::vector<heif_item_id> toItemIds = irefBox_->GetReferences(metadataItemId, BOX_TYPE_CDSC);
663 if (toItemIds.empty()) {
664 continue;
665 }
666 heif_item_id masterImageId = toItemIds[0];
667 if (masterImageId == metadataItemId) {
668 continue;
669 }
670 auto masterImage = GetImage(masterImageId);
671 if (!masterImage) {
672 continue;
673 }
674
675 std::shared_ptr<HeifMetadata> metadata = std::make_shared<HeifMetadata>();
676 metadata->itemId = metadataItemId;
677 metadata->itemType = GetItemType(metadataItemId);
678 metadata->contentType = GetItemContentType(metadataItemId);
679 metadata->itemUriType = GetItemUriType(metadataItemId);
680 heif_error err = GetItemData(metadataItemId, &(metadata->mData));
681 if (err != heif_error_ok) {
682 metadata.reset();
683 continue;
684 }
685 masterImage->AddMetadata(metadata);
686 }
687 }
688
GetImage(heif_item_id itemId)689 std::shared_ptr<HeifImage> HeifParser::GetImage(heif_item_id itemId)
690 {
691 auto iter = images_.find(itemId);
692 if (iter == images_.end()) {
693 return nullptr;
694 }
695 return iter->second;
696 }
697
GetPrimaryImage()698 std::shared_ptr<HeifImage> HeifParser::GetPrimaryImage()
699 {
700 return primaryImage_;
701 }
702
GetGainmapImage()703 std::shared_ptr<HeifImage> HeifParser::GetGainmapImage()
704 {
705 return primaryImage_ != nullptr ? primaryImage_->GetGainmapImage() : nullptr;
706 }
707
GetAuxiliaryMapImage(const std::string type)708 std::shared_ptr<HeifImage> HeifParser::GetAuxiliaryMapImage(const std::string type)
709 {
710 auto auxImages = primaryImage_->GetAuxImages();
711 for (auto image : auxImages) {
712 if (image->GetAuxImageType() == type) {
713 return image;
714 }
715 }
716 return nullptr;
717 }
718
GetTmapImage()719 std::shared_ptr<HeifImage> HeifParser::GetTmapImage()
720 {
721 return tmapImage_;
722 }
723
GetNextItemId() const724 heif_item_id HeifParser::GetNextItemId() const
725 {
726 heif_item_id max_id = 0;
727 for (const auto& infe: infeBoxes_) {
728 max_id = std::max(max_id, infe.second->GetItemId());
729 }
730 return max_id + 1;
731 }
732
AddItem(const char * itemType,bool hidden)733 std::shared_ptr<HeifInfeBox> HeifParser::AddItem(const char *itemType, bool hidden)
734 {
735 heif_item_id newItemId = GetNextItemId();
736 auto newInfe = std::make_shared<HeifInfeBox>(newItemId, itemType, false);
737 newInfe->SetHidden(hidden);
738 infeBoxes_[newItemId] = newInfe;
739 if (iinfBox_ == nullptr) {
740 return nullptr;
741 }
742 iinfBox_->AddChild(newInfe);
743 return newInfe;
744 }
745
AddIspeProperty(heif_item_id itemId,uint32_t width,uint32_t height)746 void HeifParser::AddIspeProperty(heif_item_id itemId, uint32_t width, uint32_t height)
747 {
748 auto ispe = std::make_shared<HeifIspeBox>();
749 ispe->SetDimension(width, height);
750 AddProperty(itemId, ispe, false);
751 }
752
AddProperty(heif_item_id itemId,const std::shared_ptr<HeifBox> & property,bool essential)753 heif_property_id HeifParser::AddProperty(heif_item_id itemId, const std::shared_ptr<HeifBox>& property, bool essential)
754 {
755 int index = ipcoBox_->AddChild(property);
756 ipmaBox_->AddProperty(itemId, PropertyAssociation{essential, uint16_t(index + 1)});
757 return index + 1;
758 }
759
AddPixiProperty(heif_item_id itemId,uint8_t c1,uint8_t c2,uint8_t c3)760 void HeifParser::AddPixiProperty(heif_item_id itemId, uint8_t c1, uint8_t c2, uint8_t c3)
761 {
762 auto pixi = std::make_shared<HeifPixiBox>();
763 pixi->AddBitNum(c1);
764 pixi->AddBitNum(c2);
765 pixi->AddBitNum(c3);
766 AddProperty(itemId, pixi, false);
767 }
768
769
AddHvccProperty(heif_item_id itemId)770 void HeifParser::AddHvccProperty(heif_item_id itemId)
771 {
772 auto hvcC = std::make_shared<HeifHvccBox>();
773 AddProperty(itemId, hvcC, true);
774 }
775
AppendHvccNalData(heif_item_id itemId,const std::vector<uint8_t> & data)776 heif_error HeifParser::AppendHvccNalData(heif_item_id itemId, const std::vector<uint8_t> &data)
777 {
778 auto hvcc = GetProperty<HeifHvccBox>(itemId);
779 if (!hvcc) {
780 return heif_error_no_hvcc;
781 }
782 hvcc->AppendNalData(data);
783 return heif_error_ok;
784 }
785
SetHvccConfig(heif_item_id itemId,const HvccConfig & config)786 heif_error HeifParser::SetHvccConfig(heif_item_id itemId, const HvccConfig &config)
787 {
788 auto hvcc = GetProperty<HeifHvccBox>(itemId);
789 if (!hvcc) {
790 return heif_error_no_hvcc;
791 }
792 hvcc->SetConfig(config);
793 return heif_error_ok;
794 }
795
AppendIlocData(heif_item_id itemId,const std::vector<uint8_t> & data,uint8_t construction_method)796 void HeifParser::AppendIlocData(heif_item_id itemId, const std::vector<uint8_t> &data, uint8_t construction_method)
797 {
798 if (!ilocBox_) {
799 return;
800 }
801 ilocBox_->AppendData(itemId, data, construction_method);
802 }
803
SetPrimaryItemId(heif_item_id itemId)804 void HeifParser::SetPrimaryItemId(heif_item_id itemId)
805 {
806 if (!pitmBox_) {
807 return;
808 }
809 pitmBox_->SetItemId(itemId);
810 }
811
AddReference(heif_item_id fromItemId,uint32_t type,const std::vector<heif_item_id> & toItemIds)812 void HeifParser::AddReference(heif_item_id fromItemId, uint32_t type, const std::vector<heif_item_id> &toItemIds)
813 {
814 if (!irefBox_) {
815 irefBox_ = std::make_shared<HeifIrefBox>();
816 metaBox_->AddChild(irefBox_);
817 }
818 irefBox_->AddReferences(fromItemId, type, toItemIds);
819 }
820
SetAuxcProperty(heif_item_id itemId,const std::string & type)821 void HeifParser::SetAuxcProperty(heif_item_id itemId, const std::string &type)
822 {
823 auto auxC = std::make_shared<HeifAuxcBox>();
824 auxC->SetAuxType(type);
825 AddProperty(itemId, auxC, true);
826 }
827
SetColorProfile(heif_item_id itemId,const std::shared_ptr<const HeifColorProfile> & profile)828 void HeifParser::SetColorProfile(heif_item_id itemId, const std::shared_ptr<const HeifColorProfile> &profile)
829 {
830 auto colr = std::make_shared<HeifColrBox>();
831 colr->SetColorProfile(profile);
832 AddProperty(itemId, colr, false);
833 }
834
CheckExtentData()835 void HeifParser::CheckExtentData()
836 {
837 const std::vector<HeifIlocBox::Item>& items = ilocBox_->GetItems();
838 for (const HeifIlocBox::Item& item: items) {
839 ilocBox_->ReadToExtentData(const_cast<HeifIlocBox::Item &>(item), inputStream_, idatBox_);
840 }
841 }
842
SetPrimaryImage(const std::shared_ptr<HeifImage> & image)843 void HeifParser::SetPrimaryImage(const std::shared_ptr<HeifImage> &image)
844 {
845 if (primaryImage_) {
846 if (primaryImage_->GetItemId() == image->GetItemId()) {
847 return;
848 }
849 primaryImage_->SetPrimaryImage(false);
850 }
851 primaryImage_ = image;
852 image->SetPrimaryImage(true);
853 SetPrimaryItemId(image->GetItemId());
854 }
855
GetExifHeaderOffset(const uint8_t * data,uint32_t size)856 uint32_t HeifParser::GetExifHeaderOffset(const uint8_t *data, uint32_t size)
857 {
858 uint32_t offset = 0;
859 const int endianSize = 4;
860 while (offset + endianSize < (unsigned int) size) {
861 if (!memcmp(data + offset, "MM\0*", endianSize) || !memcmp(data + offset, "II*\0", endianSize)) {
862 return offset;
863 }
864 offset++;
865 }
866 return offset;
867 }
868
SetExifMetadata(const std::shared_ptr<HeifImage> & image,const uint8_t * data,uint32_t size)869 heif_error HeifParser::SetExifMetadata(const std::shared_ptr<HeifImage> &image, const uint8_t *data, uint32_t size)
870 {
871 uint32_t offset = GetExifHeaderOffset(data, size);
872 if (offset >= size) {
873 return heif_invalid_exif_data;
874 }
875
876 std::vector<uint8_t> content;
877 content.resize(size + UINT32_BYTES_NUM);
878 std::string offsetFourcc = code_to_fourcc(offset);
879 for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
880 content[index] = (uint8_t)offsetFourcc[index];
881 }
882 if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != EOK) {
883 return heif_invalid_exif_data;
884 }
885 return SetMetadata(image, content, "Exif", nullptr);
886 }
887
UpdateExifMetadata(const std::shared_ptr<HeifImage> & master_image,const uint8_t * data,uint32_t size,heif_item_id itemId)888 heif_error HeifParser::UpdateExifMetadata(const std::shared_ptr<HeifImage> &master_image, const uint8_t *data,
889 uint32_t size, heif_item_id itemId)
890 {
891 uint32_t offset = GetExifHeaderOffset(data, size);
892 if (offset >= (unsigned int) size) {
893 return heif_invalid_exif_data;
894 }
895
896 std::vector<uint8_t> content;
897 content.resize(size + UINT32_BYTES_NUM);
898 std::string offsetFourcc = code_to_fourcc(offset);
899 for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
900 content[index] = (uint8_t)offsetFourcc[index];
901 }
902
903 if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != 0) {
904 return heif_invalid_exif_data;
905 }
906
907 uint8_t construction_method = GetConstructMethod(itemId);
908
909 return ilocBox_->UpdateData(itemId, content, construction_method);
910 }
911
SetMetadata(const std::shared_ptr<HeifImage> & image,const std::vector<uint8_t> & data,const char * item_type,const char * content_type)912 heif_error HeifParser::SetMetadata(const std::shared_ptr<HeifImage> &image, const std::vector<uint8_t> &data,
913 const char *item_type, const char *content_type)
914 {
915 auto metadataInfe = AddItem(item_type, true);
916 if (content_type != nullptr) {
917 metadataInfe->SetContentType(content_type);
918 }
919
920 heif_item_id metadataItemId = metadataInfe->GetItemId();
921 heif_item_id imageItemId = image->GetItemId();
922 AddReference(metadataItemId, BOX_TYPE_CDSC, {imageItemId});
923
924 // store metadata in mdat
925 AppendIlocData(metadataItemId, data, 0);
926 return heif_error_ok;
927 }
928
GetConstructMethod(const heif_item_id & id)929 uint8_t HeifParser::GetConstructMethod(const heif_item_id &id)
930 {
931 auto items = ilocBox_->GetItems();
932 for (const auto &item: items) {
933 if (item.itemId == id) {
934 return item.constructionMethod;
935 }
936 }
937
938 // CONSTRUCTION_METHOD_FILE_OFFSET 0
939 return 0;
940 }
941
SetTiffOffset()942 void HeifParser::SetTiffOffset()
943 {
944 if (tiffOffset_ != 0) {
945 return;
946 }
947 if (GetPrimaryImage() == nullptr) {
948 return;
949 }
950 auto metadataList = GetPrimaryImage()->GetAllMetadata();
951 heif_item_id exifId = 0;
952 for (auto metadata : metadataList) {
953 if (metadata && metadata->itemType == EXIF_ID) {
954 exifId = metadata->itemId;
955 break;
956 }
957 }
958 if (exifId == 0) {
959 return;
960 }
961
962 if (!HasItemId(exifId)) {
963 return;
964 }
965
966 auto items = ilocBox_->GetItems();
967 const HeifIlocBox::Item *ilocItem = nullptr;
968 for (const auto &item: items) {
969 if (item.itemId == exifId) {
970 ilocItem = &item;
971 break;
972 }
973 }
974 if (!ilocItem) {
975 return;
976 }
977
978 tiffOffset_ = ilocItem->baseOffset;
979 if (!ilocItem->extents.empty()) {
980 tiffOffset_ += ilocItem->extents[0].offset;
981 }
982 }
983 } // namespace ImagePlugin
984 } // namespace OHOS
985