旋转SDL_Surface会意外地产生错误的结果

问题描述

已经在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),ref best) < 0)
        throw new Exception(SDL_GetError());
}

这是一种非常不安全的方法,令我惊讶的是它的工作方式以及它在当前形式下的表现都很好,但是它在生成的图集中显示了看似不可预测的错误(如果在发条前保存旋转的曲面,则在单​​独的图像中显示) ,这只能由变形后的图片本身来最好地描述:

Imgur不会保留原始数据,而是在这里Google Drive链接到之前和之后的内容:
After rotation (png)

Before rotation (jpg)

请注意,这不仅限于.jpg文件,也不一定会导致这种问题,.png文件偶尔也会执行相同的操作,但次数较少。如果我要解释发生了什么:图像被稍微压扁,一个扇区被切割并重新定位,并且颜色分裂成看起来几乎像CRT的扫描线效果,似乎以3行的图案重复出现,但是仍然有点反映了原始图像。图片,旋转。

是否有人知道这可能是什么原因,如何防止它,或者如何以编程方式检测何时会发生并避免它。或者,如果必须这样做,那么是执行此操作的更好方法?我目前无法找到导致此问题的格式/尺寸的一致性,并已确认这不是导致该问题的blitting流程,并且maxrects算法正在按预期工作-返回的矩形有效。如果可以的话,请先谢谢。

解决方法

正如@kelter指出的那样,我最初应该已经检查了表面格式。通过在需要加载图像时选择性地转换表面,代码按预期工作。

为解释特殊的奇怪情况,我使用的两种文件格式分别为ABGR8888和RGB24,这就是为什么字节交换使原始文件部分起作用的原因,3的模式是由于3byte vs 4byte内存布局,通过在某些像素上“跳过”来引起挤压,并且溢出导致最终图像中多余的重复裁切。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...