Drawing Images using Graphics

Drawing Images using Graphics

With the Aspose.Imaging library you can draw simple shapes like lines, rectangles and circles, as well as complex shapes like polygons, curves, arcs and Bezier shapes. Aspose.Imaging library creates such shapes using Graphics class that resides in the aspose.imaging namespace. Graphics objects are responsible for performing different drawing operations on an image, thus changing the image’s surface. The Graphics class uses a variety of helper objects to enhance the shapes:

  • Pens, to draw lines, outline shapes, or render other geometric representations.
  • Brushes, to define how areas are filled in.
  • Fonts, to define the shape of characters of text.

Drawing with the Graphics Class

Below is a code example demonstrating the use of the Graphics class. The example source code has been split into several parts to keep it simple and easy to follow. Step by step, the examples show how to:

  1. Create an image.
  2. Create and initialize a Graphics object.
  3. Clear the surface.
  4. Draw an ellipse.
  5. Draw a filled polygon and save the image.

Programming Samples

Creating an Image

Start by creating an image using any of the methods described in Creating Files.

Create and Initialize a Graphics Object

Then create and initialize a Graphics object by passing the Image object to its constructor.

Clear the Surface

Clear the Graphics surface by calling the Graphics class clear method and pass a color as a parameter. This method fills the Graphics surface with the color passed in as argument.

Draw an Ellipse

You may notice that the Graphics class has exposed plenty of methods to draw and fill shapes. You’ll find get the complete list of methods in the Aspose.Imaging for Python via .NET API Reference. There are several overloaded versions of the draw_ellipse method exposed by the Graphics class. All these methods accept a Pen object as its first argument. The later parameters are passed to define the bounding rectangle around the ellipse. For the sake of this example, use the version accepting a Rectangle object as the second parameter to draw an ellipse using the Pen object in your desired color.

Draw a Filled Polygon

Next, draw a polygon using the LinearGradientBrush and an array of points. The Graphics class has exposed several overloaded versions of the fill_polygon() method. All of these accept a Brush object as its first argument, defining the characteristics of the fill. The second parameter is an array of points. Please note that every two consecutive points in the array specify a side of the polygon.

import aspose.pycore as aspycore
from aspose.imaging import Image, Graphics, Rectangle, Point, Color, Point
from aspose.imaging.brushes import SolidBrush
from aspose.imaging.fileformats.bmp import *
import os
if 'TEMPLATE_DIR' in os.environ:
templates_folder = os.environ['TEMPLATE_DIR']
else:
templates_folder = r"C:\Users\USER\Downloads\templates"
delete_output = 'SAVE_OUTPUT' not in os.environ
data_dir = templates_folder
with Image.load(os.path.join(data_dir, "template.bmp")) as image:
# Create and initialize an instance of Graphics class
graphic = Graphics(image)
graphic.fill_rectangle(SolidBrush(Color.green), Rectangle(0, 0, 100, 100))
graphic.fill_polygon_by_point(SolidBrush(Color.green), [Point(0, 0), Point(100, 100), Point(10, 10)])
image.save(os.path.join(data_dir, "result.bmp"))
if delete_output:
os.remove(os.path.join(data_dir, "result.bmp"))

Measure string using Aspose.Graphics

Aspose.Imaging Graphics supports method to measure string. Here the sample code for it is provided.

import aspose.pycore as aspycore
from aspose.imaging import Image, Graphics, Font, Color, StringFormat, SizeF, PointF
from aspose.imaging.brushes import SolidBrush
import os
if 'TEMPLATE_DIR' in os.environ:
templates_folder = os.environ['TEMPLATE_DIR']
else:
templates_folder = r"C:\Users\USER\Downloads\templates"
delete_output = 'SAVE_OUTPUT' not in os.environ
data_dir = templates_folder
# Creates an instance of FileStream
with Image.load(os.path.join(data_dir, "template.bmp")) as image:
# Create and initialize an instance of Graphics class
graphic = Graphics(image)
graphic.draw_string("Test", Font("Arial", 10.0), SolidBrush(Color.black), PointF(0.0, 0.0))
size = graphic.measure_string("Test", Font("Arial", 10.0), SizeF(100.0, 100.0), StringFormat.generic_default)
image.save(os.path.join(data_dir, "result.bmp"))
if delete_output:
os.remove(os.path.join(data_dir, "result.bmp"))

Drawing Images using Graphics : Complete Source

from aspose.imaging import Image, Graphics, Color, Pen, Rectangle, Point
from aspose.imaging.brushes import LinearGradientBrush
from aspose.imaging.imageoptions import BmpOptions
from aspose.imaging.sources import FileCreateSource
import os
if 'TEMPLATE_DIR' in os.environ:
templates_folder = os.environ['TEMPLATE_DIR']
else:
templates_folder = r"C:\Users\USER\Downloads\templates"
delete_output = 'SAVE_OUTPUT' not in os.environ
data_dir = templates_folder
# Create an instance of BmpOptions and set its various properties
with BmpOptions() as image_options:
image_options.bits_per_pixel = 24
# Create an instance of FileCreateSource and assign it to Source property
image_options.source = FileCreateSource(os.path.join(data_dir, "result.bmp"), False)
with Image.create(image_options, 500, 500) as image:
graphics = Graphics(image)
# Clear the image surface with white color and Create and initialize a Pen object with blue color
graphics.clear(Color.white)
pen = Pen(Color.blue)
# Draw Ellipse by defining the bounding rectangle of width 150 and height 100 also Draw a polygon using the LinearGradientBrush
graphics.draw_ellipse(pen, Rectangle(10, 10, 150, 100))
with LinearGradientBrush(image.bounds, Color.red, Color.white, 45.0) as linear_gradient_brush:
graphics.fill_polygon_by_point(linear_gradient_brush, [Point(200, 200), Point(400, 200), Point(250, 350)])
image.save()
if delete_output:
os.remove(os.path.join(data_dir, "result.bmp"))

