1 /* Copyright (c) MediaArea.net SARL. All Rights Reserved.
2 *
3 * Use of this source code is governed by a BSD-style license that can
4 * be found in the License.html file in the root of the source tree.
5 */
6
7 //---------------------------------------------------------------------------
8 // Pre-compilation
9 #include "MediaInfo/PreComp.h"
10 #ifdef __BORLANDC__
11 #pragma hdrstop
12 #endif
13 //---------------------------------------------------------------------------
14
15 //---------------------------------------------------------------------------
16 #include "MediaInfo/Setup.h"
17 //---------------------------------------------------------------------------
18
19 //---------------------------------------------------------------------------
20 #if defined(MEDIAINFO_NISO_YES)
21 //---------------------------------------------------------------------------
22
23 //---------------------------------------------------------------------------
24 #include "MediaInfo/Export/Export_Niso.h"
25 #include "MediaInfo/File__Analyse_Automatic.h"
26 #include "MediaInfo/OutputHelpers.h"
27 #include <ctime>
28 #include <cmath>
29
30 using namespace std;
31
32 //---------------------------------------------------------------------------
33
34 namespace MediaInfoLib
35 {
36 //---------------------------------------------------------------------------
37 extern MediaInfo_Config Config;
38 //---------------------------------------------------------------------------
39
40 //***************************************************************************
41 // Constructor/Destructor
42 //***************************************************************************
43
44 //---------------------------------------------------------------------------
Export_Niso()45 Export_Niso::Export_Niso ()
46 {
47 }
48
49 //---------------------------------------------------------------------------
~Export_Niso()50 Export_Niso::~Export_Niso ()
51 {
52 }
53
54 //***************************************************************************
55 // Helpers
56 //***************************************************************************
57
58 //---------------------------------------------------------------------------
Transform_Header()59 Node* Transform_Header()
60 {
61 //Root node
62 Node* Node_Header=new Node("mix:mix");
63 Node_Header->Add_Attribute("xmlns:mix", "http://www.loc.gov/mix/v20");
64 Node_Header->Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
65 Node_Header->Add_Attribute("xsi:schemaLocation", "http://www.loc.gov/mix/v20 http://www.loc.gov/standards/mix/mix20/mix20.xsd");
66
67 return Node_Header;
68 }
69
70 //---------------------------------------------------------------------------
ComputeSamplingFrequency(Node * Parent,Ztring & Value)71 void ComputeSamplingFrequency(Node* Parent, Ztring& Value)
72 {
73 while (Value.size()>0 && Value[Value.size()-1]==__T('0'))
74 Value.resize(Value.size()-1);
75 if (Value.size()>0 && Value[Value.size()-1]==__T('.'))
76 Value.resize(Value.size()-1);
77
78 int32u SamplingFrequencyDenominator=0;
79 size_t Dot=Value.find(__T('.'));
80 if (Dot!=std::string::npos)
81 {
82 Value.erase(Dot, 1);
83 SamplingFrequencyDenominator=(int32u)std::pow((double)10, (double)Value.size()-Dot);
84 }
85
86 Parent->Add_Child("mix:numerator", Value);
87
88 if (SamplingFrequencyDenominator)
89 Parent->Add_Child("mix:denominator", Ztring().From_Number(SamplingFrequencyDenominator));
90 }
91
92 //***************************************************************************
93 // Input
94 //***************************************************************************
95
96 //---------------------------------------------------------------------------
Transform(MediaInfo_Internal & MI,Ztring ExternalMetadataValues,Ztring ExternalMetaDataConfig)97 Ztring Export_Niso::Transform(MediaInfo_Internal &MI, Ztring ExternalMetadataValues, Ztring ExternalMetaDataConfig)
98 {
99 bool UseExternalMetaData=(!ExternalMetaDataConfig.empty() && !ExternalMetadataValues.empty());
100
101 Ztring ToReturn;
102 for (size_t Pos=0; Pos<MI.Count_Get(Stream_Image); Pos++)
103 {
104 Node* Node_Root=Transform_Header();
105 Node* Node_Extension=NULL;
106
107 //Use external metadata
108 if (UseExternalMetaData)
109 {
110 Ztring FileName;
111 if (!MI.Get(Stream_General, 0, General_FileName).empty())
112 FileName=MI.Get(Stream_General, 0, General_FileName);
113 if (!MI.Get(Stream_General, 0, General_FileExtension).empty())
114 FileName+=__T('.')+MI.Get(Stream_General, 0, General_FileExtension);
115 if (FileName.empty())
116 {
117 MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0, "File name not found in external metadata file");
118 delete Node_Root;
119 return Ztring();
120 }
121
122 Node_Extension= new Node("mix:Extension");
123 Node* Node_CoreMain=NULL;
124
125 if (ExternalMetaDataConfig.find(__T("<ebucore:ebuCoreMain"))<100)
126 {
127 //TODO: merge with EBUCore code
128 //Current date/time is ISO format
129 time_t Seconds=time(NULL);
130 Ztring DateTime; DateTime.Date_From_Seconds_1970((int32u)Seconds);
131 if (DateTime.size() >= 4 && DateTime[0] == __T('U') && DateTime[1] == __T('T') && DateTime[2] == __T('C') && DateTime[3] == __T(' '))
132 {
133 DateTime.erase(0, 4);
134 DateTime += __T('Z');
135 }
136 Ztring Date=DateTime.substr(0, 10);
137 Ztring Time=DateTime.substr(11);
138
139 Node_CoreMain=Node_Extension->Add_Child("ebucore:ebuCoreMain");
140 Node_CoreMain->Add_Attribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
141 {
142 Node_CoreMain->Add_Attribute("xmlns:ebucore", "urn:ebu:metadata-schema:ebucore");
143 Node_CoreMain->Add_Attribute("xmlns:xalan", "http://xml.apache.org/xalan");
144 Node_CoreMain->Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
145 Node_CoreMain->Add_Attribute("xsi:schemaLocation", string("urn:ebu:metadata-schema:ebucore http") + string(MediaInfoLib::Config.Https_Get() ? "s" : "") + "://www.ebu.ch/metadata/schemas/EBUCore/20171009/ebucore.xsd");
146 Node_CoreMain->Add_Attribute("version", "1.8");
147 Node_CoreMain->Add_Attribute("writingLibraryName", "MediaInfoLib");
148 Node_CoreMain->Add_Attribute("writingLibraryVersion", MediaInfoLib::Config.Info_Version_Get().SubString(__T(" - v"), Ztring()));
149 }
150 Node_CoreMain->Add_Attribute("dateLastModified", Date);
151 Node_CoreMain->Add_Attribute("timeLastModified", Time);
152 }
153
154 if (!ExternalMetadata(FileName, ExternalMetadataValues, ExternalMetaDataConfig,
155 ZtringList(__T("mix:Extension;ebucore:ebuCoreMain")), __T(""),
156 Node_CoreMain?Node_CoreMain:Node_Extension, NULL))
157 {
158 delete Node_Root;
159 return Ztring();
160 }
161 }
162
163 //BasicDigitalObjectInformation
164 Node* Node_BasicDigitalObjectInformation=Node_Root->Add_Child("mix:BasicDigitalObjectInformation");
165 Node* Node_ObjectIdentifier=Node_BasicDigitalObjectInformation->Add_Child("mix:ObjectIdentifier");
166
167 Node_ObjectIdentifier->Add_Child("mix:objectIdentifierType", std::string("MediaInfo"));
168 Node_ObjectIdentifier->Add_Child_IfNotEmpty(MI, Stream_General, 0, General_CompleteName, "mix:objectIdentifierValue");
169
170 if (MI.Get(Stream_General, 0, General_FileSize).To_int64u()>0)
171 Node_BasicDigitalObjectInformation->Add_Child("mix:fileSize", MI.Get(Stream_General, 0, General_FileSize));
172
173 if (MI.Get(Stream_General, 0, General_Format)==__T("TIFF"))
174 Node_BasicDigitalObjectInformation->Add_Child("mix:FormatDesignation")->Add_Child("mix:formatName", std::string("image/tiff"));
175
176 std::string byteOrder=MI.Get(Stream_Image, Pos, Image_Format_Settings_Endianness).To_UTF8();
177 if (!byteOrder.empty())
178 Node_BasicDigitalObjectInformation->Add_Child("mix:byteOrder", byteOrder=="Little"?std::string("little endian"):(byteOrder=="Big"?std::string("big endian"): byteOrder));
179
180 std::string CompressionScheme=MI.Get(Stream_Image, Pos, Image_Format).To_UTF8();
181 if (!CompressionScheme.empty())
182 Node_BasicDigitalObjectInformation->Add_Child("mix:Compression")->Add_Child("mix:compressionScheme", CompressionScheme=="Raw"?std::string("Uncompressed"):CompressionScheme);
183
184 if (!MI.Get(Stream_Image, Pos, Image_Width).empty() ||
185 !MI.Get(Stream_Image, Pos, Image_Height).empty() ||
186 !MI.Get(Stream_Image, Pos, Image_ColorSpace).empty())
187 {
188 Node* Node_BasicImageCharacteristics=Node_Root->Add_Child("mix:BasicImageInformation")->Add_Child("mix:BasicImageCharacteristics");
189
190 Node_BasicImageCharacteristics->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_Width, "mix:imageWidth");
191 Node_BasicImageCharacteristics->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_Height, "mix:imageHeight");
192
193 //ReferenceBlackWhite
194 std::string ColorSpace=MI.Get(Stream_Image, Pos, Image_ColorSpace).To_UTF8();
195 if (!ColorSpace.empty())
196 {
197 Node* Node_PhotometricInterpretation=Node_BasicImageCharacteristics->Add_Child("mix:PhotometricInterpretation");
198 Node_PhotometricInterpretation->Add_Child("mix:colorSpace", ColorSpace);
199
200 Node* ReferenceBlackWhite=Node_PhotometricInterpretation->Add_Child("mix:ReferenceBlackWhite");
201 for (size_t i=0; i < ColorSpace.size(); i++)
202 {
203 Node* Component=ReferenceBlackWhite->Add_Child("mix:Component");
204 Component->Add_Child("mix:componentPhotometricInterpretation", string(1, ColorSpace[i]));
205 Node* footroom=Component->Add_Child("mix:footroom");
206 footroom->Add_Child("mix:numerator", Ztring::ToZtring(0));
207 int8u BitDepth=MI.Get(Stream_Image, Pos, Image_BitDepth).To_int8u();
208 if (BitDepth)
209 {
210 Node* headroom=Component->Add_Child("mix:headroom");
211 headroom->Add_Child("mix:numerator", Ztring::ToZtring((1<<BitDepth)-1));
212 }
213 }
214 }
215 }
216
217 //ImageCaptureMetadata
218 std::string Make=MI.Get(Stream_General, 0, General_Encoded_Application_CompanyName).To_UTF8();
219 std::string Model=MI.Get(Stream_General, 0, General_Encoded_Library_Name).To_UTF8();
220 std::string Software=MI.Get(Stream_General, 0, General_Encoded_Application_Name).To_UTF8();
221 std::string Encoded_Date=MI.Get(Stream_Image, Pos, Image_Encoded_Date).To_UTF8();
222 if (!Make.empty() || !Model.empty() || !Software.empty() || !Encoded_Date.empty())
223 {
224 Node* Node_ImageCaptureMetadata=Node_Root->Add_Child("mix:ImageCaptureMetadata");
225
226 if (!Encoded_Date.empty())
227 {
228 if (Encoded_Date.size()>4 && Encoded_Date[4]==':')
229 Encoded_Date[4]='-';
230 if (Encoded_Date.size()>7 && Encoded_Date[7]==':')
231 Encoded_Date[7]='-';
232 if (Encoded_Date.size()>10 && Encoded_Date[10]==' ')
233 Encoded_Date[10]='T';
234 Node* Node_GeneralCaptureInformation=Node_ImageCaptureMetadata->Add_Child("mix:GeneralCaptureInformation");
235 Node_GeneralCaptureInformation->Add_Child("mix:dateTimeCreated", Encoded_Date);
236 }
237
238 if (!Make.empty() || !Model.empty() || !Software.empty() )
239 {
240 Node* Node_ScannerCapture=Node_ImageCaptureMetadata->Add_Child("mix:ScannerCapture");
241 if (!Make.empty())
242 Node_ScannerCapture->Add_Child("mix:scannerManufacturer", Make);
243 if (!Model.empty())
244 Node_ScannerCapture->Add_Child("mix:ScannerModel")->Add_Child("mix:scannerModelName", Model);
245 if (!Software.empty())
246 Node_ScannerCapture->Add_Child("mix:ScanningSystemSoftware")->Add_Child("mix:scanningSoftwareName", Software);
247 }
248 }
249
250 if (!MI.Get(Stream_Image, Pos, __T("Density_X")).empty() ||
251 !MI.Get(Stream_Image, Pos, __T("Density_Y")).empty() ||
252 !MI.Get(Stream_Image, Pos, Image_ColorSpace).empty())
253 {
254 Node* Node_ImageAssessmentMetadata=Node_Root->Add_Child("mix:ImageAssessmentMetadata");
255
256 //SpatialMetrics
257 string samplingFrequencyUnit=MI.Get(Stream_Image, Pos, __T("Density_Unit")).To_UTF8();
258 Ztring xSamplingFrequency=MI.Get(Stream_Image, Pos, __T("Density_X"));
259 Ztring ySamplingFrequency=MI.Get(Stream_Image, Pos, __T("Density_Y"));
260 if (!xSamplingFrequency.empty() || !ySamplingFrequency.empty())
261 {
262 Node* Node_SpatialMetrics=Node_ImageAssessmentMetadata->Add_Child("mix:SpatialMetrics");
263
264 if (samplingFrequencyUnit.empty())
265 Node_SpatialMetrics->Add_Child("mix:samplingFrequencyUnit", string("no absolute unit of measurement"));
266 else if (samplingFrequencyUnit=="dpi")
267 Node_SpatialMetrics->Add_Child("mix:samplingFrequencyUnit", string("in."));
268 else if (samplingFrequencyUnit=="dpcm")
269 Node_SpatialMetrics->Add_Child("mix:samplingFrequencyUnit", string("cm"));
270
271 if (!xSamplingFrequency.empty())
272 ComputeSamplingFrequency(Node_SpatialMetrics->Add_Child("mix:xSamplingFrequency"), xSamplingFrequency);
273 if (!ySamplingFrequency.empty())
274 ComputeSamplingFrequency(Node_SpatialMetrics->Add_Child("mix:ySamplingFrequency"), ySamplingFrequency);
275 }
276
277 size_t SamplesPerPixel=MI.Get(Stream_Image, Pos, Image_ColorSpace).length();
278 if (SamplesPerPixel)
279 {
280 Node* Node_ImageColorEncoding=Node_ImageAssessmentMetadata->Add_Child("mix:ImageColorEncoding");
281
282 Node* Node_BitsPerSample=new Node("mix:BitsPerSample");
283 for (size_t Pos2=0; Pos2<SamplesPerPixel; ++Pos2)
284 Node_BitsPerSample->Add_Child_IfNotEmpty(MI, Stream_Image, Pos, Image_BitDepth, "mix:bitsPerSampleValue");
285
286 if (!Node_BitsPerSample->Childs.empty())
287 {
288 Node_BitsPerSample->Add_Child("mix:bitsPerSampleUnit", std::string("integer"));
289 Node_ImageColorEncoding->Childs.push_back(Node_BitsPerSample);
290 }
291 else
292 delete Node_BitsPerSample;
293
294 Node_ImageColorEncoding->Add_Child("mix:samplesPerPixel", Ztring().From_Number(SamplesPerPixel).To_UTF8());
295 }
296 }
297
298 if (Node_Extension)
299 Node_Root->Childs.push_back(Node_Extension);
300
301 ToReturn+=Ztring().From_UTF8(To_XML(*Node_Root, 0, true, true).c_str());
302 }
303
304 if (ToReturn.empty())
305 ToReturn+=Ztring().From_UTF8(To_XML(*Transform_Header(), 0, true, true).c_str())+=__T("\n");
306
307 //Carriage return
308 if (MediaInfoLib::Config.LineSeparator_Get()!=__T("\n"))
309 ToReturn.FindAndReplace(__T("\n"), MediaInfoLib::Config.LineSeparator_Get(), 0, Ztring_Recursive);
310
311 return ToReturn;
312 }
313
314 //***************************************************************************
315 //
316 //***************************************************************************
317
318 } //NameSpace
319
320 #endif
321