我有一个来自 IPA 的 PNG 文件,并尝试在 Windows 照片中打开它,结果反转了所有的颜色,所以我认为这是 Apple 特有的格式,后来我发现我没有错:
$ file AppIcon29x29.png
AppIcon29x29.png: PNG image data (CgBI), 29 x 29, 8-bit/color RGBA, non-interlaced
因此我尝试将 PNG 转换为常规格式的 PNG,但没有成功:
$ ffmpeg -i AppIcon29x29.png out.png
ffmpeg version N-116015-g23531c9776-20240625 Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 14.1.0 (crosstool-NG 1.26.0.93_a87bf7f)
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --disable-w32threads --enable-pthreads --enable-iconv --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-libxml2 --enable-fontconfig --enable-libharfbuzz --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --enable-libdvdread --enable-libdvdnav --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libaribcaption --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --enable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-libs=-lgomp --extra-ldflags=-pthread --extra-ldexeflags= --cc=x86_64-w64-mingw32-gcc --cxx=x86_64-w64-mingw32-g++ --ar=x86_64-w64-mingw32-gcc-ar --ranlib=x86_64-w64-mingw32-gcc-ranlib --nm=x86_64-w64-mingw32-gcc-nm --extra-version=20240625
libavutil 59. 26.100 / 59. 26.100
libavcodec 61. 8.100 / 61. 8.100
libavformat 61. 4.100 / 61. 4.100
libavdevice 61. 2.100 / 61. 2.100
libavfilter 10. 2.102 / 10. 2.102
libswscale 8. 2.100 / 8. 2.100
libswresample 5. 2.100 / 5. 2.100
libpostproc 58. 2.100 / 58. 2.100
[png @ 00000277b0445b80] inflate returned error -3
Input #0, png_pipe, from 'AppIcon29x29.png':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: png, rgba(pc, gbr/unknown/unknown), 29x29, 25 fps, 25 tbr, 25 tbn
Stream mapping:
Stream #0:0 -> #0:0 (png (native) -> png (native))
Press [q] to stop, [?] for help
[png @ 00000277b0459340] inflate returned error -3
[vist#0:0/png @ 00000277b044d040] [dec:png @ 00000277b0449180] Decoding error: Generic error in an external library
[vist#0:0/png @ 00000277b044d040] [dec:png @ 00000277b0449180] Decode error rate 1 exceeds maximum 0.666667
[vist#0:0/png @ 00000277b044d040] [dec:png @ 00000277b0449180] Task finished with error code: -1145393733 (Error number -1145393733 occurred)
[vist#0:0/png @ 00000277b044d040] [dec:png @ 00000277b0449180] Terminating thread with return code -1145393733 (Error number -1145393733 occurred)
[vf#0:0 @ 00000277b04496c0] No filtered frames for output stream, trying to initialize anyway.
Output #0, image2, to 'out.png':
Metadata:
encoder : Lavf61.4.100
Stream #0:0: Video: png, rgba(progressive), 29x29, q=2-31, 200 kb/s, 25 fps, 25 tbn
Metadata:
encoder : Lavc61.8.100 png
[out#0/image2 @ 00000277b04278c0] video:0KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
[out#0/image2 @ 00000277b04278c0] Output file is empty, nothing was encoded(check -ss / -t / -frames parameters if used)
frame= 0 fps=0.0 q=0.0 Lsize=N/A time=N/A bitrate=N/A speed=N/A
Conversion failed!
$ ffmpeg -i AppIcon29x29.png -pix_fmt yuv420p out.png
ffmpeg version N-116015-g23531c9776-20240625 Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 14.1.0 (crosstool-NG 1.26.0.93_a87bf7f)
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --disable-w32threads --enable-pthreads --enable-iconv --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-libxml2 --enable-fontconfig --enable-libharfbuzz --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --enable-libdvdread --enable-libdvdnav --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libaribcaption --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --enable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-libs=-lgomp --extra-ldflags=-pthread --extra-ldexeflags= --cc=x86_64-w64-mingw32-gcc --cxx=x86_64-w64-mingw32-g++ --ar=x86_64-w64-mingw32-gcc-ar --ranlib=x86_64-w64-mingw32-gcc-ranlib --nm=x86_64-w64-mingw32-gcc-nm --extra-version=20240625
libavutil 59. 26.100 / 59. 26.100
libavcodec 61. 8.100 / 61. 8.100
libavformat 61. 4.100 / 61. 4.100
libavdevice 61. 2.100 / 61. 2.100
libavfilter 10. 2.102 / 10. 2.102
libswscale 8. 2.100 / 8. 2.100
libswresample 5. 2.100 / 5. 2.100
libpostproc 58. 2.100 / 58. 2.100
[png @ 0000028496766800] inflate returned error -3
Input #0, png_pipe, from 'AppIcon29x29.png':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: png, rgba(pc, gbr/unknown/unknown), 29x29, 25 fps, 25 tbr, 25 tbn
Incompatible pixel format 'yuv420p' for codec 'png', auto-selecting format 'rgb24'
Stream mapping:
Stream #0:0 -> #0:0 (png (native) -> png (native))
Press [q] to stop, [?] for help
[png @ 00000284967798c0] inflate returned error -3
[vist#0:0/png @ 000002849674a0c0] [dec:png @ 000002849676af80] Decoding error: Generic error in an external library
[vist#0:0/png @ 000002849674a0c0] [dec:png @ 000002849676af80] Decode error rate 1 exceeds maximum 0.666667
[vist#0:0/png @ 000002849674a0c0] [dec:png @ 000002849676af80] Task finished with error code: -1145393733 (Error number -1145393733 occurred)
[vist#0:0/png @ 000002849674a0c0] [dec:png @ 000002849676af80] Terminating thread with return code -1145393733 (Error number -1145393733 occurred)
[vf#0:0 @ 0000028496766800] No filtered frames for output stream, trying to initialize anyway.
Output #0, image2, to 'out.png':
Metadata:
encoder : Lavf61.4.100
Stream #0:0: Video: png, rgb24(progressive), 29x29, q=2-31, 200 kb/s, 25 fps, 25 tbn
Metadata:
encoder : Lavc61.8.100 png
[out#0/image2 @ 0000028496749440] video:0KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: unknown
[out#0/image2 @ 0000028496749440] Output file is empty, nothing was encoded(check -ss / -t / -frames parameters if used)
frame= 0 fps=0.0 q=0.0 Lsize=N/A time=N/A bitrate=N/A speed=N/A
Conversion failed!
$ ffmpeg -i AppIcon29x29.png -pix_fmt bgra out.png
[same error as before, but with unsupported format "bgra" for png]
还尝试了 Pillow:(发现了关于 BGRA 的信息,这是一种 Apple 似乎使用的像素格式 - 我不确定它是否在图像中使用) - 它似乎受支持:https://github.com/python-pillow/Pillow/pull/2057
>>> from PIL import Image
>>> Image.open("AppIcon29x29.png").save("test.png")
[...] OSError: broken data stream when reading image file
>>> Image.open("AppIcon29x29.png", mode="CgBI").save("test.png")
ValueError: bad mode 'CgBI'
>>> Image.open("AppIcon29x29.png", mode="BGRa").save("test.png")
ValueError: bad mode 'BGRa'
>>> Image.frombuffer("RGBA", (29, 29), open("AppIcon29x29.png", "rb").read(), "raw", "BGRa")
<PIL.Image.Image image mode=RGBA size=29x29 at 0x1B091892150>
>>> _.save("test.png")
[outputs an image with random colored pixels]
有什么想法吗?我真的更喜欢仅使用 FFMPEG 或仅使用 Pillow 的解决方案。(为了更容易编写 Python 脚本)。
类似问题:使用 ffmpeg 将 png 序列转换为 x264
编辑:实际上我没有看到 GNU 文件清楚地说它是 RGBA 而不是 BGRA。
编辑 2:我发现这个,如果它可以帮助:https://developer.apple.com/design/human-interface-guidelines/app-icons/#Specifications
@Rotem 建议使用 PyiPNG(位于https://github.com/venjye/PyiPNG),效果很好,我会使用它,但奇怪的是,使用 FFMPEG 无法做到同样的事情……