bmp file을 어떻게 만들 수 있을까요?

shean0의 이미지

안녕하세요..
정보가 필요해서 이렇게 문의를 드립니다.

현재 제가하려는 것이
bmp 화일을 만들려구 하거든요..

지금까지 제가 아는 것이라고는 bmp-header 에 맞추어서 정보를 셋팅하고.
그것을 임의의 내용과 함께 파일에 저장하면 ..
그것이 bmp파일이 된다 라고 들었습니다.

그래서.. 테스트를 해 보려구 하는데.. 영 정보를 못 찿겠네요.
아시는 분 있으시면... 조언을 부탁드립니다.

주==>)
인터넷에서 보니..예전 도스용 프로그램은 있던데. incude<graphics.h> 에서 걸리네요..

sylphong의 이미지

BMP는 압축이 안되어있는 형식이므로 그냥 그대로 저장하면됩니다.
예전에 BMP뷰어만들때 그냥 헤더빼고 그대로 읽어서 출력하니 그림이 나오더군요...
다만 BMP는 형식이 두가지 있는데 윈도에서 쓰는건 거꾸로 읽어야 그림이 제대로 나오더군요...아마 뒤에서 앞으로 저장하는듯...

Risty의 이미지

일단, 비트맵 형식은 MSDN에서(좀 찜찜하지만 -_-) BITMAPFILEHEADER, BITMAPINFO, BITMAPINFOHEADER 등을 검색하면 나올 것입니다. 데이터 형식이 Win32 기준이라는 것과, 데이터의 저장 방식이 Little Endian이라는 것만 명심하면 별로 어려울 것은 없을 것 같군요.

그리고 그림이 아래에서 위로 저장되는 것은 수학자들이 시스템을 설계해서 그렇다고 합니다. 컴퓨터 그래픽을 하는 사람들에게는 왼쪽 위가 시작이지만, 일반적으로 수학에서 이용하는 직교 좌표계는 왼쪽 아래가 시작입니다. 윈도에서 쓰는 GDI에 이러한 방법이 많이 이용됐다고 하네요.

shean0의 이미지

네..감사드립니다.
그런데.. unix에서는 어떻게 하죠...??

말씀하신부붑은 window상에서 하는 작업인데요.
제 경우는 소켓통신으로 해서... bmp-header를 제외한 부분[데이터] 만들
받을것 입니다.
그리고 이것에 bmp-header를 덧 붙여서 bmp파일을 만들고..

이것을 가지고..다시 jpeg..등등 변환 작업을 하려구 합니다.
뒷단은 어떻게 해야 할지 결정이 되었는데요.. 데이터를 가지고 bmp만드는 부분이 여전이 문제네요..

다시 조언을 부탁드립니다.

즉.. 로직으로 말씀 드리면..
read_data(sok,&buf[bmp-data]]);
input_bmp_header(buf); /* <==여기가 문제 */
fp= fopen( "sample.bmp","wb"); /* <== 여기가 문제 */
for( ; len ; ) fprintf("%c",buf);
fclose(fp);
close(sok);

fprintf("%c", buf

언제나 즐프를 꿈꾸며~

Risty의 이미지

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_2w1f.asp

여기 보시면 비트맵 헤더와 정보의 구조체가 있습니다. 그러면 여기서 구조체를 복제해서 프로그램에서 선언한 다음 쓰시면 됩니다. -_- 비트맵 파일에서 비트필드같은 것을 이용하지는 않으니 캐릭터 단위로 이용하면 별로 어려울 것은 없을 것 같습니다.

저도 윈도 API를 쓰지 않는 프로그램에서(돌기는 윈도에서 돌지만) 이렇게 짠 적이 있습니다.

cinsk의 이미지

BMP는 microsoft에서 만든 image format이니 MSDN을 본다고 해서 찝찝할 것 까지야 없겠죠. :)

하시려는 작업이 단순히 image format을 변경하는 것이라면 직접 하는 것도 좋지만 (Why reinvent the wheel?), 여러 라이브러리가 이미 나와 있으니 그걸 쓰시는 것이 훨씬 효율적일 것입니다.

대표적인 라이브러리로는 imlib2나, ImageMagick이 있습니다.
이 두 라이브러리의 홈페이지는 다음과 같습니다:

