Thay đổi màu sắc của hình ảnh


100

Tôi đang cố gắng thay đổi màu sắc của UIImage. Mã của tôi:

-(UIImage *)coloredImage:(UIImage *)firstImage withColor:(UIColor *)color {
    UIGraphicsBeginImageContext(firstImage.size);

    CGContextRef context = UIGraphicsGetCurrentContext();
    [color setFill];

    CGContextTranslateCTM(context, 0, firstImage.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextSetBlendMode(context, kCGBlendModeCopy);
    CGRect rect = CGRectMake(0, 0, firstImage.size.width, firstImage.size.height);
    CGContextDrawImage(context, rect, firstImage.CGImage);

    CGContextClipToMask(context, rect, firstImage.CGImage);
    CGContextAddRect(context, rect);
    CGContextDrawPath(context,kCGPathElementMoveToPoint);

    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return coloredImg;
}

Mã này hoạt động, nhưng hình ảnh thu được không tốt như vậy: các pixel giới hạn của hình ảnh trả về không liên tục và không quá mịn như trong hình ảnh đầu tiên của tôi. Làm cách nào để giải quyết vấn đề này?


1
có thể trùng lặp về thay đổi màu UIImage?
idmean

Câu trả lời:


263

Kể từ iOS 7, đây là cách đơn giản nhất để thực hiện.

Mục tiêu-C:

theImageView.image = [theImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];

Swift 2.0:

theImageView.image = theImageView.image?.imageWithRenderingMode(.AlwaysTemplate) 
theImageView.tintColor = UIColor.magentaColor()

Swift 4.0:

theImageView.image = theImageView.image?.withRenderingMode(.alwaysTemplate) 
theImageView.tintColor = .magenta

Bảng phân cảnh:

Trước tiên, hãy định cấu hình hình ảnh dưới dạng mẫu (trên thanh bên phải - Hiển thị dưới dạng) trong nội dung của bạn. Sau đó, màu của hình ảnh sẽ là màu được áp dụng. nhập mô tả hình ảnh ở đây


"UIImageRenderingModeAlwaysTemplate: Luôn vẽ hình ảnh dưới dạng hình ảnh mẫu, bỏ qua thông tin màu sắc của nó." Đẹp!
Tieme

3
Trong Swift 2.0+theImageView.image? = (theImageView.image?.imageWithRenderingMode(.AlwaysTemplate))! theImageView.tintColor = UIColor.magentaColor()
ColossalChris

@AnkishJain có bất kỳ mối quan tâm nào về hiệu suất xung quanh cách tiếp cận này không?
Ríomhaire

3
Thao tác này không làm thay đổi màu sắc của hình ảnh, mà hướng dẫn chế độ xem hiển thị nó với một sắc thái (màu) khác.
Steve Kuo

@ Có thể không thực sự. Bạn có thể sử dụng nó cho bất kỳ UIImage nào. img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [button setTintColor:[UIColor redColor]]; [button setImage:img forState:UIControlStateNormal];@Ankish cảm ơn!
Motasim

31

Đây là khá nhiều câu trả lời ở trên, nhưng hơi ngắn. Điều này chỉ lấy hình ảnh làm mặt nạ và không thực sự "nhân" hoặc tô màu cho hình ảnh.

Mục tiêu C:

    UIColor *color = <# UIColor #>;
    UIImage *image = <# UIImage #>;// Image to mask with
    UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [color setFill];
    CGContextTranslateCTM(context, 0, image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextClipToMask(context, CGRectMake(0, 0, image.size.width, image.size.height), [image CGImage]);
    CGContextFillRect(context, CGRectMake(0, 0, image.size.width, image.size.height));

    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

Nhanh:

    let color: UIColor = <# UIColor #>
    let image: UIImage = <# UIImage #> // Image to mask with
    UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
    let context = UIGraphicsGetCurrentContext()
    color.setFill()
    context?.translateBy(x: 0, y: image.size.height)
    context?.scaleBy(x: 1.0, y: -1.0)
    context?.clip(to: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), mask: image.cgImage!)
    context?.fill(CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
    let coloredImg = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

2
Bạn nên sử dụng UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);vì phiên bản của bạn sẽ chỉ tạo đồ họa không võng mạc.
Nikola Lajic 9/1213

Theo kinh nghiệm của tôi, user1270061 là cách để làm điều đó. Câu trả lời khác với "ghi" cần hình ảnh nguồn của một số màu rõ ràng. Cái này chỉ sử dụng các giá trị alpha trong các pixel nguồn và kết hợp nó với màu mong muốn - hoàn hảo.
Jason

Hoàn hảo - chỉ câu trả lời phù hợp với tôi. (16 tháng 5 ')
trdavidson

10

Một cách khác để tô màu cho hình ảnh là chỉ cần nhân nó với một màu không đổi. Đôi khi, điều này được ưu tiên hơn vì nó không "nâng" các giá trị màu trong các vùng đen; nó giữ cho các cường độ tương đối trong hình ảnh giống nhau. Sử dụng lớp phủ làm sắc thái màu có xu hướng làm phẳng độ tương phản.

Đây là mã tôi sử dụng:

UIImage *MultiplyImageByConstantColor( UIImage *image, UIColor *color ) {

    CGSize backgroundSize = image.size;
    UIGraphicsBeginImageContext(backgroundSize);

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGRect backgroundRect;
    backgroundRect.size = backgroundSize;
    backgroundRect.origin.x = 0;
    backgroundRect.origin.y = 0;

    CGFloat r,g,b,a;
    [color getRed:&r green:&g blue:&b alpha:&a];
    CGContextSetRGBFillColor(ctx, r, g, b, a);
    CGContextFillRect(ctx, backgroundRect);

    CGRect imageRect;
    imageRect.size = image.size;
    imageRect.origin.x = (backgroundSize.width - image.size.width)/2;
    imageRect.origin.y = (backgroundSize.height - image.size.height)/2;

    // Unflip the image
    CGContextTranslateCTM(ctx, 0, backgroundSize.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);

    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
    CGContextDrawImage(ctx, imageRect, image.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;
}

Phiên bản Swift

extension UIImage{

    static func multiplyImageByConstantColor(image:UIImage,color:UIColor)->UIImage{
        let backgroundSize = image.size
        UIGraphicsBeginImageContext(backgroundSize)

        let ctx = UIGraphicsGetCurrentContext()

        var backgroundRect=CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        var r:CGFloat
        var g:CGFloat
        var b:CGFloat
        var a:CGFloat
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        CGContextSetRGBFillColor(ctx, r, g, b, a)
        CGContextFillRect(ctx, backgroundRect)

        var imageRect=CGRect()
        imageRect.size = image.size
        imageRect.origin.x = (backgroundSize.width - image.size.width)/2
        imageRect.origin.y = (backgroundSize.height - image.size.height)/2

        // Unflip the image
        CGContextTranslateCTM(ctx, 0, backgroundSize.height)
        CGContextScaleCTM(ctx, 1.0, -1.0)

        CGContextSetBlendMode(ctx, .Multiply)
        CGContextDrawImage(ctx, imageRect, image.CGImage)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

Giải pháp chính xác mà tôi đang tìm kiếm! Cảm ơn!
vir us

Nếu tôi muốn tạo một ứng dụng vẽ tranh tường ảo thì sao? điều này hoạt động, nếu bạn muốn chỉ tô màu cho các bức tường trong hình ảnh. Vui lòng xem liên kết này: - stackoverflow.com/questions/27482508/…
Shailesh

Điều này hoạt động tốt hơn nhiều so với một số giải pháp khác hiện có.
Matt Hudson

3
Điều này chỉ tô màu nền đối tượng đối với tôi, không tô màu cho chính đối tượng.
dùng3562927

7

Trong Swift 3.0

imageView.image? = (imageView.image?.withRenderingMode(.alwaysTemplate))!
imageView.tintColor = UIColor.magenta

Trong Swift 2.0

yourImage.image? = (yourImage.image?.imageWithRenderingMode(.AlwaysTemplate))!
yourImage.tintColor = UIColor.magentaColor()

Chúc các bạn đi tiên phong về Swift


5
Code thì không sao, nhưng bài là về UIImage. Không phải lúc nào chúng tôi cũng xử lý UIImageViews.
HenryRootThai

5

Giải pháp Swift 4.2

extension UIImage {
    func withColor(_ color: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        guard let ctx = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }
        color.setFill()
        ctx.translateBy(x: 0, y: size.height)
        ctx.scaleBy(x: 1.0, y: -1.0)
        ctx.clip(to: CGRect(x: 0, y: 0, width: size.width, height: size.height), mask: cgImage)
        ctx.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
        guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }
        UIGraphicsEndImageContext()
        return colored
    }
}

// Usage:
// let redImage = UIImage().withColor(.red)

5

Bắt đầu từ iOS 10, bạn có thể sử dụng UIGraphicsImageRenderer:

extension UIImage {

    func colored(_ color: UIColor) -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { context in
            color.setFill()
            self.draw(at: .zero)
            context.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height), blendMode: .sourceAtop)
        }
    }

}

