// Copyright (C) 2007-2012 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CImageLoaderPPM.h" #ifdef _IRR_COMPILE_WITH_PPM_LOADER_ #include "IReadFile.h" #include "CColorConverter.h" #include "CImage.h" #include "os.h" #include "fast_atof.h" #include "coreutil.h" namespace irr { namespace video { //! constructor CImageLoaderPPM::CImageLoaderPPM() { #ifdef _DEBUG setDebugName("CImageLoaderPPM"); #endif } //! returns true if the file maybe is able to be loaded by this class //! based on the file extension (e.g. ".tga") bool CImageLoaderPPM::isALoadableFileExtension(const io::path& filename) const { return core::hasFileExtension ( filename, "ppm", "pgm", "pbm" ); } //! returns true if the file maybe is able to be loaded by this class bool CImageLoaderPPM::isALoadableFileFormat(io::IReadFile* file) const { c8 id[2]={0}; file->read(&id, 2); return (id[0]=='P' && id[1]>'0' && id[1]<'7'); } //! creates a surface from the file IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const { IImage* image; if (file->getSize() < 12) return 0; c8 id[2]; file->read(&id, 2); if (id[0]!='P' || id[1]<'1' || id[1]>'6') return 0; const u8 format = id[1] - '0'; const bool binary = format>3; core::stringc token; getNextToken(file, token); const u32 width = core::strtoul10(token.c_str()); getNextToken(file, token); const u32 height = core::strtoul10(token.c_str()); u8* data = 0; const u32 size = width*height; if (format==1 || format==4) { skipToNextToken(file); // go to start of data const u32 bytesize = size/8+(size & 3)?1:0; if (binary) { if (file->getSize()-file->getPos() < (long)bytesize) return 0; data = new u8[bytesize]; file->read(data, bytesize); } else { if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test return 0; data = new u8[bytesize]; memset(data, 0, bytesize); u32 shift=0; for (u32 i=0; i(width, height)); if (image) CColorConverter::convert1BitTo16Bit(data, (s16*)image->getData(), width, height); } else { getNextToken(file, token); const u32 maxDepth = core::strtoul10(token.c_str()); if (maxDepth > 255) // no double bytes yet return 0; skipToNextToken(file); // go to start of data if (format==2 || format==5) { if (binary) { if (file->getSize()-file->getPos() < (long)size) return 0; data = new u8[size]; file->read(data, size); image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; igetSize()-file->getPos() < (long)(2*size)) // optimistic test return 0; image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; igetSize()-file->getPos() < (long)bytesize) return 0; data = new u8[bytesize]; file->read(data, bytesize); image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; igetSize()-file->getPos() < (long)(2*bytesize)) // optimistic test return 0; image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->getData(); for (u32 i=0; igetPos()getSize()) { file->read(&c, 1); if (c=='#') { while (c!='\n' && c!='\r' && (file->getPos()getSize())) file->read(&c, 1); } else if (!core::isspace(c)) { token.append(c); break; } } while(file->getPos()getSize()) { file->read(&c, 1); if (c=='#') { while (c!='\n' && c!='\r' && (file->getPos()getSize())) file->read(&c, 1); } else if (!core::isspace(c)) token.append(c); else break; } } //! skip to next token (skip whitespace) void CImageLoaderPPM::skipToNextToken(io::IReadFile* file) const { c8 c; while(file->getPos()getSize()) { file->read(&c, 1); if (c=='#') { while (c!='\n' && c!='\r' && (file->getPos()getSize())) file->read(&c, 1); } else if (!core::isspace(c)) { file->seek(-1, true); // put back break; } } } //! creates a loader which is able to load windows bitmaps IImageLoader* createImageLoaderPPM() { return new CImageLoaderPPM; } } // end namespace video } // end namespace irr #endif