http://www.enlightenment.org/pages/imlib2.html
http://www.imagemagick.org/

기존의 image file을 다른 format으로 변경하는 것이라면 간단히 convert 프로그램을 쓸 수도 있으니 참고하세요. ;-)

유성욱의 이미지

다른 건 신경 안쓰셔도 되고요.. open(), save()만 보세요..

아 그리고 제가 Width와 Height를 2의 배수가 되도록 할 필요가 있어서 이상한

짓을 좀 했는데 신경 안쓰셔도 됩니다.

// Bmp.h: interface for the CBmp class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_BMP_H__1A8ED9A8_1B90_4D25_A698_12BA7FC174C3__INCLUDED_)
#define AFX_BMP_H__1A8ED9A8_1B90_4D25_A698_12BA7FC174C3__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define BMP_BYTE_PER_PIXEL  3

class CBmp
{
public:
    typedef enum {
        COLOR_256,
        COLOR_65K,
        COLOR_260K
    } COLOR_DEPTH;

    CBmp();
    CBmp( DWORD width, DWORD height, COLOR_DEPTH color = COLOR_65K );
    CBmp( CBmp& bmp );
    CBmp( DWORD width, DWORD height, CArray<DWORD, DWORD>& data, COLOR_DEPTH color = COLOR_65K );
    virtual ~CBmp();

    BOOL open( const char* path, COLOR_DEPTH color );
    BOOL save();
    void close();

    // 그림의 크기 및 모든 데이타를 초기화한다.
    void resize( DWORD width, DWORD height );

    const CString& getPath() { return m_path; }
    void  setPath( CString& path ) { m_path = path; }
    DWORD getWidth() { return m_width; }
    DWORD getHeight() { return m_height; }
    DWORD getImageSize();
    COLOR_DEPTH getColorDepth() { return m_color; }
    void setColorDepth( COLOR_DEPTH color ) { m_color = color; }

    // 2의 배수로 보정된 그림 크기를 알아낸다.
    DWORD getRealWidth() { return m_realWidth; }
    DWORD getRealHeight() { return m_realHeight; }

    // 그림의 크기를 2의 배수가 되도록 0이 패딩되어있다는 것을 가만해서 사용해야함
    BYTE* getImage()    { return m_image; }
    BYTE* getAllRed()   { return m_image; }
    BYTE* getAllGreen() { return m_green; }
    BYTE* getAllBlue()  { return m_blue; }

    // 각 색 데이타의 최대값과 최소값을 알아낸다.
    void findRedMaxMin( BYTE& min, BYTE& max ) { findMaxMin( m_image, min, max ); }
    void findGreenMaxMin( BYTE& min, BYTE& max ) { findMaxMin( m_green, min, max ); }
    void findBlueMaxMin( BYTE& min, BYTE& max ) { findMaxMin( m_blue, min, max ); }

    // 해당 좌표의 색값을 알아낸다.
    BYTE getRed( DWORD x, DWORD y )   { return m_image[ y * m_realWidth + x ]; }
    BYTE getGreen( DWORD x, DWORD y ) { return m_green[ y * m_realWidth + x ]; }
    BYTE getBlue( DWORD x, DWORD y )  { return m_blue[ y * m_realWidth + x ]; }

    // Hex 파일 생성
    BOOL generateHex();

    // 표현하고자 하는 색에 맞게 비트를 잘라준다.
    void adjustColor();

    const CBmp& operator = ( CBmp& bmp );

    static double calcMSE( CBmp& bmp1, CBmp& bmp2 );

private:
    void copy( CBmp& bmp );
    void findMaxMin( BYTE* pData, BYTE& min, BYTE& max );

    // RGB 별로 해당 비트수만큼만 걸러내고 나머지는 잘라버린다.
    void filtering( DWORD redBitNo, DWORD greenBitNo, DWORD blueBitNo );

    CString m_path;

    // 그림의 실제 크기
    DWORD m_width;
    DWORD m_height;

    // 이 BMP로 표현할 색상 종류
    COLOR_DEPTH m_color;

    // 그림의 실제 해상도가 아닌 2의 배수가 되도록 메모리를 잡을 것이다.
    // 2의 배수로 보정한 그림의 크기
    DWORD m_realWidth;
    DWORD m_realHeight;

