iOS:在UIImage上添加羽毛和发光/阴影效果

4

我正在尝试找到一种方法,在iOS中对UIImage应用带有阴影的羽化效果,而不是UIImageView,我还没有找到完美的解决方案。我有一个想法,可能可以通过掩蔽来实现,但我对CoreGraphics非常陌生。

如果有人能够帮助。

谢谢。


展示你目前尝试过的内容以及你遇到的问题。 - rmaddy
我不知道应该尝试什么,这就是为什么我提出了这个问题..谢谢。 - iphonic
@bradlarson,你能帮忙吗? - iphonic
2个回答

4

好的,所以: 我也在寻找同样的东西,但不幸的是没有找到。 我决定创建自己的羽化代码。

将此代码添加到UIImage扩展中,然后调用[image featherImageWithDepth:4],4只是一个示例。 尽量保持深度尽可能低。

//==============================================================================


- (UIImage*)featherImageWithDepth:(int)featherDepth {

    // First get the image into your data buffer
    CGImageRef imageRef = [self CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);


    // Now your rawData contains the image data in the RGBA8888 pixel format.
    NSUInteger byteIndex = 0;



    NSUInteger rawDataCount = width*height;
    for (int i = 0 ; i < rawDataCount ; ++i, byteIndex += bytesPerPixel) {

        NSInteger alphaIndex = byteIndex + 3;

        if (rawData[alphaIndex] > 100) {

            for (int row = 1; row <= featherDepth; row++) {
                if (testBorderLayer((long)alphaIndex,
                                    rawData,
                                    (long)rawDataCount,
                                    (long)width,
                                    (long)height,
                                    row)) {

                    int destinationAlpha = 255 / (featherDepth+1) * (row + 1);
                    double alphaDiv =  (double)destinationAlpha / (double)rawData[alphaIndex];

                    rawData[alphaIndex] = destinationAlpha;
                    rawData[alphaIndex-1] = (double)rawData[alphaIndex-1] * alphaDiv;
                    rawData[alphaIndex-2] = (double)rawData[alphaIndex-2] * alphaDiv;
                    rawData[alphaIndex-3] = (double)rawData[alphaIndex-3] * alphaDiv;

//                    switch (row) {
//                        case 1:
//                            rawData[alphaIndex-1] = 255;
//                            rawData[alphaIndex-2] = 0;
//                            rawData[alphaIndex-3] = 0;
//                            break;
//                        case 2:
//                            rawData[alphaIndex-1] = 0;
//                            rawData[alphaIndex-2] = 255;
//                            rawData[alphaIndex-3] = 0;
//                            break;
//                        case 3:
//                            rawData[alphaIndex-1] = 0;
//                            rawData[alphaIndex-2] = 0;
//                            rawData[alphaIndex-3] = 255;
//                            break;
//                        case 4:
//                            rawData[alphaIndex-1] = 127;
//                            rawData[alphaIndex-2] = 127;
//                            rawData[alphaIndex-3] = 0;
//                            break;
//                        case 5:
//                            rawData[alphaIndex-1] = 127;
//                            rawData[alphaIndex-2] = 0;
//                            rawData[alphaIndex-3] = 127;
//                        case 6:
//                            rawData[alphaIndex-1] = 0;
//                            rawData[alphaIndex-2] = 127;
//                            rawData[alphaIndex-3] = 127;
//                            break;
//                        default:
//                            break;
//                    }

                    break;

                }
            }
        }
    }


    CGImageRef newCGImage = CGBitmapContextCreateImage(context);

    UIImage *result = [UIImage imageWithCGImage:newCGImage scale:[self scale] orientation:UIImageOrientationUp];

    CGImageRelease(newCGImage);

    CGContextRelease(context);
    free(rawData);

    return result;
}


//==============================================================================


bool testBorderLayer(long byteIndex,
                     unsigned char *imageData,
                     long dataSize,
                     long pWidth,
                     long pHeight,
                     int border) {


    int width = border * 2 + 1;
    int height = width - 2;

    // run thru border pixels
    // |-|
    // | |
    // |-|

    //top,bot - hor
    for (int i = 1; i < width - 1; i++) {


        long topIndex = byteIndex + 4 * ( - border * pWidth - border + i);
        long botIndex = byteIndex + 4 * ( border * pWidth - border + i);

        long destColl = byteIndex/4 % pWidth - border + i;

        if (destColl > 1 && destColl < pWidth) {
            if (testPoint(topIndex, imageData, dataSize) ||
                testPoint(botIndex, imageData, dataSize)) {
                return true;
            }

        }

    }


    //left,right - ver
    if (byteIndex / 4 % pWidth < pWidth - border - 1) {
        for (int k = 0; k < height; k++) {
            long rightIndex = byteIndex + 4 * ( border - (border) * pWidth + pWidth * k);

            if (testPoint(rightIndex, imageData, dataSize)) {
                return true;
            }
        }
    }

    if (byteIndex / 4 % pWidth > border) {

        for (int k = 0; k < height; k++) {
            long leftIndex = byteIndex + 4 * ( - border - (border) * pWidth + pWidth * k);

            if (testPoint(leftIndex, imageData, dataSize)) {
                return true;
            }
        }
    }

    return false;
}


//==============================================================================


bool testPoint(long pointIndex, unsigned char *imageData, long dataSize) {
    if (pointIndex >= 0 && pointIndex < dataSize * 4 - 1 &&
        imageData[pointIndex] < 30) {
        return true;
    }
    return false;
}

//==============================================================================

很抱歉评论很少 ;)


这段代码的目的是查找“边框”,通过遍历所有像素,如果当前像素是不透明的,而且相邻像素是透明的,则表示这是边框像素,并将alpha设置为255/深度。 如果相邻像素是不透明的,但是相邻像素的相邻像素(至少有一个)是透明的,则意味着当前像素是距离边框的第二个像素,其alpha设置为255/深度*2,以此类推。 - zurakach
太棒了!感谢您的贡献!我可以在我的项目中使用它吗?如果可以,那么它的许可证是什么? - Janusz Chudzynski
还要检查我提出的问题: https://dev59.com/847ea4cB1Zd3GeqPE7h6 - Janusz Chudzynski
1
Just copy and paste it :)) - zurakach
好的,正如你所说,我创建了一个名为UIImage+FeatheringImage.m的类扩展,并在实现文件中包含了你的代码,然后创建了一个uiimage *featheredImage = self.img,并进行了[featheredImage featherImageWithDepth:3]; 但它并没有在我的图像上产生任何羽化效果 :( 我做错了什么?你确定你的代码运行正确吗?@zurakach 谢谢。 - Reza.Ab
显示剩余5条评论

0

你能建议我使用哪个过滤器吗? - iphonic
CISpotLight可能是你正在寻找的东西。 - maelswarm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接