Drawing an Upright Stamp Annotation on a Rotated Page

When using a custom appearance stream generator to draw a stamp annotation, you’ll have to take care of the rotation offset of the page when drawing the image.

Here’s sample code demonstrating the counter-rotation:

func addUprightStampAnnotation () {
    // We need to fetch the `pageInfo` for the page in which the stamp annotation needs to be drawn.
    let pageInfo = document.pageInfoForPage(at: 0)

    // Here, we get the rotation of the page and convert it to radians.
    let rotation = CGFloat((pageInfo!.rotationOffset.rawValue + pageInfo!.savedRotation.rawValue) % 360) * CGFloat.pi / 180

    let image: UIImage = UIImage.init(named: "stamp-image")!
    let stampAnnotation = StampAnnotation()
    stampAnnotation.boundingBox = CGRect(x: 200, y: 200, width: 50, height: 50)

    let appearanceStreamGenerator = FileAppearanceStreamGenerator(fileURL: URL(fileURLWithPath: ""))
    appearanceStreamGenerator.drawingBlock = { context in
        var transform = CGAffineTransform.identity
        // First, translate and go to the center of the stamp annotation.
        transform = transform.translatedBy(x: stampAnnotation.boundingBox.origin.x + (stampAnnotation.boundingBox.size.width / 2),
                                           y: stampAnnotation.boundingBox.origin.y + (stampAnnotation.boundingBox.size.height / 2))
        // Now, rotate the context in the opposite direction of the page rotation.
        transform = transform.rotated(by: -1 * rotation)
        // Translate back to origin.
        transform = transform.translatedBy(x: -1 * (stampAnnotation.boundingBox.origin.x + (stampAnnotation.boundingBox.size.width / 2)),
                                           y: -1 * (stampAnnotation.boundingBox.origin.y + (stampAnnotation.boundingBox.size.height / 2)))
        context.concatenate(transform)
        // Draw the image now.
        context.draw(image.cgImage!, in: stampAnnotation.boundingBox)
    }
    stampAnnotation.appearanceStreamGenerator = appearanceStreamGenerator
    document.add(annotations: [stampAnnotation])
}
- (void)addUprightStampAnnotation {
    PSPDFDocument *document;
    // We need to fetch the `pageInfo` for the page in which the stamp annotation needs to be drawn.
    PSPDFPageInfo *pageInfo = [document pageInfoForPageAtIndex:0];

    // Here, we get the rotation of the page and convert it to radians.
    CGFloat rotationInDegrees =  (CGFloat)pageInfo.rotationOffset + (CGFloat)pageInfo.savedRotation;
    CGFloat rotation = rotationInDegrees * M_PI / 180;

    UIImage *image = [UIImage imageNamed:@"stamp-image"];
    PSPDFStampAnnotation *stampAnnotation = [[PSPDFStampAnnotation alloc] init];
    stampAnnotation.boundingBox = CGRectMake(200, 200, 50, 50);

    PSPDFFileAppearanceStreamGenerator *appearanceStreamGenerator = [[PSPDFFileAppearanceStreamGenerator alloc] initWithFileURL:[NSURL new]];
    [appearanceStreamGenerator setDrawingBlock:^(CGContextRef context) {
        CGAffineTransform transform = CGAffineTransformIdentity;

       // First, translate and go to the center of the stamp annotation.
        transform = CGAffineTransformTranslate(transform,
                                               stampAnnotation.boundingBox.origin.x + (stampAnnotation.boundingBox.size.width / 2),
                                               stampAnnotation.boundingBox.origin.y + (stampAnnotation.boundingBox.size.height / 2));

        // Now, rotate the context in the opposite direction of the page rotation.
        transform = CGAffineTransformRotate(transform, -1 * rotation);

        // Translate back to origin.
        transform = CGAffineTransformTranslate(transform,
                                               -1 * (stampAnnotation.boundingBox.origin.x + (stampAnnotation.boundingBox.size.width / 2)),
                                               -1 * (stampAnnotation.boundingBox.origin.y + (stampAnnotation.boundingBox.size.height / 2)));

        CGContextConcatCTM(context, transform);

        // Draw the image now.
        CGContextDrawImage(context, stampAnnotation.boundingBox, image.CGImage);
    }];

    stampAnnotation.appearanceStreamGenerator = appearanceStreamGenerator;
    [document addAnnotations:@[stampAnnotation] options:nil];
}