Mengubah warna UIImage

100

Saya mencoba mengubah warna UIImage. Kode saya:

-(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;
}

Kode ini berfungsi, tetapi gambar yang diperoleh tidak sebaik seharusnya: batas piksel gambar yang dikembalikan terputus-putus dan tidak semulus pada gambar pertama saya. Bagaimana cara mengatasi masalah ini?

RomanHouse
sumber
1
kemungkinan duplikat warna UIImage berubah?
idmean

Jawaban:

264

Sejak iOS 7, ini adalah cara paling sederhana untuk melakukannya.

Objective-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

Papan cerita:

Pertama, konfigurasikan gambar sebagai template (di bilah kanan - Render sebagai) di aset Anda. Kemudian warna gambar akan menjadi warna tint yang diterapkan. masukkan deskripsi gambar di sini

Ankish Jain
sumber
"UIImageRenderingModeAlwaysTemplate: Selalu gambar gambar sebagai gambar template, abaikan informasi warnanya." Bagus!
Tieme
3
Di Swift 2.0+theImageView.image? = (theImageView.image?.imageWithRenderingMode(.AlwaysTemplate))! theImageView.tintColor = UIColor.magentaColor()
ColossalChris
@AnkishJain apakah ada masalah kinerja seputar pendekatan ini?
Ríomhaire
3
Ini tidak mengubah warna gambar, tetapi menginstruksikan tampilan untuk merendernya dengan tint (warna) yang berbeda.
Steve Kuo
@Wle tidak juga. Anda benar-benar dapat menggunakan ini untuk UIImage apa pun. img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [button setTintColor:[UIColor redColor]]; [button setImage:img forState:UIControlStateNormal];@Anish terima kasih!
Motasim
31

Ini adalah jawaban di atas, tetapi sedikit dipersingkat. Ini hanya mengambil gambar sebagai topeng dan tidak benar-benar "memperbanyak" atau mewarnai gambar.

Tujuan 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();

Cepat:

    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()
pengguna1270061
sumber
2
Anda harus menggunakan UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);karena versi Anda hanya akan membuat grafik non retina.
Nikola Lajic
user1270061 adalah cara untuk melakukannya, menurut pengalaman saya. Jawaban lain dengan "burning" membutuhkan gambar sumber dengan warna tertentu rupanya. Yang ini hanya menggunakan nilai alfa dalam piksel sumber dan menggabungkannya dengan warna yang diinginkan - sempurna.
Jason
Sempurna - satu-satunya jawaban yang berhasil bagi saya. (16 Mei ')
trdavidson
10

Cara lain untuk mewarnai gambar adalah dengan mengalikannya dengan warna konstan. Terkadang, ini lebih disukai karena tidak "mengangkat" nilai warna di area hitam; itu menjaga intensitas relatif pada gambar tetap sama. Menggunakan overlay sebagai tint cenderung meratakan kontras.

Ini kode yang saya gunakan:

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;
}

Versi cepat

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
    }
}
Anna Dickinson
sumber
Solusi yang tepat yang saya cari! Terima kasih!
vir us
Bagaimana jika saya ingin membuat aplikasi lukis dinding virtual? ini berfungsi, bagaimana jika ingin hanya mewarnai dinding pada gambar. Silakan lihat tautan ini: - stackoverflow.com/questions/27482508/…
Shailesh
Ini bekerja jauh lebih baik daripada beberapa solusi lain di luar sana.
Matt Hudson
3
Ini hanya mewarnai latar belakang objek bagi saya, bukan objek itu sendiri.
pengguna3562927
7

Di Swift 3.0

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

Di Swift 2.0

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

Selamat menikmati Anda para pionir Swift

ColossalChris
sumber
5
Kode tidak apa-apa, tetapi posting tentang UIImage. Kami tidak selalu berurusan dengan UIImageViews.
HenryRootTwo
6

Solusi 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)
Charlton Provatas
sumber
5

Mulai dari iOS 10 Anda dapat menggunakan 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)
        }
    }

}
Murlakatam
sumber
3

Jika Anda tidak harus melakukannya secara terprogram, Anda bisa melakukannya menggunakan Xcode UI.

Jika Anda membuka gambar di folder aset gambar, buka inspektur di sisi kanan dan ada tarik-turun "Render Sebagai" dengan opsi berikut:

  1. Default
  2. Asli
  3. Template

Setelah Anda membuat pemilihan Template, Anda dapat mengubah tintColor gambar sesuka Anda - apakah itu menggunakan Xcode storyboard UI atau secara terprogram.

masukkan deskripsi gambar di sini

Lihat gambar ini:

masukkan deskripsi gambar di sini

Mario A Guzman
sumber
Apakah Anda menggunakan XCODE 8?
doxsi
2

Inilah adaptasi saya dari jawaban @ Anna. Dua poin penting di sini:

  • Gunakan destinationInblending mode
  • Panggilan UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)untuk mendapatkan gambar yang halus

Kode di 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!
    }
}
algrid.dll
sumber
2
mengapa Anda melewatkan gambar saat memperluas UIImage? Anda harus menghapus kata kunci statis dari metode Anda dan cukup gunakan selfdi dalam metode Anda dan hapus parameter gambar yang tidak perlu
Leo Dabus
1

Berdasarkan jawaban @ Anna dan saya menulis ulang untuk swift 2.2 dan menangani gambar dengan saluran alfa:

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
}
Bill Chan
sumber
0

Kode Anna berfungsi dengan baik untuk menyalin UIImage.image di atas latar belakang .image berwarna dengan menggunakan kCGBlendModeNormal daripada kCGBlendModeMultiply. Misalnya, self.mainImage.image = [self NormalImageByConstantColor: self.mainImage.image withColor: yourColor];akan menempatkan konten mainImage.image di atas tint yourColor sambil mempertahankan opacity yourColor. Ini memecahkan masalah saya menempatkan warna latar belakang dengan opasitas di belakang gambar untuk disimpan ke Rol Kamera.

Lowell Bahner
sumber
0

Cepat 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!
    }
}
Nursultan Askarbekuly
sumber
0

Versi Swift 3.0 dari kode menakjubkan 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!
    }
}
Matthieu
sumber
0

Untuk iOS 13 dan yang lebih baru:

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

berilium
sumber