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 "buffer_metadata_stream.h"
17 #include "heif_error.h"
18 #include "heif_exif_metadata_accessor.h"
19 #include "heif_image.h"
20 #include "heif_type.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 "HeifExifMetadataAccessor"
30
31 namespace OHOS {
32 namespace Media {
33 using namespace ImagePlugin;
34
35 const auto EXIF_ID = "Exif\0\0";
36
HeifExifMetadataAccessor(std::shared_ptr<MetadataStream> & stream)37 HeifExifMetadataAccessor::HeifExifMetadataAccessor(std::shared_ptr<MetadataStream> &stream)
38 : AbstractExifMetadataAccessor(stream)
39 {}
40
~HeifExifMetadataAccessor()41 HeifExifMetadataAccessor::~HeifExifMetadataAccessor() {}
42
Read()43 uint32_t HeifExifMetadataAccessor::Read()
44 {
45 std::shared_ptr<HeifParser> parser;
46 heif_error parseRet = HeifParser::MakeFromMemory(imageStream_->GetAddr(), imageStream_->GetSize(), false, &parser);
47 if (parseRet != heif_error_ok) {
48 IMAGE_LOGE("The image source data is incorrect.");
49 return ERR_IMAGE_SOURCE_DATA;
50 }
51
52 DataBuf dataBuf;
53 if (!GetExifItemData(parser, dataBuf)) {
54 IMAGE_LOGD("The EXIF value is invalid.");
55 return ERR_IMAGE_SOURCE_DATA;
56 }
57
58 size_t byteOrderPos;
59 if (!CheckTiffPos(const_cast<byte *>(dataBuf.CData()), dataBuf.Size(), byteOrderPos)) {
60 IMAGE_LOGE("Failed to parse Exif metadata: cannot find tiff byte order");
61 return ERR_IMAGE_SOURCE_DATA;
62 }
63 ExifData *exifData = nullptr;
64 TiffParser::Decode(dataBuf.CData(byteOrderPos), dataBuf.Size() - byteOrderPos, &exifData);
65 if (exifData == nullptr) {
66 IMAGE_LOGE("Decode tiffBuf error.");
67 return ERR_EXIF_DECODE_FAILED;
68 }
69 tiffOffset_ = tiffOffset_ + static_cast<long>(byteOrderPos);
70 exifMetadata_ = std::make_shared<ExifMetadata>(exifData);
71 return SUCCESS;
72 }
73
ReadBlob(DataBuf & blob)74 bool HeifExifMetadataAccessor::ReadBlob(DataBuf &blob)
75 {
76 return false;
77 }
78
Write()79 uint32_t HeifExifMetadataAccessor::Write()
80 {
81 auto exfiMetadata = this->Get();
82 if (exfiMetadata == nullptr) {
83 IMAGE_LOGE("Heif metadata are not supported.");
84 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
85 }
86
87 ExifData *exifData = exfiMetadata->GetExifData();
88 if (exifData == nullptr) {
89 IMAGE_LOGE("Heif Exif format are not supported.");
90 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
91 }
92
93 uint_8 *dataBlob = nullptr;
94 uint32_t size = 0;
95 TiffParser::Encode(&dataBlob, size, exifData);
96
97 if (dataBlob == nullptr) {
98 IMAGE_LOGE("Failed to encode exif matatdata.");
99 return ERR_MEDIA_WRITE_PARCEL_FAIL;
100 }
101
102 size_t byteOrderPos;
103 DataBuf dataBuf(dataBlob, size);
104 if (!CheckTiffPos(const_cast<byte *>(dataBuf.CData()), dataBuf.Size(), byteOrderPos)) {
105 return ERR_MEDIA_WRITE_PARCEL_FAIL;
106 }
107 if (dataBlob != nullptr) {
108 free(dataBlob);
109 dataBlob = nullptr;
110 }
111 return WriteMetadata(dataBuf);
112 }
113
WriteMetadata(DataBuf & dataBuf)114 uint32_t HeifExifMetadataAccessor::WriteMetadata(DataBuf &dataBuf)
115 {
116 std::shared_ptr<ImagePlugin::HeifParser> parser;
117 heif_error parseRet = HeifParser::MakeFromMemory(imageStream_->GetAddr(), imageStream_->GetSize(), false, &parser);
118 if (parseRet != heif_error_ok) {
119 IMAGE_LOGE("The EXIF data failed to parser.");
120 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
121 }
122
123 auto image = parser->GetPrimaryImage();
124 ImagePlugin::heif_item_id exifItemId;
125
126 if (GetExifItemIdByHeifParser(parser, exifItemId)) {
127 if (parser->UpdateExifMetadata(image, dataBuf.CData(), dataBuf.Size(), exifItemId)
128 != heif_error::heif_error_ok) {
129 IMAGE_LOGE("The EXIF data failed to update values.");
130 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
131 }
132 } else {
133 if (parser->SetExifMetadata(image, dataBuf.CData(), dataBuf.Size())
134 != heif_error::heif_error_ok) {
135 IMAGE_LOGE("The EXIF data failed to set values.");
136 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
137 }
138 }
139
140 HeifStreamWriter writer;
141 parser->Write(writer);
142 size_t dataSize = writer.GetDataSize();
143 if (dataSize == 0) {
144 IMAGE_LOGE("The EXIF data failed to be written to the file.");
145 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
146 }
147
148 const uint8_t *buf = writer.GetData().data();
149 if (buf == nullptr) {
150 return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
151 }
152
153 BufferMetadataStream tmpBufStream;
154 tmpBufStream.Write(const_cast<uint8_t *>(buf), dataSize);
155 imageStream_->Seek(0, SeekPos::BEGIN);
156 imageStream_->CopyFrom(tmpBufStream);
157 return SUCCESS;
158 }
159
WriteBlob(DataBuf & blob)160 uint32_t HeifExifMetadataAccessor::WriteBlob(DataBuf &blob)
161 {
162 return SUCCESS;
163 }
164
CheckTiffPos(byte * buff,size_t size,size_t & byteOrderPos)165 bool HeifExifMetadataAccessor::CheckTiffPos(byte *buff, size_t size, size_t &byteOrderPos)
166 {
167 if (buff == nullptr) {
168 return false;
169 }
170
171 // find the byte order "II 0x2a00" "MM 0x002a"
172 byteOrderPos = TiffParser::FindTiffPos(buff, size);
173 if (byteOrderPos == std::numeric_limits<size_t>::max()) {
174 return false;
175 }
176 return true;
177 }
178
GetExifItemData(std::shared_ptr<HeifParser> & parser,DataBuf & dataBuf)179 bool HeifExifMetadataAccessor::GetExifItemData(std::shared_ptr<HeifParser> &parser, DataBuf &dataBuf)
180 {
181 ImagePlugin::heif_item_id exifItemId = 0xffff;
182 if (!GetExifItemIdByHeifParser(parser, exifItemId)) {
183 return false;
184 }
185
186 std::vector<uint8_t> item;
187 if (parser->GetItemData(exifItemId, &item) != heif_error::heif_error_ok) {
188 return false;
189 }
190 tiffOffset_ = parser->GetTiffOffset();
191 dataBuf = DataBuf(item.data(), item.size());
192 return true;
193 }
194
GetExifItemIdByHeifParser(std::shared_ptr<ImagePlugin::HeifParser> & parser,ImagePlugin::heif_item_id & exifItemId)195 bool HeifExifMetadataAccessor::GetExifItemIdByHeifParser(std::shared_ptr<ImagePlugin::HeifParser> &parser,
196 ImagePlugin::heif_item_id &exifItemId)
197 {
198 auto image = parser->GetPrimaryImage();
199 const std::vector<std::shared_ptr<HeifMetadata>> metadata = image->GetAllMetadata();
200 for (auto meta: metadata) {
201 if (meta == nullptr) {
202 continue;
203 }
204
205 if (meta->itemType == EXIF_ID) {
206 exifItemId = meta->itemId;
207 return true;
208 }
209 }
210 return false;
211 }
212 } // namespace Media
213 } // namespace OHOS
214