You are an expert swift ios developer. Carefully think through the user's query and relevant code files provided to generate high-quality, reliable swift code which works with the rest of their application. provide code changes with their explicit locations for maximum accuracy and communication to the user. Context of the IOS app: the app you're working with is supposed to work like this UX: user opens app>user selects image from their camera roll>image is loaded into Image Viewer to display to the user but also encode into an Computer vision model called 'SAM2'>User taps to on the image to add a point> SAM2 takes in this point and generates an image mask on the image given the point>user presses "search" button and the image mask is exported as a .png to firebase. Given this context, please accomplish the task given in the user's query:
User query:"I'm receiving an error when I build my app. Please follow these instructions to fix the error while using the context of the rest of the app:To fix the error you're receiving:

Value of type 'MLShapedArray<Float16>' has no member 'cgImage'

You need to add an extension to MLShapedArray for Element == Float16 that provides the cgImage(min:max:) method. This method will convert the MLShapedArray&lt;Float16&gt; into a CGImage. Here's how you can do it:

1. Create a New File for the Extension

Add a new Swift file to your project named MLShapedArray+Image.swift.

2. Implement the Extension

In MLShapedArray+Image.swift, add the following code:


   import CoreML
   import CoreGraphics

   extension MLShapedArray where Element == Float16 {
       func cgImage(min: Double = 0, max: Double = 255) -> CGImage? {
           let shape = self.shape

           guard shape.count == 2 else {
               print("Expected a 2D array (height x width).")
               return nil
           }

           let height = shape[0].intValue
           let width = shape[1].intValue

           let totalCount = height * width

           let scalars = self.scalars

           guard scalars.count == totalCount else {
               print("Data count does not match total elements.")
               return nil
           }

           let minValue = min
           let maxValue = max
           let scaleFactor = 255.0 / (maxValue - minValue)

           var bytes = [UInt8](repeating: 0, count: totalCount)

           for index in 0..<totalCount {
               let value = Double(scalars[index])
               var scaled = (value - minValue) * scaleFactor
               scaled = max(0, min(255, scaled))
               bytes[index] = UInt8(scaled)
           }

           return CGImage.fromByteArrayGray(bytes, width: width, height: height)
       }
   }


3. Ensure CGImage.fromByteArrayGray is Available

   Make sure that you have the CGImage+RawBytes.swift file in your project with the following content (as you already have):

   import CoreGraphics

   extension CGImage {
     @nonobjc public class func fromByteArrayGray(_ bytes: [UInt8],
                                                  width: Int,
                                                  height: Int) -> CGImage? {
       return fromByteArray(bytes, width: width, height: height,
                            bytesPerRow: width,
                            colorSpace: CGColorSpaceCreateDeviceGray(),
                            alphaInfo: .none)
     }

     @nonobjc class func fromByteArray(_ bytes: [UInt8],
                                       width: Int,
                                       height: Int,
                                       bytesPerRow: Int,
                                       colorSpace: CGColorSpace,
                                       alphaInfo: CGImageAlphaInfo) -> CGImage? {
       return bytes.withUnsafeBytes { ptr in
         let context = CGContext(data: UnsafeMutableRawPointer(mutating: ptr.baseAddress!),
                                 width: width,
                                 height: height,
                                 bitsPerComponent: 8,
                                 bytesPerRow: bytesPerRow,
                                 space: colorSpace,
                                 bitmapInfo: alphaInfo.rawValue)
         return context?.makeImage()
       }
     }
   }


4. Update SAM2.swift

   Now, in your SAM2.swift file, the error should be resolved. The lowFeatureMask.cgImage(min:max:) call will now work because the cgImage(min:max:) method exists for MLShapedArray&lt;Float16&gt;.

   The updated code in getMask function should look like:

   if let maskcgImage = lowFeatureMask.cgImage(min: minValueDouble, max: maxValueDouble) {
       let ciImage = CIImage(cgImage: maskcgImage, options: [.colorSpace: NSNull()])
       let resizedImage = try resizeImage(ciImage, to: original_size, applyingThreshold: Float(threshold))
       return resizedImage?.maskedToAlpha()?.samTinted()
   }
   return nil


Explanation of the Fix

- Why the Error Occurred: The MLShapedArray&lt;Float16&gt; type doesn't inherently have a cgImage(min:max:) method, which led to the compilation error.

- Extending MLShapedArray: By adding an extension to MLShapedArray where Element == Float16, we provide the necessary functionality to convert the array's data into a CGImage.

- Creating the CGImage:
  - We access the scalars from the MLShapedArray, which gives us a ContiguousArray&lt;Float16&gt; containing all the data.
  - We calculate the scale factor based on the provided min and max values to normalize the data to the [0, 255] range.
  - We iterate over each scalar value, normalize it, and store it as a UInt8 in the bytes array.
  - We use the fromByteArrayGray function to create a grayscale CGImage from the bytes array.

