1 year ago

#45792

test-img

kientux

Force UIView to draw with specific scale (1 point = 1 pixel)

I'm doing a barcode printing feature, it generates a barcode view and then send the pixels data to the thermal printer. The process is below:

  1. Snapshot UIView with size 250x90 (points) to UIImage:
let renderer = UIGraphicsImageRenderer(bounds: view.bounds)
let image = renderer.image { rendererContext in
    view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}
  1. Get pixels data of output image:
extension UIImage {
    func pixelData() -> [UInt8]? {
        let height = self.size.height
        let width = self.size.width
        let dataSize = width * height
        var pixelData = [UInt8](repeating: 0, count: Int(dataSize))
        let colorSpace = CGColorSpaceCreateDeviceGray()
        let bitmapInfo: UInt32 = 0
        
        let context = CGContext(data: &pixelData,
                                width: Int(width),
                                height: Int(height),
                                bitsPerComponent: 8,
                                bytesPerRow: Int(width),
                                space: colorSpace,
                                bitmapInfo: bitmapInfo)
        guard let cgImage = self.cgImage else { return nil }
        context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
        
        return pixelData
    }
}
  1. Send pixelData to printer (after some process to convert it to printer data, like which pixel is black/white/gray...)

The problem is that, the size of the output bitmap must be fixed to 250x90 pixels, so it can be fit in the label stamp. But in high resolution iPhones with screen scale of 3x, after called pixelData() with 250x90 as width/height, the output CGImage will be downscale from original cgImage (because the original has 750x270 pixels). And because of downscaling, some black area become gray, and barcode becomes unrecognizable.

I can put the image.scale to pixelData() method, but that will make the pixels data to have the physical size of 750x270 pixels and it too large to fit in the label stamp.

I also tried this way to create UIImage but it still downscales and pixelates the output image:

// force 1.0 scale
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 1.0)
drawHierarchy(in: bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image

So the question is:

  • Can I force the UIView to be drawn with 1x scale, as 1 point = 1 pixel, and everything after that will working as expected?
  • Or can I adjust the pixels data generation so that context.draw can merge 3 pixels into 1?

ios

uiview

uiimage

cgcontext

cgimage

0 Answers

Your Answer

Accepted video resources