// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved. // // 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 CoreGraphics import Foundation // MARK: - BGR ↔ CGImage /// Builds a ``CGImage`` from row-major BGR uint8 (8-bit three-channel). enum BGRImageCodec { static func makeCGImageFromBGR(pixels: [UInt8], width: Int, height: Int) throws -> CGImage { let bytesPerPixel = 4 let bytesPerRow = width * bytesPerPixel let pixelCount = width * height guard pixels.count == pixelCount * 3 else { throw QuadTextCropError.imageCreationFailed } var rgbaData = [UInt8](repeating: 255, count: pixelCount * bytesPerPixel) for i in 0.. CGImage { guard polygon.count == 4, polygon.allSatisfy({ $0.count == 2 }) else { throw QuadTextCropError.invalidPolygon( "Expected 4 points with 2 coordinates each, got \(polygon.count) points" ) } let srcPixels = try extractBGRPixels(from: image) let srcW = image.width let srcH = image.height let polyValues: [NSValue] = polygon.map { NSValue(cgPoint: CGPoint(x: CGFloat($0[0]), y: CGFloat($0[1]))) } guard let out = PDBOpenCVImageBridge.quadTextLineCropBGR( Data(srcPixels), srcWidth: srcW, srcHeight: srcH, quad: polyValues ) else { throw QuadTextCropError.openCVFailed } let bytes = [UInt8](out.rgbData) return try BGRImageCodec.makeCGImageFromBGR(pixels: bytes, width: Int(out.width), height: Int(out.height)) } } // MARK: - Pixel Extraction & Image Creation private extension QuadTextCrop { /// Row-major HWC **BGR** static func extractBGRPixels(from image: CGImage) throws -> [UInt8] { let width = image.width let height = image.height let bytesPerPixel = 4 let bytesPerRow = width * bytesPerPixel var rgbaData = [UInt8](repeating: 0, count: height * bytesPerRow) guard let colorSpace = CGColorSpace(name: CGColorSpace.sRGB), let context = CGContext( data: &rgbaData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue ) else { throw QuadTextCropError.imageCreationFailed } context.draw(image, in: CGRect(x: 0, y: 0, width: width, height: height)) let pixelCount = width * height var bgrData = [UInt8](repeating: 0, count: pixelCount * 3) for i in 0..