122bool OleRenderEmf(
const std::vector<uint8_t>& aEmf,
int aMaxWidth,
int aMaxHeight, wxImage& aImage,
123 double aTargetAspect )
125 using boost::endian::load_little_u32;
126 using boost::endian::load_little_s32;
128 if( aEmf.size() < 108 || aEmf.size() > MAX_EMF_BYTES || load_little_u32( aEmf.data() ) != 1
129 || load_little_u32( aEmf.data() + 4 ) < 88
130 || load_little_u32( aEmf.data() + 40 ) != 0x464D4520
131 || load_little_u32( aEmf.data() + 48 ) != aEmf.size() || !std::isfinite( aTargetAspect ) )
136 int64_t width = int64_t( load_little_s32( aEmf.data() + 16 ) ) - load_little_s32( aEmf.data() + 8 );
137 int64_t height = int64_t( load_little_s32( aEmf.data() + 20 ) ) - load_little_s32( aEmf.data() + 12 );
139 if( width <= 0 || height <= 0 || width > std::numeric_limits<int>::max()
140 || height > std::numeric_limits<int>::max() )
148 while( offset < aEmf.size() )
150 if( aEmf.size() - offset < 8 )
153 uint32_t length = load_little_u32( aEmf.data() + offset + 4 );
155 if( length < 8 || length % 4 != 0 || length > aEmf.size() - offset )
162 aMaxWidth, aMaxHeight, aTargetAspect );
164 if( size.
x <= 0 || size.
y <= 0 ||
size_t( size.
x ) * size.
y > MAX_RENDER_PIXELS )
167 const FONT_CONFIG
fonts = emfFontConfig();
172 generatorOptions options{};
173 options.svgDelimiter =
true;
174 options.imgWidth = size.
x;
175 options.imgHeight = size.
y;
176 options.fontConfig =
fonts.get();
178 std::vector<char> input( aEmf.begin(), aEmf.end() );
180 size_t svgLength = 0;
181 int converted = emf2svg( input.data(), input.size(), &svg, &svgLength, &options );
182 std::unique_ptr<char,
decltype( &free )> svgOwner( svg, free );
184 if( !converted || !svg || svgLength == 0 || svgLength > MAX_EMF_BYTES )
188 if( containsRaster( std::string_view( svg, svgLength ) ) )
191 std::unique_ptr<NSVGimage,
decltype( &nsvgDelete )> drawing(
192 nsvgParseWithFontConfig( svg,
"px", 96,
fonts.get() ), nsvgDelete );
194 if( !drawing || !drawing->shapes || !std::isfinite( drawing->width ) || !std::isfinite( drawing->height )
195 || drawing->width <= 0 || drawing->height <= 0 || drawing->width > aMaxWidth + 1.0
196 || drawing->height > aMaxHeight + 1.0 )
201 int renderWidth = std::max( 1,
KiROUND( drawing->width ) );
202 int renderHeight = std::max( 1,
KiROUND( drawing->height ) );
204 if(
size_t( renderWidth ) * renderHeight > MAX_RENDER_PIXELS )
207 std::unique_ptr<NSVGrasterizer,
decltype( &nsvgDeleteRasterizer )> rasterizer(
208 nsvgCreateRasterizer(), nsvgDeleteRasterizer );
213 std::vector<unsigned char> pixels(
size_t( renderWidth ) * renderHeight * 4 );
214 nsvgRasterize( rasterizer.get(), drawing.get(), 0, 0, 1, pixels.data(), renderWidth, renderHeight,
216 wxImage
image( renderWidth, renderHeight );
221 unsigned char* rgb =
image.GetData();
223 for(
size_t i = 0; i < pixels.size() / 4; ++i )
225 unsigned int alpha = pixels[i * 4 + 3];
227 for(
size_t channel = 0; channel < 3; ++channel )
228 rgb[i * 3 + channel] = ( pixels[i * 4 + channel] * alpha + 255 * ( 255 - alpha ) + 127 ) / 255;
231 if( renderWidth != size.
x || renderHeight != size.
y )
232 image.Rescale( size.
x, size.
y, wxIMAGE_QUALITY_HIGH );
234 aImage = std::move(
image );
235 return aImage.IsOk();