File: CImageLoaderSVG.cpp

package info (click to toggle)
supertuxkart 1.4%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 767,580 kB
  • sloc: cpp: 412,075; xml: 106,334; ansic: 83,792; asm: 1,559; python: 1,403; sh: 1,366; objc: 452; makefile: 333; javascript: 23; awk: 20
file content (180 lines) | stat: -rw-r--r-- 4,975 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// 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 "<svg"
    // this implementation refers IMG_isSVG() in SDL2_Image
    long filesize = file->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 "<svg" in the file
    if ( strstr(data, "<svg") )
    {
        delete[] data;
        return 1;
    }

    delete[] data;
    return 0;
}


struct NSVGimage* CImageLoaderSVG::getSVGImage(io::IReadFile* file, float* scale) const
{
    if (!file)
        return NULL;
    file->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