gpt4 book ai didi

ios - 如何更改 UIImage/UIImageView 的单个像素的颜色

转载 作者:行者123 更新时间:2023-12-01 17:37:22 25 4
gpt4 key购买 nike

我有一个 UIImageView 我已经应用了过滤器:

testImageView.layer.magnificationFilter = kCAFilterNearest;

以便单个像素可见。这个 UIImageView 在 UIScrollView 中,图像本身是 1000x1000。我使用以下代码来检测哪个像素被点击:

我首先设置了一个点击手势识别器:
UITapGestureRecognizer *scrollTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestureCaptured: )];
scrollTap.numberOfTapsRequired = 1;
[mainScrollView addGestureRecognizer:scrollTap];

然后使用点击的位置来生成点击 UIImageView 的像素的点击坐标:
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint = [gesture locationInView:testImageView];

NSLog(@"%f is X pixel num, %f is Y pixel num ; %f is width of imageview", (touchPoint.x/testImageView.bounds.size.width)*1000, (touchPoint.y/testImageView.bounds.size.width)*1000, testImageView.bounds.size.width);

}

我希望能够点击一个像素,并让它的颜色发生变化。但是,我发现的 StackOverflow 帖子都没有有效或过时的答案。但是,对于熟练的编码人员,您可以帮助我破译旧帖子以制作有效的东西,或者使用我上面的代码自行生成一个简单的修复程序,以检测 UIImageView 的哪个像素已被点击。

感谢所有帮助。

为 originaluser2 编辑:

在遵循 originaluser2 的帖子之后,当我在我的物理设备上通过他的示例 GitHub 项目运行代码时,运行代码可以完美运行。但是,当我在自己的应用程序中运行相同的代码时,我会遇到图像被替换为空白,并出现以下错误:
<Error>: Unsupported pixel description - 3 components, 16 bits-per-component, 64 bits-per-pixel
<Error>: CGBitmapContextCreateWithData: failed to create delegate.
<Error>: CGContextDrawImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
<Error>: CGBitmapContextCreateImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

该代码显然有效,正如我在手机上测试它所证明的那样。但是,相同的代码在我自己的项目中产生了一些问题。尽管我怀疑它们都是由一两个简单的中心问题引起的。我该如何解决这些错误?

最佳答案

