MTLTextureをpngファイルで保存するとなぜかサイズ(w, h)が大きくなる
サイズがw x hのMTLTextureがあるとする。
これを以下のようにしてpngで保存する。
保存したpngファイルのサイズを確認すると(w x 3 , h x 3)になってる。
3倍になってるのは私のiPhone 12 Pro Maxの場合で、これがiPadだと(w x 2, h x 3)なのでUIScreen.main.scaleの値が効いてるのかもしれない。ともかく2倍なり3倍で保存されるのは具合が悪い。
ios - Saving and Loading MTLTexture as PNG - Stack Overflow
↑同じような感じで困ってる人の投稿があったが回答はなし、、、(よくあるよね)
MTLTextureから上記の処理で作成したUIImageオブジェクトにはCGImageがない。
uiimage.cgImageはnilだ。
なのでCGImageを作成してみた。
cocoa - CGImage from byte array - Stack Overflow
↑この記事の下の方にSwiftでのコードがあるので参考にした。
MTLTextureからデータ配列を作成するには
getBytes(_:bytesPerRow:from:mipmapLevel:)
を使用。
コードはこんな感じになった↓
このメソッドを使い、同様にpngファイルで保存を試みた。
let cgImage = makeCGImageFromMTLTexture(mtlTexture)
let uiimage = UIImage(cgImage: cgImage)
let data = uiimage.pngData()!
try! data.write(to: url)
すると無事にサイズは3倍などにはならずに意図通りのサイズで作成できた。
しかし、、、色がおかしい!
MTLTexture から CGImage を生成 - Qiita
↑調べたらこちらの記事と同じことかな、と思い入れ替える処理を実装すれば無事に正しい色で表示された!
その場合のメソッドは以下のような感じ。
これを以下のようにしてpngで保存する。
let ciImage = CIImage(mtlTexture: mtlTexture, options: nil)!
let uiimage = UIImage(ciImage: ciImage)
let data = uiimage.pngData()!
try! data.write(to: url)
保存したpngファイルのサイズを確認すると(w x 3 , h x 3)になってる。
3倍になってるのは私のiPhone 12 Pro Maxの場合で、これがiPadだと(w x 2, h x 3)なのでUIScreen.main.scaleの値が効いてるのかもしれない。ともかく2倍なり3倍で保存されるのは具合が悪い。
ios - Saving and Loading MTLTexture as PNG - Stack Overflow
↑同じような感じで困ってる人の投稿があったが回答はなし、、、(よくあるよね)
MTLTextureから上記の処理で作成したUIImageオブジェクトにはCGImageがない。
uiimage.cgImageはnilだ。
なのでCGImageを作成してみた。
cocoa - CGImage from byte array - Stack Overflow
↑この記事の下の方にSwiftでのコードがあるので参考にした。
MTLTextureからデータ配列を作成するには
getBytes(_:bytesPerRow:from:mipmapLevel:)
を使用。
コードはこんな感じになった↓
private func makeCGImageFromMTLTexture(_ mtlTexture: MTLTexture) -> UIImage {
let width = mtlTexture.width
let height = mtlTexture.height
let numComponents = 4
let numBytes = height * width * numComponents
let region = MTLRegion(origin: MTLOrigin(x: 0, y: 0, z: 0),
size: MTLSize(width: width, height: height, depth: 1))
var pixelData: [UInt8] = [UInt8](repeating: 0, count: numBytes)
mtlTexture.getBytes(&pixelData, bytesPerRow: width*4, from: region, mipmapLevel: 0)
let colorspace = CGColorSpaceCreateDeviceRGB()
let rgbData = CFDataCreate(nil, pixelData, numBytes)!
let provider = CGDataProvider(data: rgbData)!
let cgImage = CGImage(width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 8 * numComponents,
bytesPerRow: width * numComponents,
space: colorspace,
bitmapInfo: CGBitmapInfo(rawValue: 0),
provider: provider,
decode: nil,
shouldInterpolate: true,
intent: CGColorRenderingIntent.defaultIntent)!
return cgImage
}
このメソッドを使い、同様にpngファイルで保存を試みた。
let cgImage = makeCGImageFromMTLTexture(mtlTexture)
let uiimage = UIImage(cgImage: cgImage)
let data = uiimage.pngData()!
try! data.write(to: url)
すると無事にサイズは3倍などにはならずに意図通りのサイズで作成できた。
しかし、、、色がおかしい!
MTLTexture から CGImage を生成 - Qiita
↑調べたらこちらの記事と同じことかな、と思い入れ替える処理を実装すれば無事に正しい色で表示された!
その場合のメソッドは以下のような感じ。
import Accelerate
private func makeCGImageFromMTLTexture(_ mtlTexture: MTLTexture) -> UIImage {
let width = mtlTexture.width
let height = mtlTexture.height
let numComponents = 4
let numBytes = height * width * numComponents
let rowBytes = width * numComponents
let region = MTLRegion(origin: MTLOrigin(x: 0, y: 0, z: 0),
size: MTLSize(width: width, height: height, depth: 1))
var bgraBytes = [UInt8](repeating: 0, count: numBytes)
mtlTexture.getBytes(&bgraBytes, bytesPerRow: width*4,
from: region, mipmapLevel: 0)
var bgraBuffer: vImage_Buffer = vImage_Buffer()
bgraBytes.withUnsafeMutableBufferPointer {bgraBytesBP in
bgraBuffer = vImage_Buffer(data: bgraBytesBP.baseAddress,
height: vImagePixelCount(height),
width: vImagePixelCount(width),
rowBytes: rowBytes)
}
var rgbaBytes = [UInt8](repeating: 0, count: numBytes)
var rgbaBuffer: vImage_Buffer = vImage_Buffer()
rgbaBytes.withUnsafeMutableBufferPointer {rgbaBytesBP in
rgbaBuffer = vImage_Buffer(data: rgbaBytesBP.baseAddress,
height: vImagePixelCount(height),
width: vImagePixelCount(width),
rowBytes: rowBytes)
}
let map: [UInt8] = [2, 1, 0, 3]
vImagePermuteChannels_ARGB8888(&bgraBuffer, &rgbaBuffer, map, 0)
let colorspace = CGColorSpaceCreateDeviceRGB()
let rgbData = CFDataCreate(nil, rgbaBytes, numBytes)!
let provider = CGDataProvider(data: rgbData)!
let cgImage = CGImage(width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 8 * numComponents,
bytesPerRow: rowBytes,
space: colorspace,
bitmapInfo: CGBitmapInfo(rawValue: 0),
provider: provider,
decode: nil,
shouldInterpolate: true,
intent: CGColorRenderingIntent.defaultIntent)!
return cgImage
}
スポンサーサイト
<< symbolicateしてcrash logからどこでcrashしたか調べる TopPage Swiftでポインタがdangling pointerだと警告が出る >>
トラックバック
トラックバックURL
https://ringsbell.blog.fc2.com/tb.php/1365-8216b7d1
https://ringsbell.blog.fc2.com/tb.php/1365-8216b7d1