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