Note on Future Compatibility

This solution is specific for MLShapedArray&lt;Float16&gt;. If you need to support other data types like Float32 or Double, you can add similar extensions for those types, adjusting the code accordingly.

Precautions for Future Errors

- Data Shape Verification: The extension assumes that the MLShapedArray has exactly 2 dimensions (height and width). If the data has a different shape, you might need to adjust the code to handle additional dimensions accordingly.

- Value Ranges: Ensure that the min and max values provided when calling cgImage(min:max:) accurately reflect the range of your data to prevent incorrect scaling.

- Memory Considerations: Be cautious with large arrays, as creating large byte arrays can consume significant memory.

By implementing this fix, your app should be able to compile and run without the previous error, and it will correctly generate image masks as per your app's workflow.
"
Here's the relevant app files for loading an image and generating an image mask:
file structure:
.
├── Assets.xcassets
│   ├── AccentColor.colorset
│   │   └── Contents.json
│   ├── AppIcon.appiconset
│   │   ├── Contents.json
│   │   ├── android-chrome-512x512 1.png
│   │   ├── android-chrome-512x512.png
│   │   ├── final-grid-shirt 1.jpg
│   │   └── final-grid-shirt.jpg
│   └── Contents.json
├── Common
│   ├── CGImage+Extension.swift
│   ├── CGImage+RawBytes.swift
│   ├── CoreImageExtensions.swift
│   ├── DirectoryDocument.swift
│   ├── MLMultiArray+Image.swift
│   ├── Models.swift
│   ├── SAM2.swift
│   └── UIImage+Extension.swift
├── ContentView.swift
├── CoreMLModels
│   ├── SAM2SmallImageEncoderFLOAT16.mlpackage
│   │   ├── Data
│   │   │   └── com.apple.CoreML
│   │   │       ├── model.mlmodel
│   │   │       └── weights
│   │   │           └── weight.bin
│   │   └── Manifest.json
│   ├── SAM2SmallMaskDecoderFLOAT16.mlpackage
│   │   ├── Data
│   │   │   └── com.apple.CoreML
│   │   │       ├── model.mlmodel
│   │   │       └── weights
│   │   │           └── weight.bin
│   │   └── Manifest.json
│   └── SAM2SmallPromptEncoderFLOAT16.mlpackage
│       ├── Data
│       │   └── com.apple.CoreML
│       │       ├── model.mlmodel
│       │       └── weights
│       │           └── weight.bin
│       └── Manifest.json
├── GoogleService-Info.plist
├── ImagePageModel.swift
├── Info.plist
├── Managers
│   ├── CloudinaryHelper.swift
│   └── ImageUploader.swift
├── Models
│   └── SearchResponse.swift
├── Package
│   └── SegmentAnyThing
├── Page.swift
├── Preview Content
│   └── Preview Assets.xcassets
│       └── Contents.json
├── SegmentAnythingDemo.entitlements
├── SegmentAnythingDemoApp.swift
├── Views
│   ├── ImageView.swift
│   └── SearchResults.swift
├── demo.jpg
└── detail
    ├── DetailCompositor.metal
    ├── DetailCompositorFilter.swift
    ├── DetailView.swift
    ├── DetailViewModel.swift
    └── LoadingView.swift


