121bool OleRenderEmf(
const std::vector<uint8_t>& aEmf,
int aMaxWidth,
int aMaxHeight, wxImage& aImage,
122 double aTargetAspect )
124 using boost::endian::load_little_u32;
125 using boost::endian::load_little_s32;
127 if( aEmf.size() < 108 || aEmf.size() > MAX_EMF_BYTES || load_little_u32( aEmf.data() ) != 1
128 || load_little_u32( aEmf.data() + 4 ) < 88
129 || load_little_u32( aEmf.data() + 40 ) != 0x464D4520
130 || load_little_u32( aEmf.data() + 48 ) != aEmf.size() || !std::isfinite( aTargetAspect ) )
135 int64_t width = int64_t( load_little_s32( aEmf.data() + 16 ) ) - load_little_s32( aEmf.data() + 8 );
136 int64_t height = int64_t( load_little_s32( aEmf.data() + 20 ) ) - load_little_s32( aEmf.data() + 12 );
138 if( width <= 0 || height <= 0 || width > std::numeric_limits<int>::max()
139 || height > std::numeric_limits<int>::max() )
147 while( offset < aEmf.size() )
149 if( aEmf.size() - offset < 8 )
152 uint32_t length = load_little_u32( aEmf.data() + offset + 4 );
154 if( length < 8 || length % 4 != 0 || length > aEmf.size() - offset )
161 aMaxWidth, aMaxHeight, aTargetAspect );
163 if( size.
x <= 0 || size.
y <= 0 ||
size_t( size.
x ) * size.
y > MAX_RENDER_PIXELS )
166 const FONT_CONFIG
fonts = emfFontConfig();
171 generatorOptions options{};
172 options.svgDelimiter =
true;
173 options.imgWidth = size.
x;
174 options.imgHeight = size.
y;
175 options.fontConfig =
fonts.get();
177 std::vector<char> input( aEmf.begin(), aEmf.end() );
179 size_t svgLength = 0;
180 int converted = emf2svg( input.data(), input.size(), &svg, &svgLength, &options );
181 std::unique_ptr<char,
decltype( &free )> svgOwner( svg, free );
183 if( !converted || !svg || svgLength == 0 || svgLength > MAX_EMF_BYTES )
187 if( containsRaster( std::string_view( svg, svgLength ) ) )
190 std::unique_ptr<NSVGimage,
decltype( &nsvgDelete )> drawing(
191 nsvgParseWithFontConfig( svg,
"px", 96,
fonts.get() ), nsvgDelete );
193 if( !drawing || !drawing->shapes || !std::isfinite( drawing->width ) || !std::isfinite( drawing->height )
194 || drawing->width <= 0 || drawing->height <= 0 || drawing->width > aMaxWidth + 1.0
195 || drawing->height > aMaxHeight + 1.0 )
200 int renderWidth = std::max( 1,
KiROUND( drawing->width ) );
201 int renderHeight = std::max( 1,
KiROUND( drawing->height ) );
203 if(
size_t( renderWidth ) * renderHeight > MAX_RENDER_PIXELS )
206 std::unique_ptr<NSVGrasterizer,
decltype( &nsvgDeleteRasterizer )> rasterizer(
207 nsvgCreateRasterizer(), nsvgDeleteRasterizer );
212 std::vector<unsigned char> pixels(
size_t( renderWidth ) * renderHeight * 4 );
213 nsvgRasterize( rasterizer.get(), drawing.get(), 0, 0, 1, pixels.data(), renderWidth, renderHeight,
215 wxImage
image( renderWidth, renderHeight );
220 unsigned char* rgb =
image.GetData();
222 for(
size_t i = 0; i < pixels.size() / 4; ++i )
224 unsigned int alpha = pixels[i * 4 + 3];
226 for(
size_t channel = 0; channel < 3; ++channel )
227 rgb[i * 3 + channel] = ( pixels[i * 4 + channel] * alpha + 255 * ( 255 - alpha ) + 127 ) / 255;
230 if( renderWidth != size.
x || renderHeight != size.
y )
231 image.Rescale( size.
x, size.
y, wxIMAGE_QUALITY_HIGH );
233 aImage = std::move(
image );
234 return aImage.IsOk();