任何大于 16x8 或 8x16 的图像尺寸的 JPEG 编码错误

JPEG encoding error for any image size larger than 16x8 or 8x16

目前我正在为一个大学项目开发​​一个 jpeg 编码器。图像具有固定大小,编码器使用固定量化和霍夫曼表进行基线处理。首先,我的代码从 SDRAM 读取 32 位 RGBx 值,转换为 YCbCr 颜色 space,将每个通道标准化为 0 并写回。然后,它开始对 8x8 块进行 DCT,并将熵编码数据写入 SDRAM。这个过程是使用 C 完成的,然后 Python 代码创建一个带有适当 JFIF 标记和熵编码数据的文件。最后,OS 使用默认的 jpeg 解码器,只需双击即可查看图像。

我的代码适用于 8x8、8x16 和 16x8 图像,但不适用于 16x16 或项目中使用的图像的实际大小。您可能会在下面看到 16x16 示例。

16x16 输入

16x16 输出

但是,在 Whosebug 上,它似乎与我的 OS' 默认解码器相比有所不同。下面是它在 macOS 预览应用程序上的样子。

我认为我的问题是由于 JFIF 中的标记或某种算法错误造成的。

如果有 jpeg 方面经验的人可以帮助我,我将非常高兴。

亲切的问候

我写了一个jpeg编解码器。它保持在 https://github.com/MalcolmMcLean/babyxrc 但是,尽管欢迎您查看甚至使用它,但这并不能真正回答您的问题。

JPEG 基于 16x16 色度块和 8x8 亮度块。因此,您的软件的初始版本在第一个 16x16 块后崩溃也就不足为奇了。这只是一个例行的编程错误。如果您无法通过阅读 JEG 规范找到它,请启动编辑器并创建平面 32x32 图像。然后查看二进制文件,看看它与您的不同之处。

这是我的没有子采样的负载扫描

static int loadscanYuv111(JPEGHEADER *hdr, unsigned char *buff, FILE *fp)
{
  short lum[64];
  short Cb[64];
  short Cr[64];
  BITSTREAM *bs;
  int i;
  int ii;
  int iii;
  int iv;
  int diffdc = 0;
  int dcb = 0;
  int dcr = 0;
  int actableY;
  int actableCb;
  int actableCr;
  int dctableY;
  int dctableCb;
  int dctableCr;
  int count = 0;
  int target;
  int luminance;
  int red;
  int green;
  int blue;

  actableY = hdr->useac[0];
  actableCb = hdr->useac[1];
  actableCr = hdr->useac[2];
  dctableY = hdr->usedc[0];
  dctableCb = hdr->usedc[1];
  dctableCr = hdr->usedc[2];

  bs = bitstream(fp);

  for(i=0;i<hdr->height;i+=8)
    for(ii=0;ii<hdr->width;ii+=8)
    {
      if(hdr->dri && (count % hdr->dri) == 0 && count > 0 )
      {
        readmarker(bs);
        diffdc = 0;
        dcb = 0;
        dcr = 0;
      }

      getblock(lum, hdr->dctable[dctableY], hdr->actable[actableY], bs);
      lum[0] += diffdc;
      diffdc = lum[0];

      for(iv=0;iv<64;iv++)
        lum[iv] *= hdr->qttable[hdr->useq[0]][iv];
      unzigzag(lum);
      idct8x8(lum);

      getblock(Cb, hdr->dctable[dctableCb], hdr->actable[actableCb], bs);
      Cb[0] += dcb;
      dcb = Cb[0];

      for(iv=0;iv<64;iv++)
        Cb[iv] *= hdr->qttable[hdr->useq[1]][iv];
      unzigzag(Cb);
      idct8x8(Cb);

      getblock(Cr, hdr->dctable[dctableCr], hdr->actable[actableCr], bs);
      Cr[0] += dcr;
      dcr = Cr[0];

      for(iv=0;iv<64;iv++)
        Cr[iv] *= hdr->qttable[hdr->useq[2]][iv];
      unzigzag(Cr);
      idct8x8(Cr);

      for(iii=0;iii<8;iii++)
      {
        if( i + iii >= hdr->height)
          break;
        for(iv=0;iv<8;iv++)
        {
          if(ii + iv >= hdr->width)
            break;
          target = (i + iii) * hdr->width * 3 + (ii + iv) * 3;
          luminance = lum[iii*8+iv]/64 + 128;
          red = (int) (luminance + 1.402  * Cr[iii*8+iv]/64);
          green = (int) (luminance - 0.34414 * Cb[iii*8+iv]/64 - 0.71414 * Cr[iii*8+iv]/64);
          blue = (int) (luminance + 1.772  * Cb[iii*8+iv]/64);
          red = clamp(red, 0, 255);
          green = clamp(green, 0, 255);
          blue = clamp(blue, 0, 255);
          buff[target] = red;
          buff[target+1] = green;
          buff[target+2] = blue;
        }
      }

      count++;
    }

  killbitstream(bs);
  if(loadeoi(fp) == 0)
    return 0;

  return -1;
}

如您所见,数据是交错的。 但是,如果你弄错了,它会创建一个尺寸正确的奇特图像,而不是比预期更小的图像。