    // 그림 데이타는 m_realWidth * m_realHeight * 3의 크기이고
    // Red, Green, Blue 순으로 데이타가 들어있다.
    BYTE* m_image;
    
    // Red는 m_image가 가리킴, Green과 Blue의 위치
    BYTE* m_green;
    BYTE* m_blue;
};

#endif // !defined(AFX_BMP_H__1A8ED9A8_1B90_4D25_A698_12BA7FC174C3__INCLUDED_)

// Bmp.cpp: implementation of the CBmp class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>
#include "Bmp.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBmp::CBmp()
{
    m_image = NULL;
    m_width = 0;
    m_height = 0;
}

CBmp::CBmp( DWORD width, DWORD height, COLOR_DEPTH color )
    : m_width( width ), m_height( height ), m_color( color )
{
    m_realWidth = m_width;
    if( m_width % 2 != 0 ) {
        ++m_realWidth;
    }
    m_realHeight = m_height;
    if( m_height % 2 != 0 ) {
        ++m_realHeight;
    }

    m_image = new BYTE[ m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL ];
    m_green = m_image + m_realWidth * m_realHeight;
    m_blue = m_image + m_realWidth * m_realHeight * 2;
    memset( m_image, 0, m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL );
}

CBmp::CBmp( CBmp& bmp )
{
    m_image = NULL;
    m_width = 0;
    m_height = 0;

    copy( bmp );
}

CBmp::CBmp( DWORD width, DWORD height, CArray<DWORD, DWORD>& data, COLOR_DEPTH color )
    : m_width( width ), m_height( height ), m_color( color )
{
    DWORD x, y;
    DWORD pos;

    m_realWidth = m_width;
    if( m_width % 2 != 0 ) {
        ++m_realWidth;
    }
    m_realHeight = m_height;
    if( m_height % 2 != 0 ) {
        ++m_realHeight;
    }

    m_image = new BYTE[ m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL ];
    m_green = m_image + m_realWidth * m_realHeight;
    m_blue = m_image + m_realWidth * m_realHeight * 2;
    memset( m_image, 0, m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL );

    for( pos = 0, y = 0; y < m_height; ++y ) {
        for( x = 0; x < m_width; ++x, ++pos ) {
            if( m_color == COLOR_65K ) {
                WORD rgb = (WORD)data[ y * m_width + x ];
                m_image[ pos ] = (BYTE)( ( rgb & 0xF800 ) >> 8 );
                m_green[ pos ] = (BYTE)( ( rgb & 0x07E0 ) >> 3 );
                m_blue[ pos ]  = (BYTE)( ( rgb & 0x001F ) << 3 );
            } else {
                DWORD rgb = data[ y * m_width + x ] ;
                m_image[ pos ] = (BYTE)( ( rgb & 0x0003F000 ) >> 10 );
                m_green[ pos ] = (BYTE)( ( rgb & 0x00000FC0 ) >> 4 );
                m_blue[ pos ]  = (BYTE)( ( rgb & 0x0000003F ) << 2 );
            }
            
        }

        if( m_width != m_realWidth ) {
            ++pos;
        }
    }
}

CBmp::~CBmp()
{
    delete[] m_image;
}