file:'detail/DetailView.swift':```
import SwiftUI
import CIImageViewer

struct DetailView: View {
    @Binding var imagePageModel: ImagePageModel
    let onDismiss: () -> Void

    @StateObject var viewModel: DetailViewModel
    @State private var currentTool: Tool = .includePoint
    @State private var isResetActive = false
    @State private var backgroundDisplayAmount: Double = 0.3
    @State private var showingSearchResults = false
    @State private var isLoading = false

    // State variable to control overlay visibility
    @State private var showTapToSelectOverlay = false

    private enum Tool {
        case includePoint, excludePoint
    }

    init(imagePageModel: Binding<ImagePageModel>, onDismiss: @escaping () -> Void) {
        self._imagePageModel = imagePageModel
        self.onDismiss = onDismiss
        self._viewModel = StateObject(
            wrappedValue: DetailViewModel(
                initialCiImage: imagePageModel.wrappedValue.inputImage,
                backgroundPercent: 0.3
            )
        )
    }

    private func onImageTap(location: CGPoint) {
        print("Tapped at location: \(location), imageSize: \(viewModel.imageSize)")
        let normalizedPoint = CGPoint(
            x: location.x / viewModel.imageSize.width,
            y: location.y / viewModel.imageSize.height
        )
        print("Normalized point: \(normalizedPoint)")
        switch currentTool {
        case .includePoint:
            print("Including point")
            viewModel.includePoint(cgPoint: normalizedPoint)
        case .excludePoint:
            print("Excluding point")
            viewModel.excludePoint(cgPoint: normalizedPoint)
        }
    }

    var body: some View {
        ZStack {
            Color.black.edgesIgnoringSafeArea(.all)

            VStack {
                HStack {
                    Button(action: onDismiss) {
                        Image(systemName: "chevron.left")
                            .foregroundColor(.white)
                            .padding()
                    }
                    Spacer()
                }

                Spacer()

                ZStack {
                    CIImageViewer(image: viewModel.renderingCiImage, onTap: { location in
                        onImageTap(location: location)
                    })
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color.black)
                    .edgesIgnoringSafeArea(.all)

                    // Overlay displaying "Tap to Select" text over the entire image view
                    if showTapToSelectOverlay {
                        Color.black.opacity(0.5)
                            .edgesIgnoringSafeArea(.all)
                            .overlay(
                                Text("Tap to Select")
                                    .foregroundColor(.white)
                                    .font(.system(size: 24, weight: .semibold))
                                    .padding()
                            )
                    }
                }

                Spacer()

                HStack {
                    Button(action: {
                        isResetActive = true
                        viewModel.reset()
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                            isResetActive = false
                        }
                    }) {
                        Image(systemName: "arrow.counterclockwise")
                            .foregroundColor(isResetActive ? .black : .white)
                            .frame(width: 44, height: 44)
                    }
                    .buttonStyle(CustomButtonStyle(isActive: isResetActive))

                    Spacer()

                    Button(action: { currentTool = .includePoint }) {
                        Image(systemName: "plus")
                            .foregroundColor(currentTool == .includePoint ? .black : .white)
                            .frame(width: 44, height: 44)
                    }
                    .buttonStyle(CustomButtonStyle(isActive: currentTool == .includePoint))

                    Button(action: { currentTool = .excludePoint }) {
                        Image(systemName: "minus")
                            .foregroundColor(currentTool == .excludePoint ? .black : .white)
                            .frame(width: 44, height: 44)
                    }
                    .buttonStyle(CustomButtonStyle(isActive: currentTool == .excludePoint))

                    Spacer()

                    Button(action: {
                        Task { @MainActor in
                            self.isLoading = true
                            if let _ = await viewModel.saveMaskAsPNG() {
                                await viewModel.uploadMaskToCloudinary()
                                await viewModel.performGoogleLensSearch()
                                showingSearchResults = true
                            }
                            self.isLoading = false
                        }
                    }) {
                        Text("Search")
                            .foregroundColor(.white)
                            .frame(width: 100, height: 44)
                    }
                    .buttonStyle(CustomButtonStyle(isActive: false))
                }
                .padding(.horizontal)
                .padding(.bottom, 30)
            }
        }
        .onAppear {
            // Show the overlay when the view appears
            self.showTapToSelectOverlay = true
            // Hide the overlay after 1 second
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                self.showTapToSelectOverlay = false
            }
        }
        .onChange(of: backgroundDisplayAmount) { newValue in
            viewModel.backgroundPercent = newValue
        }
        .sheet(isPresented: $showingSearchResults) {
            SearchResultView(searchResult: $viewModel.searchResponse)
        }
        .overlay() {
            if self.isLoading {
                LoadingView()
            }
        }
    }
}

struct CustomButtonStyle: ButtonStyle {
    var isActive: Bool

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .background(isActive ? Color.white : Color.clear)
            .cornerRadius(22)
            .overlay(
                RoundedRectangle(cornerRadius: 22)
                    .stroke(Color.white, lineWidth: 2)
            )
    }
}
```
file:'Common/SAM2.swift':```
// Common/SAM2.swift

import SwiftUI
import CoreML
import CoreImage
import CoreImage.CIFilterBuiltins
import Combine
import UniformTypeIdentifiers

@MainActor
class SAM2: ObservableObject {

    @Published var imageEncodings: SAM2SmallImageEncoderFLOAT16Output?
    @Published var promptEncodings: SAM2SmallPromptEncoderFLOAT16Output?

    @Published private(set) var initializationTime: TimeInterval?
    @Published private(set) var initialized: Bool?

    private var imageEncoderModel: SAM2SmallImageEncoderFLOAT16?
    private var promptEncoderModel: SAM2SmallPromptEncoderFLOAT16?
    private var maskDecoderModel: SAM2SmallMaskDecoderFLOAT16?

    var inputSize: CGSize { CGSize(width: 1024, height: 1024) }
    var width: CGFloat { inputSize.width }
    var height: CGFloat { inputSize.height }

    init() {
        Task {
            await loadModels()
        }
    }

    private func loadModels() async {
        let startTime = CFAbsoluteTimeGetCurrent()
        do {
            let configuration = MLModelConfiguration()
            configuration.computeUnits = .cpuOnly

            let bundle = Bundle.main

            guard let imageEncoderURL = bundle.url(forResource: "SAM2SmallImageEncoderFLOAT16", withExtension: "mlpackage"),
                  let promptEncoderURL = bundle.url(forResource: "SAM2SmallPromptEncoderFLOAT16", withExtension: "mlpackage"),
                  let maskDecoderURL = bundle.url(forResource: "SAM2SmallMaskDecoderFLOAT16", withExtension: "mlpackage") else {
                throw SAM2Error.modelPathNotFound
            }

            print("Loading Image Encoder Model from: \(imageEncoderURL)")
            let imageEncoder = try SAM2SmallImageEncoderFLOAT16(contentsOf: imageEncoderURL, configuration: configuration)
            print("Image Encoder Model loaded successfully.")

            print("Loading Prompt Encoder Model from: \(promptEncoderURL)")
            let promptEncoder = try SAM2SmallPromptEncoderFLOAT16(contentsOf: promptEncoderURL, configuration: configuration)
            print("Prompt Encoder Model loaded successfully.")

            print("Loading Mask Decoder Model from: \(maskDecoderURL)")
            let maskDecoder = try SAM2SmallMaskDecoderFLOAT16(contentsOf: maskDecoderURL, configuration: configuration)
            print("Mask Decoder Model loaded successfully.")

            self.imageEncoderModel = imageEncoder
            self.promptEncoderModel = promptEncoder
            self.maskDecoderModel = maskDecoder

            let endTime = CFAbsoluteTimeGetCurrent()
            self.initializationTime = endTime - startTime
            self.initialized = true
            print("All models loaded successfully in \(String(format: "%.2f", self.initializationTime!)) seconds")
        } catch {
            print("Failed to initialize models: \(error)")
            self.initializationTime = nil
            self.initialized = false
        }
    }

    func getImageEncoding(from pixelBuffer: CVPixelBuffer) async throws {
        guard let model = imageEncoderModel else {
            throw SAM2Error.modelNotLoaded
        }

        let encoding = try model.prediction(image: pixelBuffer)
        self.imageEncodings = encoding
    }

    func getPromptEncoding(from allPoints: [SAMPoint], with size: CGSize) async throws {
        guard let model = promptEncoderModel else {
            throw SAM2Error.modelNotLoaded
        }

        let transformedCoords = try transformCoords(allPoints.map { $0.coordinates }, normalize: false, origHW: size)

        // Create MLFeatureProvider with the required input format
        let pointsMultiArray = try MLMultiArray(shape: [1, NSNumber(value: allPoints.count), 2], dataType: .float32)
        let labelsMultiArray = try MLMultiArray(shape: [1, NSNumber(value: allPoints.count)], dataType: .int32)

        for (index, point) in transformedCoords.enumerated() {
            pointsMultiArray[[0, index, 0] as [NSNumber]] = NSNumber(value: Float(point.x))
            pointsMultiArray[[0, index, 1] as [NSNumber]] = NSNumber(value: Float(point.y))
            labelsMultiArray[[0, index] as [NSNumber]] = NSNumber(value: allPoints[index].category.type.rawValue)
        }

        let encoding = try model.prediction(points: pointsMultiArray, labels: labelsMultiArray)
        self.promptEncodings = encoding
    }

    func getMask(for original_size: CGSize) async throws -> CIImage? {
        guard let model = maskDecoderModel else {
            throw SAM2Error.modelNotLoaded
        }

        guard let image_embedding = self.imageEncodings?.image_embedding,
              let feats0 = self.imageEncodings?.feats_s0,
              let feats1 = self.imageEncodings?.feats_s1,
              let sparse_embedding = self.promptEncodings?.sparse_embeddings,
              let dense_embedding = self.promptEncodings?.dense_embeddings else {
            throw SAM2Error.missingEncodings
        }

        do {
            let output = try model.prediction(
                image_embedding: image_embedding,
                sparse_embedding: sparse_embedding,
                dense_embedding: dense_embedding,
                feats_s0: feats0,
                feats_s1: feats1
            )

            // Extract best mask and ignore the others
            let lowFeatureMask = bestMask(for: output)

            // Access scalar values of the mask using .scalars
            let scalars = lowFeatureMask.scalars
            let minValue = scalars.min() ?? Float16(0.0)
            let maxValue = scalars.max() ?? Float16(1.0)

            // Convert Float16 to Double for arithmetic operations
            let minValueDouble = Double(minValue)
            let maxValueDouble = Double(maxValue)
            let denominator = maxValueDouble - minValueDouble
            guard denominator != 0 else {
                // Handle division by zero
                return nil
            }
            let threshold = -minValueDouble / denominator

            // Resize first, then threshold
            if let maskcgImage = lowFeatureMask.cgImage(min: minValueDouble, max: maxValueDouble) {
                let ciImage = CIImage(cgImage: maskcgImage, options: [.colorSpace: NSNull()])
                let resizedImage = try resizeImage(ciImage, to: original_size, applyingThreshold: Float(threshold))
                return resizedImage?.maskedToAlpha()?.samTinted()
            }
            return nil
        } catch {
            print("Error during mask prediction: \(error)")
            throw error
        }
    }

    private func bestMask(for output: SAM2SmallMaskDecoderFLOAT16Output) -> MLShapedArray<Float16> {
        let scores = output.scoresShapedArray[0]
        let scoresArray = scores.scalars
        let argmax = scoresArray.enumerated().max(by: { $0.element < $1.element })?.offset ?? 0
        let maskSlice = output.low_res_masksShapedArray[0, argmax]
        let maskArray = MLShapedArray<Float16>(converting: maskSlice)
        return maskArray
    }

    private func transformCoords(_ coords: [CGPoint], normalize: Bool = false, origHW: CGSize) throws -> [CGPoint] {
        if normalize {
            let w = origHW.width
            let h = origHW.height

            return coords.map { coord in
                let normalizedX = coord.x / w
                let normalizedY = coord.y / h
                return CGPoint(x: normalizedX * width, y: normalizedY * height)
            }
        } else {
            return coords.map { CGPoint(x: $0.x * width, y: $0.y * height) }
        }
    }

    private func resizeImage(_ image: CIImage, to size: CGSize, applyingThreshold threshold: Float = 1) throws -> CIImage? {
        let scale = CGAffineTransform(scaleX: size.width / image.extent.width,
                                      y: size.height / image.extent.height)
        return image.transformed(by: scale).applyingThreshold(threshold)
    }
}

extension CIImage {
    func maskedToAlpha() -> CIImage? {
        let filter = CIFilter.maskToAlpha()
        filter.inputImage = self
        return filter.outputImage
    }

    func samTinted() -> CIImage? {
        let filter = CIFilter.colorMatrix()
        filter.rVector = CIVector(x: 30/255, y: 0, z: 0, w: 1)
        filter.gVector = CIVector(x: 0, y: 144/255, z: 0, w: 1)
        filter.bVector = CIVector(x: 0, y: 0, z: 1, w: 1)
        filter.biasVector = CIVector(x: -1, y: -1, z: -1, w: 0)
        filter.inputImage = self
        return filter.outputImage?.cropped(to: self.extent)
    }

    func applyingThreshold(_ threshold: Float) -> CIImage? {
        let thresholdKernelString = """
        kernel vec4 thresholdKernel(__sample image, float threshold) {
            float luma = dot(image.rgb, vec3(0.299, 0.587, 0.114));
            float mask = luma > threshold ? 1.0 : 0.0;
            return vec4(mask, mask, mask, 1.0);
        }
        """
        guard let thresholdKernel = CIColorKernel(source: thresholdKernelString) else {
            return nil
        }
        return thresholdKernel.apply(extent: self.extent, arguments: [self, threshold])
    }
}

enum SAM2Error: Error {
    case modelNotLoaded
    case pixelBufferCreationFailed
    case imageResizingFailed
    case missingEncodings
    case modelPathNotFound
}

```
file:'MLMultiArray+Image.swift':```
import Accelerate
import CoreML

public func clamp<T: Comparable>(_ x: T, min: T, max: T) -> T {
  if x < min { return min }
  if x > max { return max }
  return x
}

public protocol MultiArrayType: Comparable {
  static var multiArrayDataType: MLMultiArrayDataType { get }
  static func +(lhs: Self, rhs: Self) -> Self
  static func -(lhs: Self, rhs: Self) -> Self
  static func *(lhs: Self, rhs: Self) -> Self
  static func /(lhs: Self, rhs: Self) -> Self
  init(_: Int)
  var toUInt8: UInt8 { get }
}

extension Double: MultiArrayType {
  public static var multiArrayDataType: MLMultiArrayDataType { return .double }
  public var toUInt8: UInt8 { return UInt8(self) }
}

extension Float: MultiArrayType {
  public static var multiArrayDataType: MLMultiArrayDataType { return .float32 }
  public var toUInt8: UInt8 { return UInt8(self) }
}

extension Int32: MultiArrayType {
  public static var multiArrayDataType: MLMultiArrayDataType { return .int32 }
  public var toUInt8: UInt8 { return UInt8(self) }
}

extension Float16: MultiArrayType {
    public static var multiArrayDataType: MLMultiArrayDataType { return .float16 }
    public var toUInt8: UInt8 { return UInt8(self) }
}

extension MLMultiArray {
  /**
    Converts the multi-array to a CGImage.

    The multi-array must have at least 2 dimensions for a grayscale image, or
    at least 3 dimensions for a color image.

    The default expected shape is (height, width) or (channels, height, width).
    However, you can change this using the `axes` parameter. For example, if
    the array shape is (1, height, width, channels), use `axes: (3, 1, 2)`.

    If `channel` is not nil, only converts that channel to a grayscale image.
    This lets you visualize individual channels from a multi-array with more
    than 4 channels.

    Otherwise, converts all channels. In this case, the number of channels in
    the multi-array must be 1 for grayscale, 3 for RGB, or 4 for RGBA.

    Use the `min` and `max` parameters to put the values from the array into
    the range [0, 255], if not already:

    - `min`: should be the smallest value in the data; this will be mapped to 0.
    - `max`: should be the largest value in the data; will be mapped to 255.

    For example, if the range of the data in the multi-array is [-1, 1], use
    `min: -1, max: 1`. If the range is already [0, 255], then use the defaults.
  */
  public func cgImage(min: Double = 0,
                      max: Double = 255,
                      channel: Int? = nil,
                      axes: (Int, Int, Int)? = nil) -> CGImage? {
    switch self.dataType {
    case .double:
      return _image(min: min, max: max, channel: channel, axes: axes)
    case .float32:
      return _image(min: Float(min), max: Float(max), channel: channel, axes: axes)
    case .int32:
      return _image(min: Int32(min), max: Int32(max), channel: channel, axes: axes)
    case .float16:
        return _image(min: Float16(min), max: Float16(max), channel: channel, axes: axes)
    @unknown default:
      fatalError("Unsupported data type \(dataType.rawValue)")
    }
  }

  /**
    Helper function that allows us to use generics. The type of `min` and `max`
    is also the dataType of the MLMultiArray.
  */
  private func _image<T: MultiArrayType>(min: T,
                                         max: T,
                                         channel: Int?,
                                         axes: (Int, Int, Int)?) -> CGImage? {
    if let (b, w, h, c) = toRawBytes(min: min, max: max, channel: channel, axes: axes) {
      if c == 1 {
        return CGImage.fromByteArrayGray(b, width: w, height: h)
      } else {
        return CGImage.fromByteArrayRGBA(b, width: w, height: h)
      }
    }
    return nil
  }

  /**
    Converts the multi-array into an array of RGBA or grayscale pixels.

    - Note: This is not particularly fast, but it is flexible. You can change
            the loops to convert the multi-array whichever way you please.

    - Note: The type of `min` and `max` must match the dataType of the
            MLMultiArray object.

    - Returns: tuple containing the RGBA bytes, the dimensions of the image,
               and the number of channels in the image (1, 3, or 4).
  */
  public func toRawBytes<T: MultiArrayType>(min: T,
                                            max: T,
                                            channel: Int? = nil,
                                            axes: (Int, Int, Int)? = nil)
                  -> (bytes: [UInt8], width: Int, height: Int, channels: Int)? {
    // MLMultiArray with unsupported shape?
    if shape.count < 2 {
      print("Cannot convert MLMultiArray of shape \(shape) to image")
      return nil
    }

    // Figure out which dimensions to use for the channels, height, and width.
    let channelAxis: Int
    let heightAxis: Int
    let widthAxis: Int
    if let axes = axes {
      channelAxis = axes.0
      heightAxis = axes.1
      widthAxis = axes.2
      guard channelAxis >= 0 && channelAxis < shape.count &&
            heightAxis >= 0 && heightAxis < shape.count &&
            widthAxis >= 0 && widthAxis < shape.count else {
        print("Invalid axes \(axes) for shape \(shape)")
        return nil
      }
    } else if shape.count == 2 {
      // Expected shape for grayscale is (height, width)
      heightAxis = 0
      widthAxis = 1
      channelAxis = -1 // Never be used
    } else {
      // Expected shape for color is (channels, height, width)
      channelAxis = 0
      heightAxis = 1
      widthAxis = 2
    }

    let height = self.shape[heightAxis].intValue
    let width = self.shape[widthAxis].intValue
    let yStride = self.strides[heightAxis].intValue
    let xStride = self.strides[widthAxis].intValue

    let channels: Int
    let cStride: Int
    let bytesPerPixel: Int
    let channelOffset: Int

    // MLMultiArray with just two dimensions is always grayscale. (We ignore
    // the value of channelAxis here.)
    if shape.count == 2 {
      channels = 1
      cStride = 0
      bytesPerPixel = 1
      channelOffset = 0

    // MLMultiArray with more than two dimensions can be color or grayscale.
    } else {
      let channelDim = self.shape[channelAxis].intValue
      if let channel = channel {
        if channel < 0 || channel >= channelDim {
          print("Channel must be -1, or between 0 and \(channelDim - 1)")
          return nil
        }
        channels = 1
        bytesPerPixel = 1
        channelOffset = channel
      } else if channelDim == 1 {
        channels = 1
        bytesPerPixel = 1
        channelOffset = 0
      } else {
        if channelDim != 3 && channelDim != 4 {
          print("Expected channel dimension to have 1, 3, or 4 channels, got \(channelDim)")
          return nil
        }
        channels = channelDim
        bytesPerPixel = 4
        channelOffset = 0
      }
      cStride = self.strides[channelAxis].intValue
    }

    // Allocate storage for the RGBA or grayscale pixels. Set everything to
    // 255 so that alpha channel is filled in if only 3 channels.
    let count = height * width * bytesPerPixel
    var pixels = [UInt8](repeating: 255, count: count)

    // Grab the pointer to MLMultiArray's memory.
    var ptr = UnsafeMutablePointer<T>(OpaquePointer(self.dataPointer))
    ptr = ptr.advanced(by: channelOffset * cStride)

    // Loop through all the pixels and all the channels and copy them over.
    for c in 0..<channels {
      for y in 0..<height {
        for x in 0..<width {
          let value = ptr[c*cStride + y*yStride + x*xStride]
          let scaled = (value - min) * T(255) / (max - min)
          let pixel = clamp(scaled, min: T(0), max: T(255)).toUInt8
          pixels[(y*width + x)*bytesPerPixel + c] = pixel
        }
      }
    }
    return (pixels, width, height, channels)
  }
}

/**
  Fast conversion from MLMultiArray to CGImage using the vImage framework.

  - Parameters:
    - features: A multi-array with data type FLOAT32 and three dimensions
                (3, height, width).
    - min: The smallest value in the multi-array. This value, as well as any
           smaller values, will be mapped to 0 in the output image.
    - max: The largest value in the multi-array. This and any larger values
           will be will be mapped to 255 in the output image.

  - Returns: a new CGImage or nil if the conversion fails
*/
public func createCGImage(fromFloatArray features: MLMultiArray,
                          min: Float = 0,
                          max: Float = 255) -> CGImage? {
  assert(features.dataType == .float32)
  assert(features.shape.count == 3)

  let ptr = UnsafeMutablePointer<Float>(OpaquePointer(features.dataPointer))

  let height = features.shape[1].intValue
  let width = features.shape[2].intValue
  let channelStride = features.strides[0].intValue
  let rowStride = features.strides[1].intValue
  let srcRowBytes = rowStride * MemoryLayout<Float>.stride

  var blueBuffer = vImage_Buffer(data: ptr,
                                 height: vImagePixelCount(height),
                                 width: vImagePixelCount(width),
                                 rowBytes: srcRowBytes)
  var greenBuffer = vImage_Buffer(data: ptr.advanced(by: channelStride),
                                  height: vImagePixelCount(height),
                                  width: vImagePixelCount(width),
                                  rowBytes: srcRowBytes)
  var redBuffer = vImage_Buffer(data: ptr.advanced(by: channelStride * 2),
                                height: vImagePixelCount(height),
                                width: vImagePixelCount(width),
                                rowBytes: srcRowBytes)

  let destRowBytes = width * 4

  var error: vImage_Error = 0
  var pixels = [UInt8](repeating: 0, count: height * destRowBytes)

  pixels.withUnsafeMutableBufferPointer { ptr in
    var destBuffer = vImage_Buffer(data: ptr.baseAddress!,
                                   height: vImagePixelCount(height),
                                   width: vImagePixelCount(width),
                                   rowBytes: destRowBytes)

    error = vImageConvert_PlanarFToBGRX8888(&blueBuffer,
                                            &greenBuffer,
                                            &redBuffer,
                                            Pixel_8(255),
                                            &destBuffer,
                                            [max, max, max],
                                            [min, min, min],
                                            vImage_Flags(0))
  }

  if error == kvImageNoError {
    return CGImage.fromByteArrayRGBA(pixels, width: width, height: height)
  } else {
    return nil
  }
}
```
file:'UIImage+Extension.swift':```
import UIKit
import VideoToolbox

extension UIImage {
    func pixelBuffer() -> CVPixelBuffer? {
        return pixelBuffer(width: Int(size.width), height: Int(size.height))
    }

    func pixelBuffer(width: Int, height: Int) -> CVPixelBuffer? {
        return pixelBuffer(width: width, height: height,
                           pixelFormatType: kCVPixelFormatType_32BGRA,
                           colorSpace: CGColorSpaceCreateDeviceRGB(),
                           alphaInfo: .premultipliedFirst)
    }

    func pixelBuffer(width: Int, height: Int,
                     pixelFormatType: OSType,
                     colorSpace: CGColorSpace,
                     alphaInfo: CGImageAlphaInfo) -> CVPixelBuffer? {
        var pixelBuffer: CVPixelBuffer?
        let attrs = [
            kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue!,
            kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue!
        ] as CFDictionary
        CVPixelBufferCreate(kCFAllocatorDefault, width, height, pixelFormatType, attrs, &pixelBuffer)

        guard let buffer = pixelBuffer else { return nil }

        CVPixelBufferLockBaseAddress(buffer, [])
        let context = CGContext(data: CVPixelBufferGetBaseAddress(buffer),
                                width: width,
                                height: height,
                                bitsPerComponent: 8,
                                bytesPerRow: CVPixelBufferGetBytesPerRow(buffer),
                                space: colorSpace,
                                bitmapInfo: alphaInfo.rawValue)
        guard let context = context else {
            CVPixelBufferUnlockBaseAddress(buffer, [])
            return nil
        }

        UIGraphicsPushContext(context)
        self.draw(in: CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height)))
        UIGraphicsPopContext()
        CVPixelBufferUnlockBaseAddress(buffer, [])

        return buffer
    }
}
```
file:'CGImage+Extension.swift':```
import CoreImage
import VideoToolbox

extension CIImage {
    func toPixelBuffer(width: Int, height: Int) -> CVPixelBuffer? {
        let pixelFormat = kCVPixelFormatType_32BGRA
        let options: [CIImageOption: Any] = [CIImageOption.colorSpace: CGColorSpaceCreateDeviceRGB()]
        var pxbuffer: CVPixelBuffer?
        let attrs = [kCVPixelBufferCGImageCompatibilityKey: true,
                     kCVPixelBufferCGBitmapContextCompatibilityKey: true,
                     kCVPixelBufferIOSurfacePropertiesKey: [:]] as CFDictionary // Ensure no explicit strides
        let status = CVPixelBufferCreate(kCFAllocatorDefault, width, height, pixelFormat, attrs, &pxbuffer)
        guard status == kCVReturnSuccess, let buffer = pxbuffer else {
            print("Failed to create pixel buffer with status: \(status)")
            return nil
        }
        let context = CIContext()
        context.render(self, to: buffer, bounds: CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height)), colorSpace: CGColorSpaceCreateDeviceRGB())
        return buffer
    }
}
```
file;'CGImage+RawBytes.swift':```
import CoreGraphics

extension CGImage {
  /**
    Converts the image into an array of RGBA bytes.
  */
  @nonobjc public func toByteArrayRGBA() -> [UInt8] {
    var bytes = [UInt8](repeating: 0, count: width * height * 4)
    bytes.withUnsafeMutableBytes { ptr in
      if let colorSpace = colorSpace,
         let context = CGContext(
                    data: ptr.baseAddress,
                    width: width,
                    height: height,
                    bitsPerComponent: bitsPerComponent,
                    bytesPerRow: bytesPerRow,
                    space: colorSpace,
                    bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) {
        let rect = CGRect(x: 0, y: 0, width: width, height: height)
        context.draw(self, in: rect)
      }
    }
    return bytes
  }

  /**
    Creates a new CGImage from an array of RGBA bytes.
  */
  @nonobjc public class func fromByteArrayRGBA(_ bytes: [UInt8],
                                               width: Int,
                                               height: Int) -> CGImage? {
    return fromByteArray(bytes, width: width, height: height,
                         bytesPerRow: width * 4,
                         colorSpace: CGColorSpaceCreateDeviceRGB(),
                         alphaInfo: .premultipliedLast)
  }

  /**
    Creates a new CGImage from an array of grayscale bytes.
  */
  @nonobjc public class func fromByteArrayGray(_ bytes: [UInt8],
                                               width: Int,
                                               height: Int) -> CGImage? {
    return fromByteArray(bytes, width: width, height: height,
                         bytesPerRow: width,
                         colorSpace: CGColorSpaceCreateDeviceGray(),
                         alphaInfo: .none)
  }

  @nonobjc class func fromByteArray(_ bytes: [UInt8],
                                    width: Int,
                                    height: Int,
                                    bytesPerRow: Int,
                                    colorSpace: CGColorSpace,
                                    alphaInfo: CGImageAlphaInfo) -> CGImage? {
    return bytes.withUnsafeBytes { ptr in
      let context = CGContext(data: UnsafeMutableRawPointer(mutating: ptr.baseAddress!),
                              width: width,
                              height: height,
                              bitsPerComponent: 8,
                              bytesPerRow: bytesPerRow,
                              space: colorSpace,
                              bitmapInfo: alphaInfo.rawValue)
      return context?.makeImage()
    }
  }
}
```
Carefully analyze my app and the demo app files above to think through how my app should be modified to correctly accomplish the task given in the user's query at the beginning of this message:

Think step by step thorugh the user's task given all of the context: