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 <Message.hxx>
19 #include <Message_Messenger.hxx>
20 #include <OSD_OpenFile.hxx>
22 IMPLEMENT_STANDARD_RTTIEXT(Image_Texture, Standard_Transient)
24 // ================================================================
25 // Function : Image_Texture
27 // ================================================================
28 Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName)
29 : myImagePath (theFileName),
33 // share textures with unique file paths
34 if (!theFileName.IsEmpty())
36 myTextureId = TCollection_AsciiString ("texture://") + theFileName;
40 // ================================================================
41 // Function : Image_Texture
43 // ================================================================
44 Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName,
47 : myImagePath (theFileName),
51 // share textures with unique file paths
52 if (!theFileName.IsEmpty())
55 Sprintf (aBuff, ";%" PRId64 ",%" PRId64, theOffset, theLength);
56 myTextureId = TCollection_AsciiString ("texture://") + theFileName + aBuff;
60 // ================================================================
61 // Function : Image_Texture
63 // ================================================================
64 Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
65 const TCollection_AsciiString& theId)
66 : myBuffer (theBuffer),
72 myTextureId = TCollection_AsciiString ("texturebuf://") + theId;
76 // ================================================================
77 // Function : ReadImage
79 // ================================================================
80 Handle(Image_PixMap) Image_Texture::ReadImage() const
82 Handle(Image_PixMap) anImage;
83 if (!myBuffer.IsNull())
85 anImage = loadImageBuffer (myBuffer, myTextureId);
87 else if (myOffset >= 0)
89 anImage = loadImageOffset (myImagePath, myOffset, myLength);
93 anImage = loadImageFile (myImagePath);
98 return Handle(Image_PixMap)();
103 // ================================================================
104 // Function : loadImageFile
106 // ================================================================
107 Handle(Image_PixMap) Image_Texture::loadImageFile (const TCollection_AsciiString& thePath) const
109 Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
110 if (!anImage->Load (thePath))
112 return Handle(Image_PixMap)();
117 // ================================================================
118 // Function : loadImageBuffer
120 // ================================================================
121 Handle(Image_PixMap) Image_Texture::loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer,
122 const TCollection_AsciiString& theId) const
124 if (theBuffer.IsNull())
126 return Handle(Image_PixMap)();
128 else if (theBuffer->Size() > (Standard_Size )IntegerLast())
130 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image file size is too big '") + theId + "'.", Message_Fail);
131 return Handle(Image_PixMap)();
134 Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
135 if (!anImage->Load (theBuffer->Data(), (int )theBuffer->Size(), theId))
137 return Handle(Image_PixMap)();
142 // ================================================================
143 // Function : loadImageOffset
145 // ================================================================
146 Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiString& thePath,
148 int64_t theLength) const
150 if (theLength > IntegerLast())
152 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image file size is too big '") + thePath + "'.", Message_Fail);
153 return Handle(Image_PixMap)();
157 OSD_OpenStream (aFile, thePath.ToCString(), std::ios::in | std::ios::binary);
160 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image file '") + thePath + "' cannot be opened.", Message_Fail);
161 return Handle(Image_PixMap)();
163 aFile.seekg ((std::streamoff )theOffset, std::ios_base::beg);
166 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + thePath + "'.", Message_Fail);
167 return Handle(Image_PixMap)();
170 Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
171 if (!anImage->Load (aFile, thePath))
173 return Handle(Image_PixMap)();
178 // ================================================================
179 // Function : ProbeImageFileFormat
181 // ================================================================
182 TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
184 static const int THE_PROBE_SIZE = 20;
185 char aBuffer[THE_PROBE_SIZE];
186 if (!myBuffer.IsNull())
188 memcpy (aBuffer, myBuffer->Data(), myBuffer->Size() < THE_PROBE_SIZE ? myBuffer->Size() : THE_PROBE_SIZE);
192 std::ifstream aFileIn;
193 OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary);
196 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!", Message_Fail);
201 aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg);
204 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'.", Message_Fail);
209 if (!aFileIn.read (aBuffer, THE_PROBE_SIZE))
211 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'", Message_Fail);
216 if (memcmp (aBuffer, "\x89" "PNG\r\n" "\x1A" "\n", 8) == 0)
220 else if (memcmp (aBuffer, "\xFF\xD8\xFF", 3) == 0)
224 else if (memcmp (aBuffer, "GIF87a", 6) == 0
225 || memcmp (aBuffer, "GIF89a", 6) == 0)
229 else if (memcmp (aBuffer, "II\x2A\x00", 4) == 0
230 || memcmp (aBuffer, "MM\x00\x2A", 4) == 0)
234 else if (memcmp (aBuffer, "BM", 2) == 0)
238 else if (memcmp (aBuffer, "RIFF", 4) == 0
239 && memcmp (aBuffer + 8, "WEBP", 4) == 0)
246 // ================================================================
247 // Function : WriteImage
249 // ================================================================
250 Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile)
252 Handle(NCollection_Buffer) aBuffer = myBuffer;
253 if (myBuffer.IsNull())
255 std::ifstream aFileIn;
256 OSD_OpenStream (aFileIn, myImagePath.ToCString(), std::ios::in | std::ios::binary);
259 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!", Message_Fail);
260 return Standard_False;
263 Standard_Size aLen = (Standard_Size )myLength;
266 aFileIn.seekg ((std::streamoff )myOffset, std::ios_base::beg);
269 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'.", Message_Fail);
270 return Standard_False;
275 aFileIn.seekg (0, std::ios_base::end);
276 aLen = (Standard_Size )aFileIn.tellg();
277 aFileIn.seekg (0, std::ios_base::beg);
280 aBuffer = new NCollection_Buffer (NCollection_BaseAllocator::CommonBaseAllocator(), aLen);
281 if (!aFileIn.read ((char* )aBuffer->ChangeData(), aBuffer->Size()))
283 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'", Message_Fail);
284 return Standard_False;
288 std::ofstream aFileOut;
289 OSD_OpenStream (aFileOut, theFile.ToCString(), std::ios::out | std::ios::binary | std::ios::trunc);
292 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to create file ") + theFile + "!", Message_Fail);
293 return Standard_False;
296 aFileOut.write ((const char* )aBuffer->Data(), aBuffer->Size());
298 if (!aFileOut.good())
300 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: Unable to write file ") + theFile + "!", Message_Fail);
301 return Standard_False;
303 return Standard_True;