diff --git a/mediapipe/tasks/ios/test/vision/utils/BUILD b/mediapipe/tasks/ios/test/vision/utils/BUILD index d117ad73d..0fca5c7e6 100644 --- a/mediapipe/tasks/ios/test/vision/utils/BUILD +++ b/mediapipe/tasks/ios/test/vision/utils/BUILD @@ -7,7 +7,21 @@ objc_library( srcs = ["sources/MPPImage+TestUtils.m"], hdrs = ["sources/MPPImage+TestUtils.h"], module_name = "MPPImageTestUtils", - deps = ["//mediapipe/tasks/ios/vision/core:MPPImage"], + deps = [ + "//mediapipe/tasks/ios/vision/core:MPPImage", + "//mediapipe/tasks/ios/test/utils:MPPFileInfo"], +) + +objc_library( + name = "MPPMaskTestUtils", + srcs = ["sources/MPPMask+TestUtils.m"], + hdrs = ["sources/MPPMask+TestUtils.h"], + module_name = "MPPMaskTestUtils", + deps = [ + "//mediapipe/tasks/ios/vision/core:MPPMask", + "//mediapipe/tasks/ios/test/utils:MPPFileInfo", + "//third_party/apple_frameworks:UIKit", + ] ) cc_library( diff --git a/mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.h b/mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.h new file mode 100644 index 000000000..066fcfa8a --- /dev/null +++ b/mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.h @@ -0,0 +1,42 @@ +// Copyright 2023 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import + +#import "mediapipe/tasks/ios/test/utils/sources/MPPFileInfo.h" +#import "mediapipe/tasks/ios/vision/core/sources/MPPMask.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Helper utility for initializing `MPPMask` for MediaPipe iOS vision library tests. + */ +@interface MPPMask (TestUtils) + +/** + * Loads an image from a file in an app bundle and Creates an `MPPMask` of type + * `MPPMaskDataTypeUInt8` using the gray scale pixel data of a `UIImage` loaded from a file with the + * given `MPPFileInfo`. + * + * @param fileInfo The file info specifying the name and type of the image file in the app bundle. + * + * @return The `MPPMask` with the pixel data of the loaded image. This method returns `nil` if there + * is an error in loading the image correctly. + */ +- (nullable instancetype)initWithImageFileInfo:(MPPFileInfo *)fileInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.m b/mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.m new file mode 100644 index 000000000..d57be8383 --- /dev/null +++ b/mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.m @@ -0,0 +1,63 @@ +// Copyright 2023 The MediaPipe Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "mediapipe/tasks/ios/test/vision/utils/sources/MPPMask+TestUtils.h" + +@implementation MPPMask (TestUtils) + +- (instancetype)initWithImageFileInfo:(MPPFileInfo *)fileInfo { + UIImage *image = [[UIImage alloc] initWithContentsOfFile:fileInfo.path]; + + if (!image.CGImage) { + return nil; + } + + size_t width = CGImageGetWidth(image.CGImage); + size_t height = CGImageGetHeight(image.CGImage); + + NSInteger bitsPerComponent = 8; + + UInt8 *pixelData = NULL; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + + // For a gray scale image (single component) with no alpha, the bitmap info is + // `kCGImageAlphaNone` in combination with bytesPerRow being equal to width. + CGContextRef context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, width, + colorSpace, kCGImageAlphaNone); + + if (!context) { + CGColorSpaceRelease(colorSpace); + return nil; + } + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage); + pixelData = (UInt8 *)CGBitmapContextGetData(context); + + // A copy is needed to ensure that the pixel data outlives the `CGContextRelease` call. + // Alternative is to make the context, color space instance variables and release them in + // `dealloc()`. Since Categories don't allow adding instance variables, choosing to copy rather + // than creating a new custom class similar to `MPPMask` only for the tests. + MPPMask *mask = [[MPPMask alloc] initWithUInt8Data:pixelData + width:width + height:height + shouldCopy:YES]; + + CGColorSpaceRelease(colorSpace); + CGContextRelease(context); + + return mask; +} + +@end \ No newline at end of file