2

What I am trying to do is take a square imageview and make it a 5 point imageview in the shape of a 3 point triangle at the top and the bottom to points in a base.

enter image description here

public func shapeImage(with bezierPath: UIBezierPath, size: CGSize, fillColor: UIColor? = UIColor.clear,
                         strokeColor: UIColor? = nil, strokeWidth: CGFloat = 0.0) -> UIImage! {

UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
var image = UIImage(data: try! Data(contentsOf: URL(string:"https://a248.e.akamai.net/secure.meetupstatic.com/photos/member/5/3/5/e/highres_260901342.jpeg")!))!

if let context = context {
    context.saveGState()
    context.addPath(bezierPath.cgPath)

    if let strokeColor = strokeColor {
        strokeColor.setStroke()
        context.setLineWidth(strokeWidth)
    } else {
        UIColor.clear.setStroke()
    }

    fillColor?.setFill()
    context.drawPath(using: .fillStroke)

    image = UIGraphicsGetImageFromCurrentImageContext()!
    context.restoreGState()
    UIGraphicsEndImageContext()
}
return image

}

I want to take the top and make it bigger and keep the bottom half the same size. I do not want to mask or cut of some portion of the original image. I want to physical make the image bigger by stretching and not masking. I have not seen anything on this site that explains how to do this or if its possible.

  • Assuming the "green" part is the image - and even if not - this may not be possible without some sort of masking. Going from a 4 point quadrangle to a 5 point sextuple (sic?) pretty much has to include either masking or cropping. Any chance you could add more detail to what you are trying to do? Right now, the best idea I have is to use CIPerspectiveCorrection somehow - but even that uses a 4 point quadrangle. (You might even need to dive into geometry in your details.) –  Mar 24 '17 at 18:46
  • dont care if masking is used. I just don't want to cut out any part of the image. –  Mar 24 '17 at 18:53
  • Thinking it over, perspective correction won't help. You need a way to "stretch" an image by dragging a single point. I'm sure it can be done - but it may well require OpenGL Scripting Language (GLSL) at the pixel level. I do some coding of that, but not that particular thing. If you know it, it probably needs what is called a CI warp kernel because you need to know surrounding pixels for the "stretch". Wish I could help more (and you've given me an idea for an app)! Here's hoping someone else has a much better answer than I. –  Mar 24 '17 at 19:46
  • Jason, your example is not explanatory enough. Assume that the image is not simple fixed color but something more complicated as the image in your code, what do you expect to get? For examlpe if the original image is simple [linear gradient](https://www.w3schools.com/cssref/gradient_linear.png) and the new top-middle point is located and 2x height of the original image, how new image should look like? Would it be yellow (middle of the gradient) at the miiddle of the original top border? – SergGr Apr 02 '17 at 02:26
  • @SergGr using your linear gradient example all that would happen is that the same linear structure would just be bigger. I looks like your box is 300 x 300. I am trying to make the same thing only in a pentagon that is like 300 x 500. I am mostly trying to follow this example but this is in swift 2 http://stackoverflow.com/questions/33163317/how-to-make-imageview-with-different-shape-in-swift. –  Apr 02 '17 at 16:35
  • @JasonStone, I see an obvious contradiciton in your answers. In the question you state that "I do not want to mask or cut of some portion of the original image. I want to physical make the image bigger by stretching and not masking." on the other hand now you say that "the same linear structure would just be bigger" and in the answer you linked they do exactly that. (You can see that all the colors at the corners are absent in the "transformed" image). So what do you really want? – SergGr Apr 02 '17 at 18:42
  • @SergGr I don't know if this is possible however. Just think of it like this, lets take a 4 sided square and enlarge the image into a pentagon. Could I just take a 4 point image add another point and grab it and stretch out the point i added to make it a 5 sided shape? –  Apr 02 '17 at 19:37
  • @JasonStone, I understand that in your mind you have a good understanding of what you want to happen when your "stretch out the point i added to make it a 5 sided shape" but for others (me) it is not clear. Is the stretch the same for all the image and then you just crop the corners? Or does my linear gradient become triangular (join of two diagonal)? In the first case you need to apply mask. In the second case something more hardcore such as answer suggested by Jon Rose should be used. If both my guesses are wrong, then you should clarify what you want to get. – SergGr Apr 02 '17 at 19:41
  • @SergGr it would the second case "In the second case something more hardcore such as answer suggested by Jon Rose should be used." How would I call that function? –  Apr 02 '17 at 20:06
  • @JasonStone, Have you actually looked at the [GitHub for BCMeshTransformView](https://github.com/Ciechan/BCMeshTransformView). There are some usage examples (see `Using BCMeshTransformView` and `Simple Mesh Transform` sections) – SergGr Apr 02 '17 at 20:09
  • @SergGr ok thanks. I am going reward the bounty to Jon Rose –  Apr 02 '17 at 20:29

3 Answers3

2

If you don't want to crop with a mask you will have a very strange distorted image. If you are really really sure that is what you want you can use https://github.com/Ciechan/BCMeshTransformView to first move all the points down, then animate it to move only the center point up. something like:

BCMeshVertex vertices[] = {
    {.from = {0.0, 0.0}, .to= {0.0, 0.5, 0.0}},
    {.from = {1.0, 0.0}, .to= {1.0, 0.5, 0.0}},
    {.from = {1.0, 1.0}, .to= {1.0, 1.0, 0.0}},
    {.from = {0.0, 1.0}, .to= {0.0, 1.0, 0.0}},
};

and then when you want to turn it into a house update the vectors to:

BCMeshVertex vertices[] = {
    {.from = {0.0, 0.0}, .to= {0.0, 0.5, 0.0}},
    {.from = {0.5, 0.0}, .to= {0.0, 0.0, 0.0}},
    {.from = {1.0, 0.0}, .to= {1.0, 0.5, 0.0}},
    {.from = {1.0, 1.0}, .to= {1.0, 1.0, 0.0}},
    {.from = {0.0, 1.0}, .to= {0.0, 1.0, 0.0}},
};

This will make a weird mesh, warp effect like Warp \ bend effect on a UIView? - which is am pretty sure will look very very ugly. But that is what you asked for. (There is a MUCH simpler solution using a CAShapeLayer to mask the image).

Community
  • 1
  • 1
Jon Rose
  • 8,373
  • 1
  • 30
  • 36
  • How would I call this function? –  Apr 02 '17 at 16:32
  • Start by reading the docs here:https://github.com/Ciechan/BCMeshTransformView. Then read the blog posts. Then try it out and play with it. – Jon Rose Apr 03 '17 at 05:29
0

you can refer that

https://www.innofied.com/implementing-image-masking-in-ios/

when any problem in this i provide code for that but, now you show that help you or not..i try my best..

example:

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var imageView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let image = UIImage(named: "image.gif")
        let maskingImage = UIImage(named: "mask-image.gif")
        imageView.image = maskImage(image: image!, mask: maskingImage!)
    }

        func maskImage(image:UIImage, mask:(UIImage))->UIImage{

        let imageReference = image.cgImage
        let maskReference = mask.cgImage

        let imageMask = CGImage(maskWidth: maskReference!.width,
                                height: maskReference!.height,
                                bitsPerComponent: maskReference!.bitsPerComponent,
                                bitsPerPixel: maskReference!.bitsPerPixel,
                                bytesPerRow: maskReference!.bytesPerRow,
                                provider: maskReference!.dataProvider!, decode: nil, shouldInterpolate: true)

        let maskedReference = imageReference!.masking(imageMask!)

        let maskedImage = UIImage(cgImage:maskedReference!)

        return maskedImage
    }
}
Sagar Bhut
  • 657
  • 6
  • 28
0

I really don't see the problem to create one more point in a new BezierPath and draw a new Image with the same fillColor, Stroke etc .. You could use an extension like this one ...

public class func shapeImage(with bezierPath: UIBezierPath, size: CGSize, fillColor: UIColor? = UIColor.clear,
                             strokeColor: UIColor? = nil, strokeWidth: CGFloat = 0.0) -> UIImage! {

    UIGraphicsBeginImageContext(size)
    let context = UIGraphicsGetCurrentContext()
    var image = UIImage()
    if let context = context {
        context.saveGState()
        context.addPath(bezierPath.cgPath)

        if let strokeColor = strokeColor {
            strokeColor.setStroke()
            context.setLineWidth(strokeWidth)
        } else {
            UIColor.clear.setStroke()
        }

        fillColor?.setFill()
        context.drawPath(using: .fillStroke)

        image = UIGraphicsGetImageFromCurrentImageContext()!
        context.restoreGState()
        UIGraphicsEndImageContext()
    }
    return image
}
Johannes Knust
  • 891
  • 1
  • 11
  • 18
  • I edited the question with you suggestion and it does not do anything. I do not know how to call the function. –  Mar 31 '17 at 17:40
  • for me it's still not clear if you want to achieve a stretch on an IMAGE on a CUSTOM position or a SHAPE drawn by a bezier path?! – Johannes Knust Apr 01 '17 at 15:47
  • I want to achieve a stretch on a image on a custom position. –  Apr 01 '17 at 16:12