Image Markup iOS (Part 2)

Adding more drawing options to image markup app

M Hamza Khalid
4 min readJun 21, 2023
drawing on iPad
Photo by Kelly Sikkema on Unsplash

Drawing takes time.
A line has time in it.

Through the beautiful quote above,David Hockney emphasises the importance of taking one’s time in the creative process and recognising the significance of every mark made.

This brings us back to our topic for today which is marking images in iOS using swift.The first part of the tutorial taught us about how to use UIGraphicsImageRenderer to draw over images in iOS. If you haven’t gone through it yet, you can find it here Part 1.

Part 2

So without wasting any time, lets take our drawing knowledge further.

  1. Drawing Colour:

We will add colour setter function in out Pen class and then pass a UIColor to our didChangeColor function which will set the desired color for our Pen object.

2. Drawing Line Width:

We will add setter functions in out Pen class then pass a relevant size to our didChangePenSize function which will set the desired size for our Pen object.

3. Adding Arrows:

Now here comes the tricky part. Adding arrows on an image can be tricky especially if we want them to choose their direction dynamically.
It might seem confusing so lets dive into the coding part to understand it better

The drawArrow function is responsible for drawing an arrow on a canvas view. It checks if the current point is within the canvas view's bounds, calculates the centre point of the canvas, adds an arrow shape to the current path from the centre point to the current point, and configures a shape layer to display the arrow on the canvas with the desired stroke colour, stroke size, and styling.

Lets dive deeper into the code

We will add these functions as extension to BezierPath.The above function is used to draw an arrow on a graphical canvas, given the starting and ending points, along with parameters to control the length and angle of the arrowhead.

The above function takes two points (start and end) and calculates a new point that lies on the line segment connecting them. This point is determined by dividing the segment into a specified ratio and finding the coordinates of the corresponding point. This function is commonly used to determine the starting point of an arrow relative to two given points.

The final product will look something like this

For a detailed explanation of the above code, lets refer to the next section.

Detailed Code Explanation

The given code represents a function named addArrow that is used to draw an arrow between two points on a graphical canvas. Let's break down the code step by step:

  1. The function takes several parameters: start and end are the starting and ending points of the arrow, pointerLineLength represents the length of the arrowhead lines, and arrowAngle is the angle at which the arrowhead lines are inclined.
  2. The function calculateArrowStartPoint calculates the starting point of the arrowhead by calling the function. The calculated start point is then used to move the drawing cursor.
  3. The function adds a straight line from the starting point to the ending point of the arrow using the self.addLine method.
  4. The function calculates the angle between the x-axis and the line connecting the start and end points using trigonometry. This angle is adjusted based on the relative positions of the start and end points.
  5. Two additional points are calculated to form the arrowhead lines: arrowLine1 and arrowLine2. These points are computed by applying trigonometric functions (cosine and sine) to the arrow angle and the pointer line length, and then adjusting their coordinates based on the end point.
  6. The function adds two lines: one from the ending point to arrowLine1 and another from the ending point to arrowLine2 using the self.addLine method.

The given code snippet represents a function named calculateArrowStartPoint that is used to determine the starting point of an arrow. This function calculates a point that lies on the line segment connecting two given points.

Let’s break down the code step by step:

  1. The function calculates the distance d between the start and end points using the Euclidean distance formula. This formula involves computing the square root of the sum of the squared differences of the coordinates.
  2. The function defines a segment ratio r. This ratio will be used to determine the position of the arrow's starting point along the line segment. The value of 100 is arbitrary and can be adjusted based on the desired length of the segment.
  3. The function computes the x-coordinate of the starting point x3 by multiplying the start.x value by the ratio r and the end.x value by the complement of the ratio (1 - r). This calculation finds the point on the line segment that divides it into the ratio (1-r):r. Essentially, it determines how far along the segment the starting point should be.
  4. Similarly, the function calculates the y-coordinate of the starting point y3 by multiplying the start.y value by the ratio r and the end.y value by the complement of the ratio (1 — r).
  5. Finally, the function returns a CGPoint object representing the calculated starting point, with the coordinates (x3, y3).

Conclusion

To sum up, expanding the drawing options in an image markup app opens up a world of creative possibilities and enhances the user experience. By incorporating a diverse range of tools, such as different brush types, colours, shapes, and even advanced features like adding dynamic arrows, users can achieve whatever they want.

I hope you liked it! Follow me for more interesting topics and tutorials.
Thanks for the read !

--

--

M Hamza Khalid

An experienced iOS developer with a deep-rooted passion for creating robust, user-friendly mobile apps. Excited to share my knowledge to build something amazing