我在MFC中用CFile打开了一个bmp图像,它的信息(就是那些信息头和图像像素数据等之类的)我都基本得到了。如果我想在图像上随便加一行字,然后保存图像(另存为一个新的图像文件也行),使得以后每次打开该图像文件时该文字是存在的,请问怎样做?
  给整个过程的代码或者几个关键步骤的函数都行。谢谢了。

解决方案 »

  1.   

    http://topic.csdn.net/t/20010330/13/90523.html
      

  2.   

    用GDI+吧,用bmp图像文件创建一个IStream,然后用这个IStream创建一个Bitmap对象,之后创建一个Graphics对象将这个Bitmap对象选入,然后调用DrawString,之后再调用Bitmap的Save方法保存成另外一个文件就可以了。
      

  3.   

    要把你的BMP选入DC然后再上面写字,最后保存,例如:IBmp bmp;
    bmp.Load( bmpName );
    // 取来GDI作图
    CDC *pDrawDC = CDC::FromHandle( bmp.BeginDraw() );
    // 设置字体背景透明
    // pDrawDC->SetBKMode( TRANSPARENT );
    // 字体颜色
    // pDrawDC->SetTextColors( RGB( x, x, x ) );
    // 写字
    // pDrawDC->TextOut( x, y, "hello, world!" );
    // 写完释放
    bmp.EndDraw();
    // 保存.
    bmp.Save( bmpName );
    简单吧..
      

  4.   

    找不到BeginDraw()函数啊。
    还有,IBmp bmp;是什么意思?
      

  5.   

    先将BMP文件贴到DC上来,然后用TextOut写字,然后将HBITMAP对象保存为BMP文件即可。
    这里面最大的问题是将HBitmap对象保存为BMP文件,下面有示例代码:http://blog.csdn.net/wltg2001/archive/2008/04/17/2300258.aspx
      

  6.   

    去这里找到IBmp类:
    http://blog.csdn.net/lambochan/archive/2009/12/31/5115776.aspx然后导入到你的工程(或者自己新建个类copy粘贴),就可以如法炮制了...
      

  7.   

    我只把那个IBmp.h 和IBmp.cpp通过“工程-增加到工程-文件”添加到了我的工程。我把头文件IBmp.h通过#include"IBmp.h"添加到了我的工程的View类的cpp文件中,因为我只在View类进行操作,但是出现如下错误:
    fatal error C1083: Cannot open include file: 'IBmp.h': No such file or directory真的不知道为什么,请教楼上。
      

  8.   

    呵呵!方法很多,就看你会不会用了,另:6楼的方法值得一试,至于将HBitmap对象保存为bmp文件的代码,我这有,可以发给你,或你到我的资源中去下。
      

  9.   


    要把它copy到你工程的目录下.
    "No such file or directory"就是找不到文件..估计你是单纯引用没有copy到目录吧.
    #include "xxx.h"时,只会在当前目录找文件的
      

  10.   

    我用自己的方法解决了,其实也不算是自己的方法。
    有一点我要说明一下,我本来就是用CFile 打开了一个BMP文件,就是它的BITMAPINFOHEADER,BITMAPFILEHEADER,RGBQUAD,还有实际的图像数据的指针lpBuf四部分的数据我都得到了。之后我用dc在图片上写字,然后用dc.GetPixel去把修改后每点的像素再存放一个lpBuf_new指向的区域。
    然后我又用CFile建了一个新的文件,之后把先前得到的修改前BMP文件的BITMAPINFOHEADER,BITMAPFILEHEADER,RGBQUAD用Write函数依次写进这个文件,最后一部分用lpBuf_new代替就得到一个新的文件,这个文件保存的就是修改后的效果。而且有一点我要声明,我刚才处理的是24位彩色图,lpBuf里存放的就是实际的图像的颜色值。
      现在问题来了,假如我处理的是256色图,那么这时lpBuf里存放的是索引值,RGBQUAD存放的是真正的颜色值,我还想用类似的方法怎么做。因为我在图像上加了一些字,万一这些字的颜色在RGBQUAD里没有对应项,那么我这些字就找不到对应的索引值。请问怎么做?谢谢
      

  11.   


    有简单方法不用,要绕个大圈子去GDI getpixel(),慢且不说,还只能对付ddb...
    上面那个只需8行代码就搞定的,用你的方法恐怕得转来转去..dib to ddb-->gdi作图-->ddb to dib...
    good luck..
      

  12.   

       呵呵,您有点着急了,我是初学者,刚开始还是想试一下自己的想法,请谅解。您的方法我试过了,确实是很好用,有空我会自习钻研一下那个类的代码,应该封装了不少东西吧,不然几行代码就搞定了。
        我再问个问题,如果这次我不在上面写字了,我想把某部分的像素颜色变一下,比如说反色吧。如果还借助你这个IBmp类该怎么做啊?
        十分感谢!!!
      

  13.   


    那个类很简单的,而且比你这:
    "我本来就是用CFile 打开了一个BMP文件,就是它的BITMAPINFOHEADER,BITMAPFILEHEADER,RGBQUAD,还有实际的图像数据的指针lpBuf四部分的数据我都得到了。" 
    多不了多少东西.有如它的说明一样,只能打开/保存/显示和写写画画.
        要处理位图,其实90%以上都是在处理它的位数据,你用GDI的SetPixel/GetPixel其实也就是在改变它的位数据,不过是选了个最慢的方法而已,通常的方法就是直接对其位数据指针赋值从而改变位图.当然了,你要操作的时候,你必须知道你所要做的算法,就举例你说的反色:    本来反色颇简单的,没记错的话,应该是取原图的pixel的三通道R/G/B,然后用255减去后再赋给原pixel,但你要"局部反色"的话,难听点讲句,你在异想天开~~
        对于8Bit以上(含8Bit灰度),你的"局部反色"和全部反色一样,没有问题,但当8bit或以下时,局部反色就涉及到色彩表溢出的问题,例如1Bit位图:这个位图只含有黑色和红色两种,现在你要把局部的黑色来"反色",得出白色;现在就看出了,原图应该变成3种色了..但那是1Bit位图,怎能容下3种颜色呢?解决的办法估计就只能够"曲线救国",把要"反色"的只反成另一种:也就是黑变红/红变黑..那和反色的意思差远了.(实际上全部反色的话,应该是黑变白,红RGB(0xFF,0,0)变青RGB(0,0xFF,0xFF),那只是改改色彩表的颜色就搞定的玩意)
        最后说说256色的标准灰度图的反色,由于这是种像素=灰度且r=g=b的情况,所以你随便乱反局部,都不会导致它的colors table颜色溢出.    当然,有了算法,做起来就简单,举例说说全局反色:
    伪代码..
    BOOL FanSe()
    {
        if( GetBitCount() <= 8 ){
            LPRGBQUAD lpRGB = GetColorsTable();
            DWORD dwNumColors = GetNumColors();
            for( i = 0; i < dwNumColors;++i ){
                lpRGB[i].rgbBlue = 0xFF = lpRGB[i].rgbBlue;
                green..
                red..
            }
        } // 8 bit or lower end
        else {
            LPBYTE lpDibBits = GetBmpBits(); // 取位数据指针操作
            BYTE, r, g, b;
            for( i = 0; i < GetHeight(); ++i ){
                for( j = 0; j < GetWidth(); ++j ){
                    switch(GetBitCount()){
                    case 16:
                        do this..
                        break;
                    case 24:
                        do this & this;
                        break;
                    case 32:
                        do this & this & this;
                        break;
                    } // end switch
                } // end for j
            } // end for i
        } // 16bit or up end.
    }这是全部反色的大约方法,不过无论是"全局"或"局部",靠你自己去实现了,hohoho...
    貌似偶那附带了个反转的例子就是操作它的位数据指针.
      

  14.   

     lpRGB[i].rgbBlue = 0xFF = lpRGB[i].rgbBlue; //手快快打错.汗
    应为:
    lpRGB[i].rgbBlue = 0xFF - lpRGB[i].rgbBlue;
      

  15.   

    现在我对256色图和24位图都可以做到全局反色了。关于256色图我有两个问题请教一下:
    1.lambochan,不知你写上去的那些文字是怎么保存的,那些文字完全可以是ColorsTable中没有的颜色。
    2.对于256色图,不能做任意的图像处理?比如我提取出了一个目标,我想让这个目标用Colorstable外的颜色表示,其它部分还保持原来的颜色,但是最后还是保存为256色图的格式。   关于第二问,如果我不关心最终数据量的大小问题,是不是把256色图保存成24位图的格式就很容易实现该功能了?
      谢谢高手们赐教!
      

  16.   

    自己的方法,不错
    其实很多win低层实现都是和自己饶来饶去的方法是一样的,只不过他们封装起来了
      

  17.   


    1: 看上去不变那只不过是被GDI用近似色map了,很简单的,在灰度图上你画条红色的线就知道了,根本没那种颜色的话,它只能用近似色来映射,但灰度图上映射的话,出来的红线肯定是灰色的(因为色彩表里全是灰度)...也就是偶所说的色彩表溢出的问题..
    2: 答案是一样的,色彩表溢出的话,你要处理后再保存256色只有一种可能:把它转成真彩色做了你的处理后重新量化为8Bit...不过后果是难以预料的,可能因此前后两图面目全非.
    last: 你转成真彩来做处理的话,那肯定是完全没烦恼(只要你也保存成真彩色)
      

  18.   

    To everybody:
      好了,问大家困扰了我很久的问题:
      1.我知道图像分类中有256色图,24位图。我这样理解对不对,256色图实际上也就是24位图,它的每个点也是有R,G,B三个值,一般情况下也就是24位,不考虑什么保留位什么的。只不过它只选用了其中的256种颜色而已,所以对应的索引值有256个。有时又称它为8位图,就因为它的索引值是8位。这样理解对不对?
      2.有没有256色灰度图这个概念,有的话它的意思是色彩表里一定是(0,0,0),(1,1,1),(2,2,2),(3,3,3)...(255,255,255)?还是这些色彩值仍然是任意的?   我是新手,如果说我的问题很白痴的话我不介意的。欢迎大家解答。
      

  19.   

    1:256色和24位色唯一相同的地方就是都是BMP以及都是用RGB来显示颜色.不过格式不一样,所以用来保存颜色的方法也不一样.
    2:当然有,要是灰度图里的话,色彩表里的RGB三通道总是相等的,不过由于各个软件处理灰度图的方法不一样,所以它们在colors table的排位可能是任意的,而标准的灰度图的色彩表应该是按顺序的,也就是色彩表里的各项应该是由1~255,这样的好处是(和乱排的比较):index = 灰度,直接处理index即可,而无须要考虑index所对应的灰度(因为它们是相等的,而乱排的是不等的)..btw:去google一下位图格式look look吧,摸清了就随便搞的,不要嫌闷啊~~~