【问题标题】:data corruption while converting from char * to stringstream and then back to char*从 char * 转换为 stringstream 然后再转换回 char* 时数据损坏
【发布时间】:2014-05-14 16:21:55
【问题描述】:

所以,我尝试使用 XImage,创建了我的第一个屏幕捕获程序,它运行良好。现在我想通过 thrift 将此 XImage 发送到另一台机器并将其保存在那里,但由于客户端存在一些数据读取问题,因此我将整个服务器端代码转移到客户端(出于测试目的。我最终会移动它回到服务器端)

代码:

transport->open();
Display *display = XOpenDisplay(NULL);
  Window root = DefaultRootWindow(display);
  XWindowAttributes gwa;
  XGetWindowAttributes(display, root, &gwa);

  int width = gwa.width;
  int height = gwa.height;
  XImage *image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap);

  char *data    = image->data;
  int imgwidth  = image->width;
  int imgheight = image->height;
  int depth     = image->depth;
  int offset    = 0;
  int xpad = 32; //may be 8 or 16 or 32
  int format = ZPixmap;
  int bytes_per_line = image->bytes_per_line;


  sendImage image_send;

  ostringstream s;
  //s<<image->data;
  s.write(image->data,(width)*(height));
  image_send.width  = imgwidth;
  image_send.height = imgheight;
  image_send.depth  = depth;
  image_send.offset = 2000;
  image_send.data   = s.str();
  image_send.xpad   = xpad;
  image_send.format = format;
  image_send.bytes_per_line = bytes_per_line;

 //server side code 
     int width1  = image_send.width;
     int height1 = image_send.height;
     int depth1  = image_send.depth;
     int offset1 = image_send.offset;
     char* tmp = new char[image_send.data.length() + 1];
     strcpy(tmp,image_send.data.c_str());
     char *data1 = tmp;
     int xpad1  = image_send.xpad;
     int format1 = image_send.format;
     int bytes_per_line1 = image_send.bytes_per_line;

     //Initialising X Operations
     //Display *display = XOpenDisplay(NULL);
     //Window root = DefaultRootWindow(display);
     //XWindowAttributes gwa;
    //XGetWindowAttributes(display, root, &gwa);

   int serverwidth = gwa.width;
   int serverheight = gwa.height;
   XImage *image1 = XCreateImage(display,DefaultVisual(display,DefaultScreen(display)),depth1, format1,offset1,data1,width1,height1,xpad1, bytes_per_line1);



   unsigned char *array = new unsigned char[width * height * 3];

   unsigned long red_mask = image1->red_mask;
   unsigned long green_mask = image1->green_mask;
   unsigned long blue_mask = image1->blue_mask;

   CImg<unsigned char> pic(array,width,height,1,3);

   for (int x = 0; x < width1; x++)
      for (int y = 0; y < height1 ; y++)
      {
         unsigned long pixel = XGetPixel(image1,x,y);

     unsigned char blue = pixel & blue_mask;
     unsigned char green = (pixel & green_mask) >> 8;
     unsigned char red = (pixel & red_mask) >> 16;



     array[(x + width1 * y) * 3] = red;
     array[(x + width1* y) * 3+1] = green;
     array[(x + width1 * y) * 3+2] = blue;

     pic(x,y,0,0) = red;
     pic(x,y,0,1) = green;
     pic(x,y,0,2) = blue;
  }



   pic.save_png("blah1.png");

如您所见,我从图像指针中获取数据部分,将其写入流中,然后将该值分配给节俭对象(image_send)

对于服务器端。我使用 c_str() 将其存储到 data1 中,然后使用 data1 使用 XCreateImage

这是我在 XCreateImage 中将 data1 作为源传递时得到的输出

这是我使用数据时得到的输出(来自原始 XImage 的客户端变量)

我们可以看到,第一张图片中有很多空白区域。经过进一步检查,我发现 data1 在开始时包含很多空值,而数据却没有

所以,我相信在从 char * 转换为字符串流然后再转换回 char * 时数据会损坏。

你会提出什么建议来纠正这个问题? 更新:

所以,我尝试了各种方法,终于奏效了。问题原来是缓冲区分配和 strcpy 的使用(我猜)我改为 memcpy

int main() {

Display *display = XOpenDisplay(NULL);
Window root = DefaultRootWindow(display);
XWindowAttributes gwa;
XGetWindowAttributes(display, root, &gwa);

int width = gwa.width;
int height = gwa.height;
XImage *image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap);

char *data    = image->data;
int imgwidth  = image->width;
int imgheight = image->height;
int depth     = image->depth;
int offset    = 0;
int xpad = 32; //may be 8 or 16 or 32
int format = ZPixmap;
int bytes_per_line = image->bytes_per_line;


//sendImage image_send;

ostringstream s;
//s<<image->data;
s.write(data,(width)*(height) * 4);

string stemp = s.str(); 
//server side code 
int width1  = width;
int height1 = height;
int depth1  = depth;
int offset1 = offset;
char* tmp = new char[stemp.length()];
//strcpy(tmp,stemp.c_str());
memcpy(tmp,stemp.data(),stemp.length());
char *data1 = tmp;
int xpad1  = 32;
int format1 = ZPixmap;
int bytes_per_line1 = bytes_per_line;

int serverwidth = gwa.width;
int serverheight = gwa.height;
XImage *image1 = XCreateImage(display,DefaultVisual(display,DefaultScreen(display)),depth1, format1,offset1,data1,serverwidth,serverheight,xpad1, bytes_per_line1);

unsigned char *array = new unsigned char[width * height];

unsigned long red_mask = image1->red_mask;
unsigned long green_mask = image1->green_mask;
unsigned long blue_mask = image1->blue_mask;

CImg<unsigned char> pic(array,width,height,1,3);

for (int x = 0; x < width1; x++) {
    for (int y = 0; y < height1 ; y++)
    {
        unsigned long pixel = XGetPixel(image1,x,y);
        unsigned char blue = pixel & blue_mask;
        unsigned char green = (pixel & green_mask) >> 8;
        unsigned char red = (pixel & red_mask) >> 16;

        pic(x,y,0,0) = red;
        pic(x,y,0,1) = green;
        pic(x,y,0,2) = blue;
    }
}

pic.save_png("blah.png");

return 0;
}

但是有几件事我不明白

1) 当我将数据写入流时,为什么我必须将缓冲区的大小设为 (width * height * 4)。任何更少的东西都会按比例裁剪图像。如果我理解正确,缓冲区大小不应该等于屏幕的宽度*高度,还是它的结构更像是红色、绿色、蓝色和深度的数组?

2) 我的缓冲区大小约为 4MB,但图像大小约为 150K,是不是编码原因

3) 连续分配和释放这么多缓冲区大小会影响性能吗?

编辑:为了将来的目的

第一个问题的答案是:我们可以使用 (bytes_per_lineheight) 得到相同的结果,它恰好给出了与 width 相同的结果height*4

【问题讨论】:

    标签: c++ buffer x11 stringstream


    【解决方案1】:

    图像数据是二进制的,你不能将它当作 C 字符串来操作。第一个零字节会毁了聚会。

    使用std::string::data() 和/或memcpy,而不是std::string::str()strcpy

    我不知道这是否是唯一的问题。 (width)*(height) 在我看来很可疑。你有一个字节的像素吗?

    【讨论】:

    • 是的,我做了那些必要的更正,可以在代码的后面部分看到。就宽度宽度X高度而言。不,它是 4 字节,因此,我的图像失真了。无论如何,更好的方法是使用 (bytes_per_line*height)
    猜你喜欢
    • 1970-01-01
    • 2015-12-19
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多