草庐IT

C++ 从 8 位位图构建像素数据并访问 bmiColor 表信息

coder 2024-06-19 原文

我是一个 n00b,过去几天一直在研究这个问题,但我只是被困住了。我在 OpenSuse Linux 中工作,试图解释 Windows 位图图像以使用 Cairo 图形库显示。简单地说,我只需要将每个像素的颜色信息放入一个数组并将其提供给开罗,例如pixeldata[i] = someColor,用于图像中的所有像素。到目前为止,我已经弄明白了如何解析位图 header 并使其能够很好地显示 24 位位图。

但是,现在我正在努力让 8 位位图也显示出来,而且它只是一个难以处理、不直观的野兽。我能够显示图像,但显示的颜色是错误的......不仅如此,每次我运行程序时它们都会改变! :P 我想我正在错误地访问和解释 bmiColors 调色板数组。这是我从构建像素数组的冗长互联网研究中拼凑而成的相关代码(请注意,到代码中的这一点, header 信息已经被解析并且在对象 m_bmpInfoHeader 和 m_bmpHeader 中可用):

#define RGB(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16 )))

#pragma pack (2)
typedef struct tagRGBQUAD {
  long rgbBlue;
  long rgbGreen;
  long rgbRed;
  int rgbReserved;
} RGBQUAD;

typedef struct
{
  char verifier[2];
  unsigned int size;
  unsigned short int reserved1, reserved2;
  unsigned int offset;
} BITMAPHEADER;

typedef struct
{
  unsigned int size;               /* Header size in bytes      */
  signed int width, height;        /* Width and height of image */
  unsigned short int planes;       /* Number of colour planes   */
  unsigned short int bits;         /* Bits per pixel            */
  unsigned int compression;        /* Compression type          */
  unsigned int imagesize;          /* Image size in bytes       */
  int xresolution,yresolution;     /* Pixels per meter    */
  unsigned int ncolors;            /* Number of colors         */
  unsigned int importantcolors;    /* Important colors   */
  RGBQUAD bmiColors [1];
} BITMAPINFOHEADER; 
#pragma pack()

// Function sets up and returns color index for bitmap.
long BitmapDef::GetColorInx (int numbits, char* data, long offset)
{
  long inx;

  switch (numbits)
  {
    case 1:
      inx = data[offset >> 3];
      offset &= 7;
      inx >>= offset;
      inx &= 0x01;
      break;
    case 2:
      inx = data[offset >> 2];
      offset &= 3;
      offset <<= 1;
      inx >>= offset;
      inx &= 0x03;
      break;
    case 4:
      inx = data[offset >> 1];
      if (!(offset & 1))
      {
        inx >>= 4;
      }
      inx &= 0x0f;
      break;
    case 24:
    {
      offset *= 3;
      inx = *((long*) &data[offset]);
      char r = GetBValue(inx);
      char g = GetGValue(inx);
      char b = GetRValue(inx);
      inx = ((r << 16) + (g << 8) + b);
      break;
    }
    case 8:
    default:
      inx = data[offset] & 0xff;
      break;
  }
  return inx;
}

void BitmapDef::Build8BitPixelData()
{
  m_PixelData = new unsigned int[m_bmpInfoHeader.width * m_bmpInfoHeader.height];

  FILE * pFile;
  long lSize;
  char * buffer;
  size_t result;

  pFile = fopen ((const char *)m_Filename, "rb" );
  if (pFile==NULL)
  {
    fputs ("File error", stderr);
    exit (1);
  }

  // obtain file size:
  fseek (pFile , 0 , SEEK_END);
  lSize = ftell (pFile);
  rewind (pFile);

  // allocate memory to contain the whole file:
  buffer = (char*) malloc (sizeof(char) * lSize);
  if (buffer == NULL) {fputs ("Memory error", stderr); exit (2);}

  // copy the file into the buffer:
  result = fread (buffer, 1, lSize, pFile);
  if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

  BITMAPHEADER* bmfh = (BITMAPHEADER*) (&(buffer[0]));

  char* bmp = (char*) &buffer[m_bmpHeader.offset];

  BITMAPINFOHEADER * bmi = (BITMAPINFOHEADER*) &buffer[sizeof(*bmfh)];
  std::cout<<"\nsize: "<<bmi->size<<std::endl;
  std::cout<<"width: "<<bmi->width<<std::endl;
  std::cout<<"height: "<<bmi->height<<std::endl;
  std::cout<<"planes: "<<bmi->planes<<std::endl;
  std::cout<<"bits: "<<bmi->bits<<std::endl;
  std::cout<<"annnd compression: "<<bmi->planes<<std::endl;

  int ix, iy;

  int position = 0;

  for (iy = 0; iy < bmi->height; ++iy)
  {
    for (ix = 0; ix < bmi->width; ++ix)
    {
      int offset = (m_bmpInfoHeader.height - 1 - iy) * m_bmpInfoHeader.width;
      offset += ix;
      //std::cout<<"offset: "<<offset<<" bmp[offset]: "<<bmp[offset] << " " ;

      long inx = GetColorInx (m_bmpInfoHeader.bits, dataBuf, offset);
      //std::cout<<inx<<" ";

      m_PixelData[position] = RGB(bmi->bmiColors[inx].rgbRed, bmi->bmiColors[inx].rgbGreen, bmi->bmiColors[inx].rgbBlue);

      position++;
    }
  }

  fclose (pFile);
  free (buffer);
}

有什么想法吗?请注意,我在非 Windows 环境中工作,因此我不得不将许多以 Windows 为中心的函数转换为在 C++ 中工作。感谢任何帮助,谢谢!

更新:

感谢 cbranch 的推荐,我将 RGBQUAD 修改为具有 char 属性而不是 long/int,以便它保持 4 字节结构。这解决了颜色不断变化的问题。然而,奇怪的是颜色仍然不正确。目前我正在尝试在黑色背景上显示绿色钻石的简单图像,但由于某种原因钻石显示为黄色。有什么想法吗?

此外,我刚刚注意到我不小心将“#pragma pack()”指令从我原来的帖子中的结构周围遗漏了,现在才将它们添加到帖子中。

最佳答案

RGBQuad 应该是四个字节。

这个宏:

#define RGB(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16 )))

有问题。您可能正在获得符号扩展。一个完整的绿色像素将有 g == 0xFF。您将它转换为(带符号的)short,因此您可能会得到符号扩展(0xFFFF),然后进行移位。现在您已将红色和绿色设置为完整值,因此它看起来是黄色的。

在进行按位操作时,您几乎总是希望使用无符号值。

关于C++ 从 8 位位图构建像素数据并访问 bmiColor 表信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14816968/

有关C++ 从 8 位位图构建像素数据并访问 bmiColor 表信息的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  7. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  8. ruby - 在 Ruby 中构建长字符串的简洁方法 - 2

    在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

随机推荐