Annotation Rotation
Annotation rotation provides the functionality to rotate standard stamp annotations, custom stamp annotations, image annotations, and electronic signature annotations, allowing users to rotate annotations through a full range (-180~180 degrees). ComPDFKit offers convenient APIs for rotating annotations, along with demo demonstrations.
Rotating Annotations Programmatically
To rotate annotations programmatically, we need to set three properties of the annotation when initializing it: annotationRotation
, saveSourceRect
, and saveRectRotationPoints
.
annotationRotation
Sets the rotation angle of the annotation in degrees, with a range from -180 to 180.
saveSourceRect
The rectangular Rect before rotation. It's worth noting that this only needs to be refreshed when the annotation is scaled or moved, not when it is rotated.
saveRectRotationPoints
All rectangular vertices after rotation. Below is an example of how to obtain the vertices after rotation.
Here is the example code for annotation rotation:
// Create standard Stamp annotations
let stampAnnotation = CPDFStampAnnotation(document: document, type: selectedIndex)
annotation?.bounds = CGRect(x: 100, y: 100, width: 100, height: 100)
// Sets the rotation property of the annotations
stampAnnotation.annotationRotation = 0
// rotatePoints initialize the four vertices of the bounds
stampAnnotation.setSaveRectRotationPoints(rotatePoints)
stampAnnotation.updateRotationAppearanceStream()
stampAnnotation.setSaveSourceRect(stampAnnotation.bounds)
stampAnnotation.setSaveRectRotationPoints(rotatePoints)
// Annotation rotation
@objc func rotateStampAnnotation(_ stampAnnotation: CPDFStampAnnotation, Roate angleDifference: CGFloat) {
stampAnnotation.annotationRotation = Int(angleDifference * 180 / .pi)
// Get stampAnnotation.saveSourceRect() four vertices
var rotatedVertices = computeRotatedRectVerticesWithMidpoints(bounds: stampAnnotation.saveSourceRect(), annotationRotationDegrees: 0, includeMidpoints: true)
// rotatedVertices are sorted, with the lower left foot of saveSourceRect as the first point, sorted counterclockwise
rotatedVertices = sortPointsToFormRectangle(points: rotatedVertices)
let center = CGPoint(x: stampAnnotation.saveSourceRect().midX, y: stampAnnotation.saveSourceRect().midY)
var rotatePoints: [NSValue] = []
var newRotatedVertices: [CGPoint] = []
for point in rotatedVertices {
// Gets the rotated vertex
let rotatePoint = rotatePointAroundCenter(point: point, center: center, angleRadians: angleDifference)
let pointValue = NSValue(cgPoint: rotatePoint)
rotatePoints.append(pointValue)
newRotatedVertices.append(rotatePoint)
}
stampAnnotation.setSaveRectRotationPoints(rotatePoints)
stampAnnotation.bounds = boundingRectForPoints(points: newRotatedVertices)
stampAnnotation.updateRotationAppearanceStream()
stampAnnotation.setSaveRectRotationPoints(rotatePoints)
}
// Gets the rotated vertex
func rotatePointAroundCenter(point: CGPoint, center: CGPoint, angleRadians: CGFloat) -> CGPoint {
let s = sin(angleRadians)
let c = cos(angleRadians)
// Translate point back to origin
var translatedPoint = CGPoint(x: point.x - center.x, y: point.y - center.y)
// Rotate point
let xnew = translatedPoint.x * c - translatedPoint.y * s
let ynew = translatedPoint.x * s + translatedPoint.y * c
// Translate point back
translatedPoint.x = xnew + center.x
translatedPoint.y = ynew + center.y
return translatedPoint
}
// Create standard Stamp annotations
CPDFStampAnnotation *stampAnnotation = [[CPDFStampAnnotation alloc] initWithDocument:document type:selectedIndex];
stampAnnotation.bounds = CGRectMake(100, 100, 100, 100);
// Sets the rotation property of the annotations
stampAnnotation.annotationRotation = 0;
// rotatePoints initialize the four vertices of the bounds
[stampAnnotation setSaveRectRotationPoints:rotatedVertices];
[stampAnnotation updateAnnotationRotationAppearanceStream];
[stampAnnotation setSaveRectRotationPoints:rotatedVertices];
[stampAnnotation setSaveSourceRect:stampAnnotation.bounds];
// Annotation rotation
- (void)rotateStampAnnotation:(CPDFStampAnnotation *)stampRotation rotateAngle:(CGFloat)currentAngle {
CGPoint center = CGPointMake(CGRectGetMidX(stampRotation.saveSourceRect), CGRectGetMidY(stampRotation.saveSourceRect));
// Get stampAnnotation.saveSourceRect() four vertices
NSMutableArray<NSValue *> *saveSourceRectPoint = computeRotatedRectVerticesWithMidpoints(stampRotation.saveSourceRect, 0, YES);
// rotatedVertices are sorted, with the lower left foot of saveSourceRect as the first point, sorted counterclockwise
NSMutableArray<NSValue *> *saveRectPoints = sortPointsToFormRectangle(saveSourceRectPoint);
[stampRotation setAnnotationRotation :currentAngle];
NSMutableArray<NSValue *> *saveRectRotationPoints = [[NSMutableArray array] mutableCopy];
for (NSUInteger i = 0; i < saveRectPoints.count ; i ++) {
NSValue *savePointValue = [saveRectPoints objectAtIndex:i];
CGPoint savePoint = [savePointValue pointValue];
CGFloat angleRadians = currentAngle * M_PI / 180.0;
// Gets the rotated vertex
CGPoint saveRotationPoint = rotatePointAroundCenter(savePoint, center, angleRadians);
[saveRectRotationPoints addObject:[NSValue valueWithPoint:saveRotationPoint]];
}
[stampRotation setSaveRectRotationPoints:saveRectRotationPoints];
stampRotation.bounds = boundingRectForPoints(saveRectRotationPoints);
[stampRotation updateAnnotationRotationAppearanceStream];
[stampRotation setSaveRectRotationPoints:saveRectRotationPoints];
[self setNeedsDisplayAnnotationViewForPage:stampRotation.page];
}
// Gets the rotated vertex
CGPoint rotatePointAroundCenter(CGPoint point, CGPoint center, CGFloat angleRadians) {
CGFloat s = sin(angleRadians);
CGFloat c = cos(angleRadians);
// Translate point back to origin
point.x -= center.x;
point.y -= center.y;
// Rotate point
CGFloat xnew = point.x * c - point.y * s;
CGFloat ynew = point.x * s + point.y * c;
// Translate point back
point.x = xnew + center.x;
point.y = ynew + center.y;
return point;
}