【发布时间】:2020-09-06 22:48:47
【问题描述】:
一直在用 C# 中的 SDL2 进行试验,并尝试创建一个 maxrects 驱动的纹理打包器。为了以节省空间的方式打包图集,几乎总是需要旋转纹理。该程序使用 SDL_Surfaces 从文件中加载图像并将它们 blit 到更大的 SDL_Surface 并将其写入磁盘。这就是我实现轮换的方式:
// get pointer to original SDL_Surface
var sptr = (SDL_Surface*)surfaces[bestIndex].Item2;
// check if maxrects algorithm has rotated the rectangle "best"
if (best.w != sptr->w) {
var rotd = (SDL_Surface*)SDL_CreateRGBSurfaceWithFormat(0, sptr->h, sptr->w, 32, SDL_PIXELFORMAT_RGBA8888);
IntPtr rotdPixels = rotd->pixels;
IntPtr sptrPixels = sptr->pixels;
for (int y = 0; y < sptr->h; y++) {
for (int x = 0; x < sptr->w; x++) {
// get target pointer by swapping dimensions and flipping one, resulting in a rotation
uint* target = (uint*)(rotdPixels + x * rotd->pitch + (sptr->h - y - 1) * 4);
// set target from the expected location. Bswsp is necessary.
*target = System.Buffers.Binary.BinaryPrimitives.ReverseEndianness(*(uint*)(sptrPixels + y * sptr->pitch + x * 4));
}
}
if (SDL_BlitSurface(new IntPtr(rotd), IntPtr.Zero, atlas, ref best) < 0)
throw new Exception(SDL_GetError());
} else {
if (SDL_BlitSurface(new IntPtr(sptr), IntPtr.Zero, atlas, ref best) < 0)
throw new Exception(SDL_GetError());
}
这是一种非常不安全的方法,我很惊讶它在当前形式下的效果和它一样好,但是它在生成的图集中出现了一个看似不可预测的错误(如果我在 blitting 之前保存旋转的表面,则在单独的图像中) ,这只能通过错误转换的图像本身来最好地描述:
Imgur 不保留原始数据,而是在此处 Google Drive 链接到之前和之后:
After rotation (png)
请注意,这不仅限于 .jpg 文件,该格式也不一定会导致问题,.png 文件偶尔也会这样做,但频率较低。如果我要解释发生了什么:图像被轻微压扁,一个扇区被切割并重新定位,颜色分裂成几乎像 CRT 一样的扫描线效果,似乎以 3 行的模式重复,但仍然在一定程度上反映了原始图片,旋转。
有谁知道这可能是什么原因造成的,如何防止它,或者如何以编程方式检测它何时会发生并避免它。或者,如果必须是这样的话,一个更好的方法来做到这一点?我目前无法找到导致此问题的格式/尺寸的任何一致性,并且已确认这不是导致问题的 blitting 过程,并且 maxrects 算法按预期工作 - 返回的矩形是有效的。如果您能提供帮助,请提前致谢..
【问题讨论】:
-
您是否尝试过使用图像的原始格式而不是 RGBA8888?
-
看起来您的颜色通道顺序错误。什么是源表面格式?你确定你需要反向字节序吗?
-
@keltar 所有表面都以 RGBA8888 格式加载,程序中不使用其他格式。反转字节顺序时,不仅正确旋转的图像看起来很完美,而且旋转错误的图像看起来也更准确。
-
@Aram 所有表面都以 RGBA8888 格式加载,并且所有表面都以原始形式正确表示,它们正确保存。除非 SDL 库以某种方式忽略格式转换并给出不正确的大小像素,否则它会在将图像写回磁盘时自行恢复(这是可能的,但似乎不太可能),我认为没有必要为不同的格式创建不同的例程。这也导致:我如何检测这种格式变化?
-
@SFBDragon 用 alpha 交换红色将产生半透明。您的图像看起来非常半透明。检查
surface->format->format的实际值。
标签: c# sdl-2 image-rotation