BOOL CBmp::open( const char* path, COLOR_DEPTH color )
{
    BOOL             retVal = TRUE;
    CFile            fileBmp;
    BITMAPFILEHEADER bfh;
    BITMAPINFOHEADER bih;
    DWORD            restHeaderSize;
    DWORD            imageSize;
    DWORD            realImageSize;
    BYTE             buffer[ 4096 ];
    BYTE*            image = NULL;
    BYTE*            red = NULL;
    BYTE*            green = NULL;
    BYTE*            blue = NULL;
    DWORD            x, y;
    DWORD            width4;
    DWORD            pixelAddr;

    ASSERT( path != NULL );

    if( fileBmp.Open( path, CFile::modeRead ) == FALSE ) {
        return FALSE;
    }

    // BITMAPFILEHEADER를 읽는다. (14 bytes)
    if( fileBmp.Read( (void*)&bfh, sizeof( bfh ) ) != sizeof( bfh ) ) {
        goto _fail;
    }

    // 파일 형식은 "BM"이어야한다.
    if( bfh.bfType != ((WORD)('M' << 8) | 'B') ) {
        goto _fail;
    }

    // BITMAPINFO를 읽는다. (44 bytes)
    if( fileBmp.Read( (void*)&bih, sizeof( bih ) ) != sizeof( bih ) ) {
        goto _fail;
    }

    // Bitmap 정보를 읽어들인다.
    m_width = bih.biWidth;
    m_height = bih.biHeight;

    // 그림 크기를 2의 배수에 맞게 계산한다.
    m_realWidth = m_width;
    if( m_width % 2 != 0 ) {
        ++m_realWidth;
    }
    m_realHeight = m_height;
    if( m_height % 2 != 0 ) {
        ++m_realHeight;
    }

    // 처리할 수 있는 Bit Count인지 검사한다.
    if( bih.biBitCount != 24 ) {
        goto _fail;
    }

    // 아직도 안 읽어들인 헤더가 있으면 읽어버린다.
    restHeaderSize = bfh.bfOffBits - sizeof( bfh ) - sizeof( bih );
    if( restHeaderSize > 0 ) {
        if( fileBmp.Read( buffer, restHeaderSize ) != restHeaderSize ) {
            goto _fail;
        }
    }

    // 이미지 내용을 읽어들인다.
    width4 = m_width * BMP_BYTE_PER_PIXEL;
    if( width4 % 4 != 0 ) {
        width4 += ( 4 - width4 % 4 );
    }
    imageSize = width4 * m_height;
    realImageSize = m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL;
    image = new BYTE[ imageSize ];
    m_image = new BYTE[ realImageSize ];
    if( image == NULL || m_image == NULL ) {
        goto _fail;
    }
    if( fileBmp.Read( image, imageSize ) != imageSize ) {
        goto _fail;
    }

    // Bitmap 포맷은 상하 반전된 구조이므로 상하 반전시킨다. R, G, B 순으로 데이타를 분리한다.
    memset( m_image, 0, realImageSize );
    red = m_image;
    m_green = green = m_image + m_realWidth * m_realHeight;
    m_blue = blue = m_image + m_realWidth * m_realHeight * 2;
    for( y = 0; y < m_height; ++y ) {
        for( x = 0; x < m_width; ++x ) {
            pixelAddr = ( m_height - 1 - y ) * width4 + x * BMP_BYTE_PER_PIXEL;

            *red = image[ pixelAddr + 2 ];
            ++red;

            *green = image[ pixelAddr + 1 ];
            ++green;

            *blue = image[ pixelAddr ];
            ++blue;
        }
        if( m_width != m_realWidth ) {
            *red = 0; ++red;
            *green = 0; ++green;
            *blue = 0; ++blue;
        }
    }

    m_path = path;
    m_color = color;

    // 색상에 맞게 bit 연산을 수행한다.
    adjustColor();

    if( 0 ) {
_fail:
        delete[] m_image;
        m_image = NULL;

        retVal = FALSE;
    }

    delete[] image;
    fileBmp.Close();

    return retVal;
}

BOOL CBmp::save()
{
    BOOL             retVal = TRUE;
    CFile            fileBmp;
    BYTE             zeros[ 8 ];
    DWORD            dw;
    BITMAPINFOHEADER bih;

    if( fileBmp.Open( m_path, CFile::modeCreate | CFile::modeWrite ) == FALSE ) {
        return FALSE;
    }

    /////////////////////////////////////////////////////////////////////
    // BITMAPFILEHEADER

    // bfType
    fileBmp.Write( "BM", 2 );

    // bfSize는 일단 뛰어넘는다. bfReserved1, bfReserved2
    memset( zeros, 0, 8 );
    fileBmp.Write( zeros, 8 );

    // bfOffBits
    dw = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
    fileBmp.Write( &dw, 4 );

    /////////////////////////////////////////////////////////////////////
    // BITMAPINFOHEADER
    bih.biSize = sizeof( BITMAPINFOHEADER );
    bih.biWidth = m_width;
    bih.biHeight = m_height;
    bih.biPlanes = 1;
    bih.biBitCount = 24;
    bih.biCompression = 0;
    bih.biSizeImage = 0;
    bih.biXPelsPerMeter = 3779;
    bih.biYPelsPerMeter = 3779;
    bih.biClrUsed = 0;
    bih.biClrImportant = 0;
    fileBmp.Write( &bih, sizeof( BITMAPINFOHEADER ) );

    /////////////////////////////////////////////////////////////////////
    // RGB 데이타를 기록한다.
    DWORD width4;
    int   x, y;
    BYTE  r, g, b;

    width4 = m_width * BMP_BYTE_PER_PIXEL;
    if( width4 % 4 != 0 ) {
        width4 += ( 4 - width4 % 4 );
    }

    for( y = m_height - 1; y >= 0; --y ) {
        for( x = 0; x < (int)m_width; ++x ) {
            r = m_image[ y * m_realWidth + x ];
            g = m_green[ y * m_realWidth + x ];
            b = m_blue[ y * m_realWidth + x ];
            
            fileBmp.Write( &b, 1 );
            fileBmp.Write( &g, 1 );
            fileBmp.Write( &r, 1 );
        }

        fileBmp.Write( zeros, width4 - m_width * BMP_BYTE_PER_PIXEL );
    }

    /////////////////////////////////////////////////////////////////////
    // BITMAPFILEHEADER에 bfSizefmf 기록한다.
    dw = fileBmp.GetLength();
    fileBmp.Seek( 2, CFile::begin );
    fileBmp.Write( &dw, 4 );
    fileBmp.Close();

    return retVal;
}

