最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

swift - Unwanted Padding in Image Created with NSBitmapImageRep Despite Manual Pixel Allocation - Stack Overflow

programmeradmin0浏览0评论

I am trying to create an NSImage in macOS using NSBitmapImageRep while having full control over its pixel data. Specifically, I want to:

Manually allocate and fill pixel data with a solid color.

Support both RGB (when hasAlpha = false) and RGBA (when hasAlpha = true).

Ensure no automatic padding is added when hasAlpha = false (i.e., the image should be stored in memory as tightly packed RGB data without extra unused bytes).

Avoid using NSGraphicsContext or CGContext, relying solely on NSBitmapImageRep to construct the image, because, based on what I learned from other questions and issues, NSGraphicsContext does not support RGB-only images.

Here is my function, but I still see unwanted padding added to my image. Here is the output of this code:

Expected Bytes Per Row: 3072 bytes/row
Actual Bytes Per Row: 4096 bytes/row
Image has padding! Extra 1024 bytes per row.

use case:

let size: NSSize = NSSize(width: 1024, height: 1024)

let myImage = createImage(hasAlpha: false, pixelSize: size, color: .red)

if let validImage: NSImage = myImage {
    if let tiffData: Data = validImage.tiffRepresentation, let nsBitmapImageRep: NSBitmapImageRep = NSBitmapImageRep(data: tiffData) {

        let expectedBytesPerRow = nsBitmapImageRep.samplesPerPixel*nsBitmapImageRep.pixelsWide
        let actualBytesPerRow = nsBitmapImageRep.bytesPerRow
        
        print("Expected Bytes Per Row: \(expectedBytesPerRow) bytes/row")
        print("Actual Bytes Per Row: \(actualBytesPerRow) bytes/row")
        
        if actualBytesPerRow > expectedBytesPerRow {
            print("Image has padding! Extra \(actualBytesPerRow - expectedBytesPerRow) bytes per row.")
        } else {
            print("No padding detected.")
        }
        
    }
}

func createImage(hasAlpha: Bool, pixelSize: NSSize, color: NSColor) -> NSImage? {
    
    let width = Int(pixelSize.width)
    let height = Int(pixelSize.height)
    let components = hasAlpha ? 4 : 3  // RGBA or RGB
    let bitsPerSample = 8
    let bytesPerPixel = components
    let bytesPerRow = width * bytesPerPixel  // Ensure exact memory layout, no padding

    // Allocate memory for pixel buffer
    guard let pixelData = malloc(height * bytesPerRow)?.assumingMemoryBound(to: UInt8.self) else {
        print("Failed to allocate memory.")
        return nil
    }

    defer { free(pixelData) }  // Free memory on function exit

    // Convert color to RGB space
    let colorSpace = NSColorSpace.deviceRGB
    guard let colorInRGB = color.usingColorSpace(colorSpace) else {
        print("Failed to convert color to RGB space.")
        return nil
    }

    let red = UInt8(colorInRGB.redComponent * 255)
    let green = UInt8(colorInRGB.greenComponent * 255)
    let blue = UInt8(colorInRGB.blueComponent * 255)
    let alpha = hasAlpha ? UInt8(colorInRGB.alphaComponent * 255) : 255

    // Fill pixel buffer manually
    for y in 0..<height {
        for x in 0..<width {
            let pixelIndex = (y * bytesPerRow) + (x * bytesPerPixel)
            pixelData[pixelIndex] = red
            pixelData[pixelIndex + 1] = green
            pixelData[pixelIndex + 2] = blue
            if hasAlpha {
                pixelData[pixelIndex + 3] = alpha
            }
        }
    }

    // Create a pointer to the pixel buffer
    var pixelDataPlane: UnsafeMutablePointer<UInt8>? = pixelData

    // Create NSBitmapImageRep without extra padding
    guard let bitmapRep = NSBitmapImageRep(
        bitmapDataPlanes: &pixelDataPlane,  // Pass pointer to pointer
        pixelsWide: width,
        pixelsHigh: height,
        bitsPerSample: bitsPerSample,
        samplesPerPixel: components,
        hasAlpha: hasAlpha,
        isPlanar: false,
        colorSpaceName: .deviceRGB,
        bytesPerRow: bytesPerRow,  // Prevent unwanted padding
        bitsPerPixel: bitsPerSample * bytesPerPixel
    ) else {
        print("Failed to create bitmap representation.")
        return nil
    }

    // Create final NSImage
    let image = NSImage(size: pixelSize)
    image.addRepresentation(bitmapRep)

    return image
}
发布评论

评论列表(0)

  1. 暂无评论