1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-21 10:13:43 +03:00
occt/src/Image/Image_Texture.cxx
kgv 65acdce54c 0032352: Coding Rules - clean up code from compatibility hacks with pre-C++11 compilers
Removed usage of std::auto_ptr.
opencascade::std workarounds for VS2008 have been dropped, when possible.
OCCT_NO_RVALUE_REFERENCE workaround for VS2008 has been removed.
2021-12-03 17:56:37 +03:00

423 lines
13 KiB
C++

// Author: Kirill Gavrilov
// Copyright (c) 2015-2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Image_Texture.hxx>
#include <Image_AlienPixMap.hxx>
#include <Image_DDSParser.hxx>
#include <Image_SupportedFormats.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <OSD_FileSystem.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Image_Texture, Standard_Transient)
// ================================================================
// Function : Image_Texture
// Purpose :
// ================================================================
Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName)
: myImagePath (theFileName),
myOffset (-1),
myLength (-1)
{
// share textures with unique file paths
if (!theFileName.IsEmpty())
{
myTextureId = TCollection_AsciiString ("texture://") + theFileName;
}
}
// ================================================================
// Function : Image_Texture
// Purpose :
// ================================================================
Image_Texture::Image_Texture (const TCollection_AsciiString& theFileName,
int64_t theOffset,
int64_t theLength)
: myImagePath (theFileName),
myOffset (theOffset),
myLength (theLength)
{
// share textures with unique file paths
if (!theFileName.IsEmpty())
{
char aBuff[60];
Sprintf (aBuff, ";%" PRId64 ",%" PRId64, theOffset, theLength);
myTextureId = TCollection_AsciiString ("texture://") + theFileName + aBuff;
}
}
// ================================================================
// Function : Image_Texture
// Purpose :
// ================================================================
Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId)
: myBuffer (theBuffer),
myOffset (-1),
myLength (-1)
{
if (!theId.IsEmpty())
{
myTextureId = TCollection_AsciiString ("texturebuf://") + theId;
}
}
// ================================================================
// Function : ReadCompressedImage
// Purpose :
// ================================================================
Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const
{
if (!theSupported->HasCompressed())
{
return Handle(Image_CompressedPixMap)();
}
if (!myBuffer.IsNull())
{
return Image_DDSParser::Load (theSupported, myBuffer, 0);
}
else if (myOffset >= 0)
{
return Image_DDSParser::Load (theSupported, myImagePath, 0, myOffset);
}
TCollection_AsciiString aFilePathLower = myImagePath;
aFilePathLower.LowerCase();
if (!aFilePathLower.EndsWith (".dds"))
{
// do not waste time on file system access in case of wrong file extension
return Handle(Image_CompressedPixMap)();
}
return Image_DDSParser::Load (theSupported, myImagePath, 0);
}
// ================================================================
// Function : ReadImage
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::ReadImage (const Handle(Image_SupportedFormats)& ) const
{
Handle(Image_PixMap) anImage;
if (!myBuffer.IsNull())
{
anImage = loadImageBuffer (myBuffer, myTextureId);
}
else if (myOffset >= 0)
{
anImage = loadImageOffset (myImagePath, myOffset, myLength);
}
else
{
anImage = loadImageFile (myImagePath);
}
if (anImage.IsNull())
{
return Handle(Image_PixMap)();
}
return anImage;
}
// ================================================================
// Function : loadImageFile
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::loadImageFile (const TCollection_AsciiString& thePath) const
{
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (!anImage->Load (thePath))
{
return Handle(Image_PixMap)();
}
return anImage;
}
// ================================================================
// Function : loadImageBuffer
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::loadImageBuffer (const Handle(NCollection_Buffer)& theBuffer,
const TCollection_AsciiString& theId) const
{
if (theBuffer.IsNull())
{
return Handle(Image_PixMap)();
}
else if (theBuffer->Size() > (Standard_Size )IntegerLast())
{
Message::SendFail (TCollection_AsciiString ("Error: Image file size is too big '") + theId + "'");
return Handle(Image_PixMap)();
}
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (!anImage->Load (theBuffer->Data(), (int )theBuffer->Size(), theId))
{
return Handle(Image_PixMap)();
}
return anImage;
}
// ================================================================
// Function : loadImageOffset
// Purpose :
// ================================================================
Handle(Image_PixMap) Image_Texture::loadImageOffset (const TCollection_AsciiString& thePath,
int64_t theOffset,
int64_t theLength) const
{
if (theLength > IntegerLast())
{
Message::SendFail (TCollection_AsciiString ("Error: Image file size is too big '") + thePath + "'");
return Handle(Image_PixMap)();
}
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFile = aFileSystem->OpenIStream (thePath, std::ios::in | std::ios::binary);
if (aFile.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Image file '") + thePath + "' cannot be opened");
return Handle(Image_PixMap)();
}
aFile->seekg ((std::streamoff )theOffset, std::ios_base::beg);
if (!aFile->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + thePath + "'");
return Handle(Image_PixMap)();
}
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (!anImage->Load (*aFile, thePath))
{
return Handle(Image_PixMap)();
}
return anImage;
}
// ================================================================
// Function : MimeType
// Purpose :
// ================================================================
TCollection_AsciiString Image_Texture::MimeType() const
{
const TCollection_AsciiString aType = ProbeImageFileFormat();
if (aType == "jpg")
{
return "image/jpeg";
}
else if (aType == "png"
|| aType == "bmp"
|| aType == "webp"
|| aType == "gif"
|| aType == "tiff")
{
return TCollection_AsciiString ("image/") + aType;
}
else if (aType == "dds")
{
return "image/vnd-ms.dds";
}
else if (!aType.IsEmpty())
{
return TCollection_AsciiString ("image/x-") + aType;
}
return TCollection_AsciiString();
}
// ================================================================
// Function : ProbeImageFileFormat
// Purpose :
// ================================================================
TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
{
static const Standard_Size THE_PROBE_SIZE = 20;
char aBuffer[THE_PROBE_SIZE];
if (!myBuffer.IsNull())
{
memcpy (aBuffer, myBuffer->Data(), myBuffer->Size() < THE_PROBE_SIZE ? myBuffer->Size() : THE_PROBE_SIZE);
}
else
{
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFileIn = aFileSystem->OpenIStream (myImagePath, std::ios::in | std::ios::binary);
if (aFileIn.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to open file '") + myImagePath + "'");
return false;
}
if (myOffset >= 0)
{
aFileIn->seekg ((std::streamoff )myOffset, std::ios_base::beg);
if (!aFileIn->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
return false;
}
}
if (!aFileIn->read (aBuffer, THE_PROBE_SIZE))
{
Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
return false;
}
}
if (memcmp (aBuffer, "\x89" "PNG\r\n" "\x1A" "\n", 8) == 0)
{
return "png";
}
else if (memcmp (aBuffer, "\xFF\xD8\xFF", 3) == 0)
{
return "jpg";
}
else if (memcmp (aBuffer, "GIF87a", 6) == 0
|| memcmp (aBuffer, "GIF89a", 6) == 0)
{
return "gif";
}
else if (memcmp (aBuffer, "II\x2A\x00", 4) == 0
|| memcmp (aBuffer, "MM\x00\x2A", 4) == 0)
{
return "tiff";
}
else if (memcmp (aBuffer, "BM", 2) == 0)
{
return "bmp";
}
else if (memcmp (aBuffer, "RIFF", 4) == 0
&& memcmp (aBuffer + 8, "WEBP", 4) == 0)
{
return "webp";
}
else if (memcmp (aBuffer, "DDS ", 4) == 0)
{
return "dds";
}
return "";
}
// ================================================================
// Function : WriteImage
// Purpose :
// ================================================================
Standard_Boolean Image_Texture::WriteImage (const TCollection_AsciiString& theFile)
{
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::ostream> aFileOut = aFileSystem->OpenOStream (theFile, std::ios::out | std::ios::binary | std::ios::trunc);
if (aFileOut.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to create file '") + theFile + "'");
return false;
}
if (!WriteImage (*aFileOut, theFile))
{
return false;
}
aFileOut->flush();
if (!aFileOut->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to write file '") + theFile + "'");
return false;
}
aFileOut.reset();
return true;
}
// ================================================================
// Function : WriteImage
// Purpose :
// ================================================================
Standard_Boolean Image_Texture::WriteImage (std::ostream& theStream,
const TCollection_AsciiString& theFile)
{
if (!myBuffer.IsNull())
{
theStream.write ((const char* )myBuffer->Data(), myBuffer->Size());
if (!theStream.good())
{
Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' cannot be written");
return false;
}
return true;
}
const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aFileIn = aFileSystem->OpenIStream (myImagePath, std::ios::in | std::ios::binary);
if (aFileIn.get() == NULL)
{
Message::SendFail (TCollection_AsciiString ("Error: Unable to open file ") + myImagePath + "!");
return false;
}
int64_t aLen = myLength;
if (myOffset >= 0)
{
aFileIn->seekg ((std::streamoff )myOffset, std::ios_base::beg);
if (!aFileIn->good())
{
Message::SendFail (TCollection_AsciiString ("Error: Image is defined with invalid file offset '") + myImagePath + "'");
return false;
}
}
else
{
aFileIn->seekg (0, std::ios_base::end);
aLen = (int64_t )aFileIn->tellg();
aFileIn->seekg (0, std::ios_base::beg);
}
Standard_Integer aChunkSize = 4096;
NCollection_Array1<Standard_Byte> aBuffer (0, aChunkSize - 1);
for (int64_t aChunkIter = 0; aChunkIter < aLen; aChunkIter += aChunkSize)
{
if (aChunkIter + aChunkSize >= aLen)
{
aChunkSize = Standard_Integer(aLen - aChunkIter);
}
if (!aFileIn->read ((char* )&aBuffer.ChangeFirst(), aChunkSize))
{
Message::SendFail (TCollection_AsciiString ("Error: unable to read image file '") + myImagePath + "'");
return false;
}
theStream.write ((const char* )&aBuffer.First(), aChunkSize);
}
if (!theStream.good())
{
Message::SendFail (TCollection_AsciiString ("File '") + theFile + "' can not be written");
return false;
}
return true;
}
//=======================================================================
//function : DumpJson
//purpose :
//=======================================================================
void Image_Texture::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
{
OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myTextureId)
OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myImagePath)
OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myBuffer.get())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myOffset)
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLength)
}