void CBmp::close()
{
    delete[] m_image;
    m_image = NULL;
}

void CBmp::resize( DWORD width, DWORD height )
{
    m_width = width;
    m_height = height;
    m_realWidth = m_width;
    if( m_width % 2 != 0 ) {
        ++m_realWidth;
    }
    m_realHeight = m_height;
    if( m_height % 2 != 0 ) {
        ++m_realHeight;
    }

    delete[] m_image;
    m_image = new BYTE[ m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL ];
    m_green = m_image + m_realWidth * m_realHeight;
    m_blue = m_image + m_realWidth * m_realHeight * 2;
    memset( m_image, 0, m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL );
}

DWORD CBmp::getImageSize() {
    DWORD size = m_width * m_height;

    switch( m_color ) {
    case COLOR_65K:  size *= sizeof( WORD ); break;
    case COLOR_260K: size *= sizeof( DWORD ); break;
    }

    return size;
}

BOOL CBmp::generateHex()
{
    union {
        DWORD d;
        WORD w;
        BYTE b[ 4 ];
    } tmp;

    DWORD x, y;
    DWORD imageSize, count;
    FILE* fileHex;
    CString hexFileName = m_path.Left( m_path.ReverseFind( '.' ) );

    hexFileName += ".hex";
    fileHex = fopen( hexFileName, "w" );
    if( fileHex == NULL ) {
        return FALSE;
    }
    fprintf( fileHex, "// HEX data for %s : %d x %d\n", (const char*)m_path, m_width, m_height );

    ////////////////////////////////////////////////////////
    // Hex 생성
    imageSize = m_width * m_height;
    for( y = 0, count = 0; y < m_height; ++y ) {
        for( x = 0; x < m_width; ++x ) {
            if( m_color == COLOR_65K ) {
                tmp.w = ( (WORD)getRed( x, y ) << 8 ) |
                        ( (WORD)getGreen( x, y ) << 3 ) |
                        ( (WORD)getBlue( x, y ) >> 3 );

                fprintf( fileHex, "0x%04x", tmp.w );
            } else {
                tmp.d = ( (DWORD)getRed( x, y ) << 10 ) |
                        ( (DWORD)getGreen( x, y ) << 4 ) |
                        ( (DWORD)getBlue( x, y ) >> 2 );
                fprintf( fileHex, "0x%08x", tmp.d );
            }

            if( ++count < imageSize ) {
                if( count % 10 == 0 ) {
                    fprintf( fileHex, ",\n" );
                } else {
                    fprintf( fileHex, "," );
                }
            }
        }
    }

    fclose( fileHex );

    return TRUE;
}

void CBmp::adjustColor()
{
    switch( m_color ) {
        case COLOR_256: filtering( 3, 3, 2 ); break;
        case COLOR_65K: filtering( 5, 6, 5 ); break;
        case COLOR_260K: filtering( 6, 6, 6 ); break;
    }
}

const CBmp& CBmp::operator = ( CBmp& bmp )
{
    copy( bmp );

    return *this;
}