3

Nếu bạn không phải làm điều đó theo chương trình, bạn có thể thực hiện việc đó bằng Xcode UI.

Nếu bạn đi tới hình ảnh trong thư mục nội dung hình ảnh của mình, hãy mở trình kiểm tra ở phía bên phải và có menu thả xuống "Kết xuất dưới dạng" với các tùy chọn sau:

  1. Mặc định
  2. Nguyên
  3. Bản mẫu

Khi bạn đã chọn xong Mẫu, bạn có thể thay đổi màu của hình ảnh theo bất kỳ cách nào bạn muốn - cho dù nó đang sử dụng giao diện người dùng bảng phân cảnh Xcode hay theo chương trình.

nhập mô tả hình ảnh ở đây

Xem hình ảnh này:

nhập mô tả hình ảnh ở đây


Bạn có đang sử dụng XCODE 8 không?
doxsi

2

Đây là sự điều chỉnh của tôi về câu trả lời của @ Anna. Hai điểm chính ở đây:

  • Sử dụng destinationInchế độ hòa trộn
  • Gọi UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)để có được hình ảnh mượt mà

Mã trong Swift 3 :

extension UIImage {

    static func coloredImage(image: UIImage?, color: UIColor) -> UIImage? {

        guard let image = image else {
            return nil
        }

        let backgroundSize = image.size
        UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)