All classes that implement enter and exit methods and access unmanaged resources are instantiated in a with statement to ensure that they are disposed of correctly.

Drawing Text on images using Graphics

Using Aspose.Imaging you can easily draw text on image with text alignment using Graphics.

import aspose.pycore as aspycore
from aspose.imaging import Image, Graphics, Color, Pen, RectangleF, Point, SizeF, \
StringFormat, StringAlignment, StringFormatFlags, Font
from aspose.imaging.brushes import SolidBrush
from aspose.imaging.imageoptions import PngOptions
from aspose.imaging.sources import FileCreateSource
import os
if 'TEMPLATE_DIR' in os.environ:
templates_folder = os.environ['TEMPLATE_DIR']
else:
templates_folder = r"C:\Users\USER\Downloads\templates"
delete_output = 'SAVE_OUTPUT' not in os.environ
data_dir = templates_folder
def run():
alignments = ["Left", "Center", "Right"]
for alignment in alignments:
draw_string(templates_folder, alignment)
def draw_string(base_folder, align):
output_file_name = os.path.join(data_dir, "result.png")
font_names = ["Arial", "Times New Roman", "Bookman Old Style", "Calibri", "Comic Sans MS", "Courier New", "Microsoft Sans Serif", "Tahoma", "Verdana", "Proxima Nova Rg"]
font_sizes = [10.0, 22.0, 50.0, 100.0]
width = 3000
height = 3500
# Create an instance of PngOptions and set its various properties
with PngOptions() as png_options:
# Set the Source for PngOptions
png_options.source = FileCreateSource(output_file_name, False)
# Create an instance of Image
with Image.create(png_options, width, height) as image:
# Create and initialize an instance of Graphics class
graphics = Graphics(image)
# Clear Graphics surface
graphics.clear(Color.white)
# Create a SolidBrush object and set its various properties
brush = SolidBrush()
brush.color = Color.black
x = 10
line_x = 0
y = 10
w = width - 20
pen = Pen(Color.red, 1.0)
alignment = StringAlignment.NEAR
if align == "Left":
line_x = round(x, 0)
elif align == "Center":
alignment = StringAlignment.CENTER
line_x = round(x + w / 2.0, 0)
elif align == "Right":
alignment = StringAlignment.FAR
line_x = round(x + w)
string_format = StringFormat(StringFormatFlags.EXACT_ALIGNMENT)
string_format.alignment = alignment
for font_name in font_names:
for font_size in font_sizes:
font = Font(font_name, font_size)
text = "This is font: {0}, size:{1}".format(font_name, font_size)
s = graphics.measure_string(text, font, SizeF.empty, None)
graphics.draw_string(text, font, brush, RectangleF(float(x), float(y), float(w), float(s.height)), string_format)
y += s.height
graphics.draw_line(pen, Point(round(x), round(y)), Point(round(x + w), round(y)))
graphics.draw_line(pen, Point(round(line_x), 0), Point(round(line_x), round(y)))
# save all changes.
image.save()
if delete_output:
os.remove(os.path.join(data_dir, "result.png"))
run()

Memory Strategy optimization

Graphics operations can be proceeded using memory strategy optimization - ie limiting memory buffer size for operation.

from aspose.imaging import Image, Graphics, Color, Pen, Rectangle, Point
from aspose.imaging.brushes import LinearGradientBrush
from aspose.imaging.imageoptions import PngOptions
from aspose.imaging.sources import FileCreateSource
import os
if 'TEMPLATE_DIR' in os.environ:
templates_folder = os.environ['TEMPLATE_DIR']
else:
templates_folder = r"C:\Users\USER\Downloads\templates"
delete_output = 'SAVE_OUTPUT' not in os.environ
data_dir = templates_folder
image_size = 2000
with PngOptions() as create_options:
create_options.source = FileCreateSource(os.path.join(data_dir, "result.png"), False)
create_options.buffer_size_hint = 30
with Image.create(create_options, image_size, image_size) as image:
graphics = Graphics(image)
# You can use any graphic operations here, all of them will be performed within the established memory limit
# For example:
graphics.clear(Color.light_sky_blue)
graphics.draw_line(Pen(Color.red, 3.0), 0, 0, image.width, image.height)
image.save()
if delete_output:
os.remove(os.path.join(data_dir, "result.png"))
# A large number of graphic operations are also supported:
operation_area_size = 10
with PngOptions() as create_options:
create_options.source = FileCreateSource(os.path.join(data_dir, "result_2.png"), False)
create_options.buffer_size_hint = 30
with Image.create(create_options, image_size, image_size) as image:
graphics = Graphics(image)
graphics.begin_update()
graphics.clear(Color.light_sky_blue)
for column in range(image_size // operation_area_size):
for row in range(image_size // operation_area_size):
x = column * operation_area_size
y = row * operation_area_size
is_reversed = (column + row) % 2 != 0
if (is_reversed):
graphics.draw_line(
Pen(Color.red),
x + operation_area_size - 2,
y,
x,
y + operation_area_size);
else:
graphics.draw_line(
Pen(Color.red),
x,
y,
x + operation_area_size - 2,
y + operation_area_size);
# About 40k operations will be applied here, while they do not take up too much memory
# (since they are already unloaded into the external file, and will be loaded from there one at a time)
graphics.end_update()
image.save()
if delete_output:
os.remove(os.path.join(data_dir, "result_2.png"))