1 // Author: Kirill Gavrilov
2 // Copyright (c) 2015-2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <Image_Texture.hxx>
17 #include <Image_AlienPixMap.hxx>
18 #include <Image_DDSParser.hxx>
19 #include <Image_SupportedFormats.hxx>
20 #include <Message.hxx>
21 #include <Message_Messenger.hxx>
22 #include <OSD_OpenFile.hxx>
24 IMPLEMENT_STANDARD_RTTIEXT(Image_Texture, Standard_Transient)
26 // ================================================================
27 // Function : Image_Texture
29 // ================================================================
30 Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName)
31 : myImagePath (theFileName),
35 // share textures with unique file paths
36 if (!theFileName.IsEmpty())
38 myTextureId = TCollection_AsciiString ("texture://") + theFileName;
42 // ================================================================
43 // Function : Image_Texture
45 // ================================================================
46 Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName,
49 : myImagePath (theFileName),
53 // share textures with unique file paths
54 if (!theFileName.IsEmpty())
57 Sprintf (aBuff, ";%" PRId64 ",%" PRId64, theOffset, theLength);
58 myTextureId = TCollection_AsciiString ("texture://") + theFileName + aBuff;
62 // ================================================================
63 // Function : Image_Texture
65 // ================================================================
66 Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
67 const TCollection_AsciiString& theId)
68 : myBuffer (theBuffer),
74 myTextureId = TCollection_AsciiString ("texturebuf://") + theId;
78 // ================================================================
79 // Function : ReadCompressedImage
81 // ================================================================
82 Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const
84 if (!theSupported->HasCompressed())
86 return Handle(Image_CompressedPixMap)();
89 if (!myBuffer.IsNull())
91 return Image_DDSParser::Load (theSupported, myBuffer, 0);
93 else if (myOffset >= 0)
95 return Image_DDSParser::Load (theSupported, myImagePath, 0, myOffset);
98 TCollection_AsciiString aFilePathLower = myImagePath;
99 aFilePathLower.LowerCase();
100 if (!aFilePathLower.EndsWith (".dds"))
102 // do not waste time on file system access in case of wrong file extension
103 return Handle(Image_CompressedPixMap)();
105 return Image_DDSParser::Load (theSupported, myImagePath, 0);
108 // ================================================================
109 // Function : ReadImage
111 // ================================================================
112 Handle(Image_PixMap) Image_Texture::ReadImage (const Handle(Image_SupportedFormats)& ) const
114 Handle(Image_PixMap) anImage;
115 if (!myBuffer.IsNull())
117 anImage = loadImageBuffer (myBuffer, myTextureId);
119 else if (myOffset >= 0)
121 anImage = loadImageOffset (myImagePath, myOffset, myLength);
125 anImage = loadImageFile (myImagePath);
128 if (anImage.IsNull())
130 return Handle(Image_PixMap)();
135 // ================================================================
136 // Function : loadImageFile
138 // ================================================================
139 Handle(Image_PixMap) Image_Texture::loadImageFile (const TCollection_AsciiString& thePath) const
141 Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
142 if (!anImage->Load (thePath))
144 return Handle(Image_PixMap)();
149 // ================================================================
150 // Function : loadImageBuffer
152 // ================================================================
153 Handle(Image_PixMap) Image_Texture::loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer,
154 const TCollection_AsciiString& theId) const
156 if (theBuffer.IsNull())
158 return Handle(Image_PixMap)();
160 else if (theBuffer->Size() > (Standard_Size )IntegerLast())
162 Message::SendFail (TCollection_AsciiString ("Error: Image file size is too big '") + theId + "'");
163 return Handle(Image_PixMap)();
166 Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
167 if (!anImage->Load (theBuffer->Data(), (int )theBuffer->Size(), theId))
169 return Handle(Image_PixMap)();
174 // ================================================================
175 // Function : loadImageOffset
177 // ================================================================
178 Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiString& thePath,
180 int64_t theLength) const
182 if (theLength > IntegerLast())
184 Message::SendFail (TCollection_AsciiString ("Error: Image file size is too big '") + thePath + "'");
185 return Handle(Image_PixMap)();
189 OSD_OpenStream (aFile, thePath.ToCString(), std::ios::in | std::ios::binary);
192 Message::SendFail (TCollection_AsciiString ("Error: Image file '") + thePath + "' cannot be opened");
193 return Handle(Image_PixMap)();
195 aFile.seekg ((std::streamoff )theOffset, std::ios_base::beg);
198 Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + thePath + "'");
199 return Handle(Image_PixMap)();
202 Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
203 if (!anImage->Load (aFile, thePath))
205 return Handle(Image_PixMap)();
210 // ================================================================
211 // Function : ProbeImageFileFormat
213 // ================================================================
214 TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
216 static const Standard_Size THE_PROBE_SIZE = 20;
217 char aBuffer[THE_PROBE_SIZE];
218 if (!myBuffer.IsNull())
220 memcpy (aBuffer, myBuffer->Data(), myBuffer->Size() < THE_PROBE_SIZE ? myBuffer->Size() : THE_PROBE_SIZE);
224 std::ifstream aFileIn;
225 OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary);
228 Message::SendFail (TCollection_AsciiString ("Error: Unable to open file '") + myImagePath + "'");
233 aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg);
236 Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
241 if (!aFileIn.read (aBuffer, THE_PROBE_SIZE))
243 Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
248 if (memcmp (aBuffer, "\x89" "PNG\r\n" "\x1A" "\n", 8) == 0)
252 else if (memcmp (aBuffer, "\xFF\xD8\xFF", 3) == 0)
256 else if (memcmp (aBuffer, "GIF87a", 6) == 0
257 || memcmp (aBuffer, "GIF89a", 6) == 0)
261 else if (memcmp (aBuffer, "II\x2A\x00", 4) == 0
262 || memcmp (aBuffer, "MM\x00\x2A", 4) == 0)
266 else if (memcmp (aBuffer, "BM", 2) == 0)
270 else if (memcmp (aBuffer, "RIFF", 4) == 0
271 && memcmp (aBuffer + 8, "WEBP", 4) == 0)
275 else if (memcmp (aBuffer, "DDS ", 4) == 0)
282 // ================================================================
283 // Function : WriteImage
285 // ================================================================
286 Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile)
288 Handle(NCollection_Buffer) aBuffer = myBuffer;
289 if (myBuffer.IsNull())
291 std::ifstream aFileIn;
292 OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary);
295 Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!");
296 return Standard_False;
299 Standard_Size aLen = (Standard_Size )myLength;
302 aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg);
305 Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
306 return Standard_False;
311 aFileIn.seekg (0, std::ios_base::end);
312 aLen = (Standard_Size )aFileIn.tellg();
313 aFileIn.seekg (0, std::ios_base::beg);
316 aBuffer = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator(), aLen);
317 if (!aFileIn.read ((char* )aBuffer->ChangeData(), aBuffer->Size()))
319 Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
320 return Standard_False;
324 std::ofstream aFileOut;
325 OSD_OpenStream (aFileOut, theFile.ToCString(), std::ios::out | std::ios::binary | std::ios::trunc);
328 Message::SendFail (TCollection_AsciiString ("Error: Unable to create file '") + theFile + "'");
329 return Standard_False;
332 aFileOut.write ((const char* )aBuffer->Data(), aBuffer->Size());
334 if (!aFileOut.good())
336 Message::SendFail (TCollection_AsciiString ("Error: Unable to write file '") + theFile + "'");
337 return Standard_False;
339 return Standard_True;
342 //=======================================================================
343 //function : DumpJson
345 //=======================================================================
346 void Image_Texture::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
348 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
350 OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myTextureId)
351 OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myImagePath)
353 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myBuffer.get())
355 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myOffset)
356 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLength)