// Copyright (C) 2002-2012 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // This file is modified by riso from CImageLoaderJPG.h // nanosvg as parser and rasterizer for SVG files. // The nanosvg headers are based on those in SDL2_image-2.0.5 #include "CImageLoaderSVG.h" #include "IReadFile.h" #include "CImage.h" #include "os.h" #include "irrString.h" #include "CNullDriver.h" #ifndef SERVER_ONLY #include "ge_main.hpp" #endif namespace irr { namespace video { //! constructor CImageLoaderSVG::CImageLoaderSVG() { } //! returns true if the file maybe is able to be loaded by this class //! based on the file extension (e.g. ".tga") bool CImageLoaderSVG::isALoadableFileExtension(const io::path& filename) const { return core::hasFileExtension ( filename, "svg" ); } //! returns true if the file maybe is able to be loaded by this class bool CImageLoaderSVG::isALoadableFileFormat(io::IReadFile* file) const { // read first 4095 characters, check if can find "getSize(); long cropsize = filesize < 4095L ? filesize : 4095L; char* data = new char[cropsize+1]; int readsize = file->read(data,cropsize); data[cropsize] = '\0'; if( (long)readsize != cropsize) { os::Printer::log("Couldn't read SVG image file", file->getFileName(), ELL_ERROR); delete[] data; return 0; } // check if can find "seek(0); struct NSVGimage *img = 0; // read all the characters in the svg file to data long filesize = file->getSize(); char* data = new char[filesize+1]; int readsize = file->read(data,filesize); data[filesize] = '\0'; if( (long)readsize != filesize) { os::Printer::log("Couldn't read SVG image file", file->getFileName(), ELL_ERROR); delete[] data; return NULL; } // parse the svg image img = nsvgParse(data, "px", 96); if ( !img ) { os::Printer::log("Couldn't parse SVG image", ELL_ERROR); delete[] data; return NULL; } delete[] data; // only rescale the icons if ( strstr(file->getFileName().c_str(),"gui/icons/") ) { #ifndef SERVER_ONLY // determine scaling based on screen size float screen_height = (float)GE::getDriver()->getCurrentRenderTargetSize().Height; float desired_icon_size = 0.21*screen_height + 30.0f; // phenomenological *scale = desired_icon_size/img->height; #endif } return img; } core::dimension2du CImageLoaderSVG::getImageSize(struct NSVGimage* img, float scale) const { core::dimension2du dim; dim.Width = (unsigned)(img->width*scale); dim.Height = (unsigned)(img->height*scale); return dim; } bool CImageLoaderSVG::getImageSize(io::IReadFile* file, core::dimension2du* dim) const { if (!dim || !file || !isALoadableFileFormat(file)) return false; float scale = 1.0f; struct NSVGimage *img = getSVGImage(file, &scale); if (!img) return false; *dim = getImageSize(img, scale); nsvgDelete(img); file->seek(0); return true; } //! creates a surface from the file IImage* CImageLoaderSVG::loadImage(io::IReadFile* file, bool skip_checking) const { // check IMG_LoadSVG_RW float scale = 1.0f; struct NSVGimage *img = getSVGImage(file, &scale); struct NSVGrasterizer *rasterizer = 0; video::IImage* image = 0; rasterizer = nsvgCreateRasterizer(); if ( !rasterizer ) { os::Printer::log("Couldn't create SVG rasterizer", ELL_ERROR); nsvgDelete( img ); return 0; } image = new CImage(ECF_A8R8G8B8, getImageSize(img, scale)); if ( !image ) { os::Printer::log("LOAD SVG: create image struct failure", file->getFileName(), ELL_ERROR); nsvgDeleteRasterizer( rasterizer ); nsvgDelete( img ); return 0; } // rasterization nsvgRasterize(rasterizer, img, 0.0f, 0.0f, scale, (unsigned char *)image->lock(), (int)image->getDimension().Width, (int)image->getDimension().Height, (int)image->getPitch()); if (image) image->unlock(); // clean up nsvgDeleteRasterizer( rasterizer ); nsvgDelete( img ); return image; } //! creates a loader which is able to load svg images IImageLoader* createImageLoaderSVG() { return new CImageLoaderSVG(); } } // end namespace video } // end namespace irr