public static SvgDataUri Parse(
string href
)
href
The href value as a string.
Object that contains the parsed values.
The Parse method takes an href value as a raw string and tries to parse the data URI uniform resource identifier (URI) members out of it. Refer to SvgDataUri for more information. Parsing is useful for extracting, setting, and converting the pixel data of an image element in an SVG document.
For example, if the image element contains an embedded pixel data as follows:
<image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA ... etc" />
then Parse will return an SvgDataUri object set up as follows:
Member | Value |
---|---|
IsDataUri |
true since the parsing was successful and the href contains valid data URI. |
Href |
Same value as the source |
MediaOffset |
5. This is the offset into the href where the media type part starts. In this particular case it is 5, since this is the start of |
MediaLength |
9. This is the length of |
CharSetOffset |
-1 since the source href does not contain an explicit charset value. If it did, then this will contain the index into the href where the value starts. |
CharSetLength |
0 since the source href does not contain an explicit charset value. Otherwise, it will contain the number of characters of the value. |
IsBase64 |
true since the source href states the encoding. |
ValueOffset |
22. This is the offset into the href where the pixel data of the image starts. In this case 22, since this is the start of the pixel data |
ValueLength |
The length of the pixel data in the href from ValueOffset to the end of the string. |
ImageFormat |
RasterImageFormat.Png since the media type is |
Extension |
|
The reason for using offsets/length pairs instead of getting the values and putting them into properties in the class is because the href can be a very lengthy string containing the pixel data of a large image and making a copy can use unnecessary memory if the user is not interested in the particular value.
To get the values to a separate string, simply use String.Substring
passing SvgDataUri.Href and the offset and the length of the desired value. For example, this gets the Media type:
string mediaType = svgDataUri.Href.Substring(svgDataUri.MediaOffset, svgDataUri.MediaLength);
And to get the image data, use:
string base64ImageData = svgDataUri.Href.Substring(svgDataUri.ValueOffset, svgDataUri.ValueLength);
In both cases, checking if the offset is not -1 beforehand in case the object does not contain the value.
The image data is base64 encoded. To convert it to a byte array, use any standard base-64 conversion function such as Convert.FromBase64String
or Convert.ToBase64String
to encode the data in a byte into a base 64 encoded string.
If the SVG element does not contain a valid data URI but instead has a link to an external resource, for example <image xlink:href="image.png" />
or <image xlink:href="http://server/image.png" />
then calling Parse will succeed, but the value of IsDataUri will be false and the rest of the values of the class should not be used (will be set to their default values.
After successfully parsing (or constructing manually) an SvgDataUri object, you can save the resulting image to a disk file or stream using DecodeToStream or DecodeToFile. For example, with the previous SVG image element with the data URI, calling DecodeToFile will result in a PNG file saved to disk. The Extension property is useful for automatically setting the extension of the file as follows:
var href = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA ... etc";
// Parse it. If successful, save it to disk
var svgDataUri = SvgDataUri.Parse(href);
if(svgDataUri.IsDataUri)
svgDataUri.DecodeToFile("filename." + svgDataUri.Extension);
The EncodeFromFile and EncodeFromStream methods can create data URI values from image files. For example:
// filename.png is from the previous example
var href = SvgDataUri.EncodeFromFile("filename.png");
// Results in href = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA ... etc"
// Same as the original value.
These methods can accept any image file encoded as PNG, GIF, or JPEG. These are the standard file formats used by the web (and by extension, SVG). Any other image format will fail.
using Leadtools;
using Leadtools.Codecs;
using Leadtools.Drawing;
using Leadtools.Forms.DocumentWriters;
using Leadtools.Svg;
using Leadtools.Document.Writer;
private static void SvgDocumentEnumerateElementsExample()
{
// The source PDF file
var sourceFile = $@"{LEAD_VARS.ImagesDir}\Leadtools.pdf";
var beforeSvgFile = $@"{LEAD_VARS.ImagesDir}\Leadtools_before.svg";
var afterSvgFile = $@"{LEAD_VARS.ImagesDir}\Leadtools_after.svg";
// Assume this is our Virtual Directory
var virtualDirectory = "http://localhost/leadtools_images/svg/resources";
// Assume this phrysical directory maps to the Virtual Directory
var physicalDirectory = $@"{LEAD_VARS.ImagesDir}\svg\resources";
if (!Directory.Exists(physicalDirectory))
Directory.CreateDirectory(physicalDirectory);
// Our SVG element enumartion callback
SvgEnumerateElementsCallback callback = (SvgDocument document, SvgNodeHandle node, object userData) =>
{
if (node.ElementType == SvgElementType.Image)
{
// Get the href
var href = node.GetAttributeValue("xlink:href");
if (!string.IsNullOrEmpty(href))
{
// Parse it as data URI
var dataUri = SvgDataUri.Parse(href);
// Check if it is a data URI
if (dataUri.IsDataUri)
{
// Yes, create a new file in a virtual directory
// Show the dataURI properties
Console.WriteLine("Replacing data URI");
Console.WriteLine("Format:" + dataUri.ImageFormat);
if (dataUri.MediaLength > 0)
Console.WriteLine("Media:" + dataUri.Href.Substring(dataUri.MediaOffset, dataUri.MediaLength));
if (dataUri.CharSetOffset > 0)
Console.WriteLine("CharSet:" + dataUri.Href.Substring(dataUri.CharSetOffset, dataUri.CharSetLength));
else
Console.WriteLine("CharSet: not set");
Console.WriteLine("IsBase64:" + dataUri.IsBase64);
Console.WriteLine("ImageFormat:" + dataUri.ImageFormat);
var extension = dataUri.Extension;
Console.WriteLine("Extension:" + dataUri.Extension);
// Get a file name
var name = Guid.NewGuid().ToString().Replace("-", "") + "." + dataUri.Extension;
// Save it
// Full physical path
var filePath = Path.Combine(physicalDirectory, name);
dataUri.DecodeToFile(filePath);
/* Alternatively you can save the data yourself using this code
var data = dataUri.Href.Substring(dataUri.ValueOffset, dataUri.ValueLength);
// Save the data
var base64String = dataUri.Href.Substring(dataUri.ValueOffset, dataUri.ValueLength);
byte[] rawData = Convert.FromBase64String(base64String);
// Save it to disk
File.WriteAllBytes(filePath, rawData);
*/
// Finally replace the attribute in the image element with the URI
var virtualPath = virtualDirectory + "/" + name;
node.SetAttributeValue("xlink:href", virtualPath);
}
else
{
Console.WriteLine("Does not contain a valid data URI.");
}
}
}
return true;
};
using (var rasterCodecs = new RasterCodecs())
{
// Use 300 DPI when loading document images
rasterCodecs.Options.RasterizeDocument.Load.Resolution = 300;
// Load the first page as SVG
using (var svg = rasterCodecs.LoadSvg(sourceFile, 1, null) as SvgDocument)
{
if (!svg.IsFlat)
svg.Flat(null);
if (!svg.Bounds.IsValid)
svg.CalculateBounds(false);
// Save this SVG to disk, report the size
svg.SaveToFile(beforeSvgFile, null);
Console.WriteLine("Before unembedding the image, size is " + new FileInfo(beforeSvgFile).Length);
// Now enumerate the elements to replace each embedded image with a URL
// Since we are going to modify the SVG, call BeginUpdate/EndUpdate to speed up the process
svg.BeginUpdate();
svg.EnumerateElements(new SvgEnumerateOptions { EnumerateDirection = SvgEnumerateDirection.TopToBottom }, callback, null);
svg.EndUpdate();
// Save this SVG to disk again, report the size, should be alot smaller since the image are unembedded and stored as external resources
svg.SaveToFile(afterSvgFile, null);
Console.WriteLine("Before unembedding the image, size is " + new FileInfo(afterSvgFile).Length);
}
}
}
static class LEAD_VARS
{
public const string ImagesDir = @"C:\LEADTOOLS23\Resources\Images";
}