double CBmp::calcMSE( CBmp& bmp1, CBmp& bmp2 )
{
    double error = 0;
    DWORD  x, y;
    BYTE   r1, r2;
    BYTE   g1, g2;
    BYTE   b1, b2;

    ASSERT( bmp1.getImage() != NULL && bmp2.getImage() != NULL );
    ASSERT( bmp1.getWidth() == bmp2.getWidth() );
    ASSERT( bmp1.getHeight() == bmp2.getHeight() );
    ASSERT( bmp1.getColorDepth() == bmp2.getColorDepth() );

    for( y = 0; y < bmp1.getHeight(); ++y ) {
        for( x = 0; x < bmp1.getWidth(); ++x ) {
            r1 = bmp1.getRed( x, y );   r2 = bmp2.getRed( x, y );
            g1 = bmp1.getGreen( x, y ); g2 = bmp2.getGreen( x, y );
            b1 = bmp1.getBlue( x, y );  b2 = bmp2.getBlue( x, y );

            switch( bmp1.getColorDepth() ) {
            case COLOR_256:
                r1 >>= ( 8 - 3 ); r2 >>= ( 8 - 3 );
                g1 >>= ( 8 - 3 ); g2 >>= ( 8 - 3 );
                b1 >>= ( 8 - 2 ); b2 >>= ( 8 - 2 );
                break;
            case COLOR_65K:  
                r1 >>= ( 8 - 5 ); r2 >>= ( 8 - 5 );
                g1 >>= ( 8 - 6 ); g2 >>= ( 8 - 6 );
                b1 >>= ( 8 - 5 ); b2 >>= ( 8 - 5 );
                break;
            case COLOR_260K:
                r1 >>= ( 8 - 6 ); r2 >>= ( 8 - 6 );
                g1 >>= ( 8 - 6 ); g2 >>= ( 8 - 6 );
                b1 >>= ( 8 - 6 ); b2 >>= ( 8 - 6 );
                break;
            }

            error += ( r1 - r2 ) * ( r1 - r2 );
            error += ( g1 - g2 ) * ( g1 - g2 );
            error += ( b1 - b2 ) * ( b1 - b2 );
        }
    }

    error /= ( bmp1.getRealWidth() * bmp1.getRealHeight() / 3 );

    return error;
}

void CBmp::copy( CBmp& bmp )
{
    DWORD bmpSize;

    m_path     = bmp.getPath();
    m_width    = bmp.getWidth();
    m_height   = bmp.getHeight();
    m_color    = bmp.getColorDepth();

    m_realWidth = m_width;
    if( m_width % 2 != 0 ) {
        ++m_realWidth;
    }
    m_realHeight = m_height;
    if( m_height % 2 != 0 ) {
        ++m_realHeight;
    }

    delete[] m_image;
    bmpSize = m_realWidth * m_realHeight * BMP_BYTE_PER_PIXEL;
    m_image = new BYTE[ bmpSize ];
    if( m_image != NULL ) {
        memcpy( m_image, bmp.getImage(), bmpSize );
    }

    m_green = m_image + m_realWidth * m_realHeight;
    m_blue = m_image + m_realWidth * m_realHeight * 2;
}

void CBmp::findMaxMin( BYTE* pData, BYTE& min, BYTE& max )
{
    DWORD size = m_realWidth * m_realHeight;
    DWORD a;

    max = 0;
    min = 255;

    for( a = 0; a < size; ++a ) {
        if( pData[ a ] > max ) {
            max = pData[ a ];
        }
        if( pData[ a ] < min ) {
            min = pData[ a ];
        }
    }
}

void CBmp::filtering( DWORD redBitNo, DWORD greenBitNo, DWORD blueBitNo )
{
    BYTE* red   = getAllRed();
    BYTE* green = getAllGreen();
    BYTE* blue  = getAllBlue();
    DWORD a;
    DWORD imageSize;
    BYTE  filter[] = { 0, 128, 192, 224, 240, 248, 252, 254, 255 };

    ASSERT( redBitNo <= 8 && greenBitNo <= 8 && blueBitNo <= 8 );

    imageSize = m_realWidth * m_realHeight;

    for( a = 0; a < imageSize; ++a ) {
        red[ a ]   &= filter[ redBitNo ];
        green[ a ] &= filter[ greenBitNo ];
        blue[ a ]  &= filter[ blueBitNo ];
    }
}

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.