        let ctx = UIGraphicsGetCurrentContext()!

        var backgroundRect=CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        var r:CGFloat = 0
        var g:CGFloat = 0
        var b:CGFloat = 0
        var a:CGFloat = 0
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        ctx.setFillColor(red: r, green: g, blue: b, alpha: a)
        ctx.fill(backgroundRect)

        var imageRect = CGRect()
        imageRect.size = image.size
        imageRect.origin.x = (backgroundSize.width - image.size.width) / 2
        imageRect.origin.y = (backgroundSize.height - image.size.height) / 2

        // Unflip the image
        ctx.translateBy(x: 0, y: backgroundSize.height)
        ctx.scaleBy(x: 1.0, y: -1.0)

        ctx.setBlendMode(.destinationIn)
        ctx.draw(image.cgImage!, in: imageRect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

2
tại sao bạn vượt qua hình ảnh khi mở rộng UIImage? bạn nên loại bỏ các từ khóa tĩnh của phương pháp của bạn và chỉ sử dụng selftrong phương pháp của bạn và loại bỏ các tham số hình ảnh không cần thiết
Leo Dabus

1

Dựa trên câu trả lời của @ Anna và tôi viết lại cho swift 2.2 và xử lý hình ảnh bằng kênh alpha:

static func multiplyImageByConstantColor(image:UIImage,color:UIColor)->UIImage{
    let backgroundSize = image.size
    UIGraphicsBeginImageContext(backgroundSize)

    let ctx = UIGraphicsGetCurrentContext()

    var backgroundRect=CGRect()
    backgroundRect.size = backgroundSize
    backgroundRect.origin.x = 0
    backgroundRect.origin.y = 0

    var r:CGFloat = 0
    var g:CGFloat = 0
    var b:CGFloat = 0
    var a:CGFloat = 0
    color.getRed(&r, green: &g, blue: &b, alpha: &a)
    CGContextSetRGBFillColor(ctx, r, g, b, a)

    // Unflip the image
    CGContextTranslateCTM(ctx, 0, backgroundSize.height)
    CGContextScaleCTM(ctx, 1.0, -1.0)
    CGContextClipToMask(ctx, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
    CGContextFillRect(ctx, backgroundRect)

    var imageRect=CGRect()
    imageRect.size = image.size
    imageRect.origin.x = (backgroundSize.width - image.size.width)/2
    imageRect.origin.y = (backgroundSize.height - image.size.height)/2


    CGContextSetBlendMode(ctx, .Multiply)
    CGContextDrawImage(ctx, imageRect, image.CGImage)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

0

Mã của Anna hoạt động tốt để sao chép hình ảnh UIImage.image trên nền .image màu bằng cách sử dụng kCGBlendModeNormal thay vì kCGBlendModeMultiply. Ví dụ: self.mainImage.image = [self NormalImageByConstantColor: self.mainImage.image withColor: yourColor];sẽ đặt nội dung của mainImage.image trên màu sắc của yourColor trong khi vẫn bảo toàn độ mờ của yourColor. Điều này đã giải quyết được vấn đề của tôi khi đặt màu nền có độ mờ đằng sau hình ảnh để lưu vào Thư viện ảnh.


0

Swift 3:

extension UIImage{

    static func multiplyImageByConstantColor(image:UIImage,color:UIColor) -> UIImage{

        let backgroundSize = image.size
        UIGraphicsBeginImageContext(backgroundSize)

        guard let ctx = UIGraphicsGetCurrentContext() else {return image}

        var backgroundRect=CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        var r:CGFloat = 0
        var g:CGFloat = 0
        var b:CGFloat = 0
        var a:CGFloat = 0
        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        ctx.setFillColor(red: r, green: g, blue: b, alpha: a)

        // Unflip the image
        ctx.translateBy(x: 0, y: backgroundSize.height)
        ctx.scaleBy(x: 1.0, y: -1.0)
        ctx.clip(to: CGRect(0, 0, image.size.width, image.size.height), mask: image.cgImage!)
        ctx.fill(backgroundRect)


        var imageRect=CGRect()
        imageRect.size = image.size
        imageRect.origin.x = (backgroundSize.width - image.size.width)/2
        imageRect.origin.y = (backgroundSize.height - image.size.height)/2


        ctx.setBlendMode(.multiply)
        ctx.draw(image.cgImage!, in: imageRect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

0

Phiên bản Swift 3.0 của mã kỳ diệu của Anna:

extension UIImage{

    static func multiplyImageByConstantColor(image:UIImage,color:UIColor)-> UIImage {
        let backgroundSize = image.size
        UIGraphicsBeginImageContext(backgroundSize)

        let ctx = UIGraphicsGetCurrentContext()!

        var backgroundRect=CGRect()
        backgroundRect.size = backgroundSize
        backgroundRect.origin.x = 0
        backgroundRect.origin.y = 0

        let myFloatForR = 0
        var r = CGFloat(myFloatForR)
        let myFloatForG = 0
        var g = CGFloat(myFloatForG)
        let myFloatForB = 0
        var b = CGFloat(myFloatForB)
        let myFloatForA = 0
        var a = CGFloat(myFloatForA)

        color.getRed(&r, green: &g, blue: &b, alpha: &a)
        ctx.setFillColor(red: r, green: g, blue: b, alpha: a)
        ctx.fill(backgroundRect)

        var imageRect=CGRect()
        imageRect.size = image.size
        imageRect.origin.x = (backgroundSize.width - image.size.width)/2
        imageRect.origin.y = (backgroundSize.height - image.size.height)/2

        // Unflip the image
        ctx.translateBy(x: 0, y: backgroundSize.height)
        ctx.scaleBy(x: 1.0, y: -1.0)

        ctx.setBlendMode(.multiply)
        ctx.draw(image.cgImage!, in: imageRect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

0

Đối với iOS 13 và mới hơn:

let redImage = image.withTintColor(.red, renderingMode: .alwaysTemplate)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.