Get real frame after affine transformation

658 views Asked by At

The goal is to get real frames in pdf page to identify the searched string, I am using PDFKitten lib to highlight the text that was searched and trying to figure out how to get frames for highlighted text. The core method is next:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    CGContextSetFillColorWithColor(ctx, [[UIColor whiteColor] CGColor]);
    CGContextFillRect(ctx, layer.bounds);

    // Flip the coordinate system
    CGContextTranslateCTM(ctx, 0.0, layer.bounds.size.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);

    // Transform coordinate system to match PDF
    NSInteger rotationAngle = CGPDFPageGetRotationAngle(pdfPage);
    CGAffineTransform transform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, layer.bounds, -rotationAngle, YES);
    CGContextConcatCTM(ctx, transform);

    CGContextDrawPDFPage(ctx, pdfPage);

    if (self.keyword)
    {
        CGContextSetFillColorWithColor(ctx, [[UIColor yellowColor] CGColor]);
        CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
        for (Selection *s in self.selections)
        {
            NSLog(@"layer.bounds = %f, %f, %f, %f", layer.bounds.origin.x, layer.bounds.origin.y, layer.bounds.size.width, layer.bounds.size.height);
            CGContextSaveGState(ctx);
            CGContextConcatCTM(ctx, s.transform);
            NSLog(@"s.frame = %f, %f, %f, %f", s.frame.origin.x, s.frame.origin.y, s.frame.size.width, s.frame.size.height);
            CGContextFillRect(ctx, s.frame);
            CGContextRestoreGState(ctx);
        }
    }
}

Size of layer is (612.000000, 792.000000), but the size of s.frame is (3.110400, 1.107000). How can I get real frame from rect that is filled yellow?

2

There are 2 answers

0
Duncan C On

As Matt says, a view/layer's frame property is not valid unless the transform is the identity transform.

If you want to transform some rectangle using a transform then the CGRect structure isn't useful, since a CGRect specifies an origin and a size, and assumes that the other 3 points of the rect are shifted right/down from the origin.

In order to create a transformed rectangle you need to build 4 points for the upper left, upper right, lower left, and lower right points of the untransformed frame rectangle, and then apply the transform to those points, before applying the transform to the view.

See the function CGPoint CGPointApplyAffineTransform(CGPoint point, CGAffineTransform t) to apply a CGAffineTransform to a point.

Once you've done that you could use the transformed points to build a bezier path containing a polygon that is your transformed rectangle. (It may or may not be a rectangle after transformation, and the only sure-fire way to represent it is as 4 points that describe a quadralateral.)

0
Nick Rybalko On

Please use bounds property. Also you have to use bounds when create custom layout. It's transform free.

frame it's rectangle which defines the size and position of the view in its superlayer’s coordinate system. bounds it's rectangle defines the size and position of the layer in its itself coordinate system. 

https://developer.apple.com/reference/quartzcore/calayer/1410915-bounds