您需要将此问题分解为多个步骤。

  • 获取触摸点在图像坐标系中的坐标
  • 获取要改变的像素的x和y位置
  • 创建位图上下文并用新颜色的组件替换给定像素的组件。

  • 首先,要获得触摸点在图像坐标系中的坐标——可以使用我在 UIImageView 上写的分类方法。 .这将返回 CGAffineTransform它将一个点从 View 坐标映射到图像坐标——取决于 View 的内容模式。
    @interface UIImageView (PointConversionCatagory)

    @property (nonatomic, readonly) CGAffineTransform viewToImageTransform;
    @property (nonatomic, readonly) CGAffineTransform imageToViewTransform;

    @end

    @implementation UIImageView (PointConversionCatagory)

    -(CGAffineTransform) viewToImageTransform {

    UIViewContentMode contentMode = self.contentMode;

    // failure conditions. If any of these are met – return the identity transform
    if (!self.image || self.frame.size.width == 0 || self.frame.size.height == 0 ||
    (contentMode != UIViewContentModeScaleToFill && contentMode != UIViewContentModeScaleAspectFill && contentMode != UIViewContentModeScaleAspectFit)) {
    return CGAffineTransformIdentity;
    }

    // the width and height ratios
    CGFloat rWidth = self.image.size.width/self.frame.size.width;
    CGFloat rHeight = self.image.size.height/self.frame.size.height;

    // whether the image will be scaled according to width
    BOOL imageWiderThanView = rWidth > rHeight;

    if (contentMode == UIViewContentModeScaleAspectFit || contentMode == UIViewContentModeScaleAspectFill) {

    // The ratio to scale both the x and y axis by
    CGFloat ratio = ((imageWiderThanView && contentMode == UIViewContentModeScaleAspectFit) || (!imageWiderThanView && contentMode == UIViewContentModeScaleAspectFill)) ? rWidth:rHeight;

    // The x-offset of the inner rect as it gets centered
    CGFloat xOffset = (self.image.size.width-(self.frame.size.width*ratio))*0.5;

    // The y-offset of the inner rect as it gets centered
    CGFloat yOffset = (self.image.size.height-(self.frame.size.height*ratio))*0.5;

    return CGAffineTransformConcat(CGAffineTransformMakeScale(ratio, ratio), CGAffineTransformMakeTranslation(xOffset, yOffset));
    } else {
    return CGAffineTransformMakeScale(rWidth, rHeight);
    }
    }

    -(CGAffineTransform) imageToViewTransform {
    return CGAffineTransformInvert(self.viewToImageTransform);
    }

    @end

    这里没有什么太复杂的东西,只是一些额外的比例调整/填充逻辑,以确保图像的居中被考虑在内。如果您在屏幕上以 1:1 的比例显示图像,则可以完全跳过此步骤。

    接下来,您需要获取要更改的像素的 x 和 y 位置。这很简单——你只想使用上面的类别属性 viewToImageTransform获取图像坐标系中的像素,然后使用 floor使值变得完整。
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewWasTapped:)];
    tapGesture.numberOfTapsRequired = 1;
    [imageView addGestureRecognizer:tapGesture];

    ...

    -(void) imageViewWasTapped:(UIGestureRecognizer*)tapGesture {

    if (!imageView.image) {
    return;
    }

    // get the pixel position
    CGPoint pt = CGPointApplyAffineTransform([tapGesture locationInView:imageView], imageView.viewToImageTransform);
    PixelPosition pixelPos = {(NSInteger)floor(pt.x), (NSInteger)floor(pt.y)};

    // replace image with new image, with the pixel replaced
    imageView.image = [imageView.image imageWithPixel:pixelPos replacedByColor:[UIColor colorWithRed:0 green:1 blue:1 alpha:1.0]];
    }

    最后,你会想要使用我的另一个分类方法—— imageWithPixel:replacedByColor:。用给定颜色的替换像素取出新图像。
    /// A simple struct to represent the position of a pixel
    struct PixelPosition {
    NSInteger x;
    NSInteger y;
    };

    typedef struct PixelPosition PixelPosition;

    @interface UIImage (UIImagePixelManipulationCatagory)

    @end

    @implementation UIImage (UIImagePixelManipulationCatagory)

    -(UIImage*) imageWithPixel:(PixelPosition)pixelPosition replacedByColor:(UIColor*)color {

    // components of replacement color – in a 255 UInt8 format (fairly standard bitmap format)
    const CGFloat* colorComponents = CGColorGetComponents(color.CGColor);
    UInt8* color255Components = calloc(sizeof(UInt8), 4);
    for (int i = 0; i < 4; i++) color255Components[i] = (UInt8)round(colorComponents[i]*255.0);

    // raw image reference
    CGImageRef rawImage = self.CGImage;

    // image attributes
    size_t width = CGImageGetWidth(rawImage);
    size_t height = CGImageGetHeight(rawImage);
    CGRect rect = {CGPointZero, {width, height}};

    // image format
    size_t bitsPerComponent = 8;
    size_t bytesPerRow = width*4;

    // the bitmap info
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;

    // data pointer – stores an array of the pixel components. For example (r0, b0, g0, a0, r1, g1, b1, a1 .... rn, gn, bn, an)
    UInt8* data = calloc(bytesPerRow, height);

    // get new RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create bitmap context
    CGContextRef ctx = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);

    // draw image into context (populating the data array while doing so)
    CGContextDrawImage(ctx, rect, rawImage);

    // get the index of the pixel (4 components times the x position plus the y position times the row width)
    NSInteger pixelIndex = 4*(pixelPosition.x+(pixelPosition.y*width));

    // set the pixel components to the color components
    data[pixelIndex] = color255Components[0]; // r
    data[pixelIndex+1] = color255Components[1]; // g
    data[pixelIndex+2] = color255Components[2]; // b
    data[pixelIndex+3] = color255Components[3]; // a

    // get image from context
    CGImageRef img = CGBitmapContextCreateImage(ctx);

    // clean up
    free(color255Components);
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    free(data);

    UIImage* returnImage = [UIImage imageWithCGImage:img];
    CGImageRelease(img);

    return returnImage;
    }

    @end

    这样做是首先以 255 UInt8 格式将要写入其中一个像素的颜色分量取出。接下来,它使用输入图像的给定属性创建一个新的位图上下文。

    这种方法的重要一点是:
    // get the index of the pixel (4 components times the x position plus the y position times the row width)
    NSInteger pixelIndex = 4*(pixelPosition.x+(pixelPosition.y*width));

    // set the pixel components to the color components
    data[pixelIndex] = color255Components[0]; // r
    data[pixelIndex+1] = color255Components[1]; // g
    data[pixelIndex+2] = color255Components[2]; // b
    data[pixelIndex+3] = color255Components[3]; // a

    这样做是获取给定像素的索引(基于像素的 x 和 y 坐标)——然后使用该索引用替换颜色的颜色分量替换该像素的分量数据。

    最后,我们从位图上下文中取出图像并进行一些清理。

    完成结果:

    enter image description here

    完整项目:https://github.com/hamishknight/Pixel-Color-Changing

    关于ios - 如何更改 UIImage/UIImageView 的单个像素的颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36576326/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com