Java Tip 60 : Java로 비트 맵 파일 저장

이 팁은 Java 애플리케이션에서 비트 맵 파일을로드하는 프로세스를 보여준 Java Tip 43을 보완합니다. 이번 달에는 24 비트 비트 맵 파일에 이미지를 저장하는 방법과 이미지 객체에서 비트 맵 파일을 작성하는 데 사용할 수있는 코드 스닙에 대한 자습서를 따라갑니다.

Microsoft Windows 환경에서 작업하는 경우 비트 맵 파일을 만드는 기능은 많은 문을 엽니 다. 예를 들어, 마지막 프로젝트에서 Java와 Microsoft Access를 인터페이스해야했습니다. 자바 프로그램을 통해 사용자는 화면에지도를 그릴 수있었습니다. 그런 다음지도가 Microsoft Access 보고서에 인쇄되었습니다. Java는 OLE를 지원하지 않기 때문에 내 유일한 해결책은 맵의 비트 맵 파일을 만들고 Microsoft Access 보고서에 가져올 위치를 알려주는 것입니다. 이미지를 클립 보드로 보내기 위해 응용 프로그램을 작성해야했다면이 팁이 유용 할 수 있습니다. 특히이 정보가 다른 Windows 응용 프로그램으로 전달되는 경우에 유용합니다.

비트 맵 파일의 형식

비트 맵 파일 형식은 4 비트 RLE (실행 길이 인코딩)와 8 비트 및 24 비트 인코딩을 지원합니다. 24 비트 형식 만 다루기 때문에 파일의 구조를 살펴 보겠습니다.

비트 맵 파일은 세 부분으로 나뉩니다. 아래에 정리해 놓았습니다.

섹션 1 : 비트 맵 파일 헤더

이 헤더에는 비트 맵 파일의 유형 크기 및 레이아웃에 대한 정보가 포함되어 있습니다. 구조는 다음과 같습니다 (C 언어 구조 정의에서 가져옴).

typedef 구조체 tagBITMAPFILEHEADER {UINT bfType; DWORD bfSize; UINT bfReserved1; UINT bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER;

다음은 위 목록의 코드 요소에 대한 설명입니다.

  • bfType: 파일 유형을 나타내며 항상 BM으로 설정됩니다.
  • bfSize: 전체 파일의 크기를 바이트 단위로 지정합니다.
  • bfReserved1: 예약 됨-0으로 설정해야합니다.
  • bfReserved2: 예약 됨-0으로 설정해야합니다.
  • bfOffBits: BitmapFileHeader에서 이미지 시작 까지의 바이트 오프셋을 지정합니다 .

여기에서 비트 맵 헤더의 목적이 비트 맵 파일을 식별하는 것을 보았습니다. 비트 맵 파일을 읽는 모든 프로그램은 파일 유효성 검사를 위해 비트 맵 헤더를 사용합니다.

섹션 2 : 비트 맵 정보 헤더

정보 헤더 라고하는 다음 헤더 에는 이미지 자체의 모든 속성이 포함됩니다.

Windows 3.0 (이상) 장치 독립 비트 맵 (DIB)의 크기 및 색상 형식에 대한 정보를 지정하는 방법은 다음과 같습니다.

typedef 구조체 tagBITMAPINFOHEADER {DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; 단어 biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClr 중요; } BITMAPINFOHEADER;

위 코드 목록의 각 요소는 다음과 같습니다.

  • biSize: BITMAPINFOHEADER구조에 필요한 바이트 수를 지정합니다 .
  • biWidth: 비트 맵의 ​​너비를 픽셀 단위로 지정합니다.
  • biHeight: 비트 맵의 ​​높이를 픽셀 단위로 지정합니다.
  • biPlanes: 대상 장치의 평면 수를 지정합니다. 이 멤버는 1로 설정해야합니다.
  • biBitCount: 픽셀 당 비트 수를 지정합니다. 이 값은 1, 4, 8 또는 24 여야합니다.
  • biCompression: 압축 된 비트 맵의 ​​압축 유형을 지정합니다. 24 비트 형식에서 변수는 0으로 설정됩니다.
  • biSizeImage : 이미지의 크기 (바이트)를 지정합니다. 비트 맵이 BI_RGB형식 이면이 멤버를 0으로 설정하는 것이 유효 합니다.
  • biXPelsPerMeter : 비트 맵에 대한 대상 장치의 수평 해상도 (미터당 픽셀)를 지정합니다. 응용 프로그램은이 값을 사용하여 현재 장치의 특성과 가장 일치하는 자원 그룹에서 비트 맵을 선택할 수 있습니다.
  • biYPelsPerMeter : 비트 맵에 대한 대상 장치의 수직 해상도 (미터당 픽셀)를 지정합니다.
  • biClrUsed : 비트 맵에서 실제로 사용하는 색상 표의 색상 인덱스 수를 지정합니다. 이 biBitCount24로 설정된 경우 biClrUsedWindows 색상 팔레트의 성능을 최적화하는 데 사용되는 참조 색상 표의 크기를 지정합니다.
  • biClr 중요 : 비트 맵 표시에 중요한 것으로 간주되는 색상 인덱스의 수를 지정합니다. 이 값이 0이면 모든 색상이 중요합니다.

이제 이미지를 만드는 데 필요한 모든 정보가 정의되었습니다.

섹션 3 : 이미지

24 비트 형식에서 이미지의 각 픽셀은 BRG로 저장된 일련의 3 바이트 RGB로 표시됩니다. 각 스캔 라인은 짝수 4 바이트 경계까지 채워집니다. 프로세스를 조금 더 복잡하게하기 위해 이미지는 아래에서 위로 저장됩니다. 즉, 첫 번째 스캔 라인이 이미지의 마지막 스캔 라인입니다. 다음 그림은 머리글 ( BITMAPHEADER)과 ( BITMAPINFOHEADER) 및 이미지의 일부를 보여줍니다 . 각 섹션은 수직 막대로 구분됩니다.

0000000000 4D42 B536 0002 0000 0000 0036 0000 | 0028 0000000020 0000 0107 0000 00E0 0000 0001 0018 0000 0000000040 0000 B500 0002 0EC4 0000 0EC4 0000 0000 0000000060 0000 0000 0000 | FFFF FFFF FFFF FFFF FFFF 0000000100 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF *

이제 코드에 대해

이제 우리는 24 비트 비트 맵 파일의 구조에 대해 모두 알았으므로 여기에 여러분이 기다려온 것이 있습니다. 이미지 객체에서 비트 맵 파일을 작성하는 코드입니다.

import java.awt. *; import java.io. *; import java.awt.image. *; public class BMPFile extends Component {// --- private 상수 private final static int BITMAPFILEHEADER_SIZE = 14; 개인 최종 정적 int BITMAPINFOHEADER_SIZE = 40; // --- 전용 변수 선언 // --- 비트 맵 파일 헤더 전용 바이트 bitmapFileHeader [] = new byte [14]; 개인 바이트 bfType [] = { 'B', 'M'}; private int bfSize = 0; private int bfReserved1 = 0; private int bfReserved2 = 0; private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; // --- 비트 맵 정보 헤더 전용 바이트 bitmapInfoHeader [] = 새 바이트 [40]; private int biSize = BITMAPINFOHEADER_SIZE; private int biWidth = 0; private int biHeight = 0; private int biPlanes = 1; private int biBitCount = 24; private int biCompression = 0; private int biSizeImage = 0x030000;private int biXPelsPerMeter = 0x0; private int biYPelsPerMeter = 0x0; private int biClrUsed = 0; private int biClrImportant = 0; // --- 비트 맵 원시 데이터 private int bitmap []; // --- 파일 섹션 private FileOutputStream fo; // --- 기본 생성자 public BMPFile () {} public void saveBitmap (String parFilename, Image parImage, int parWidth, int parHeight) {try {fo = new FileOutputStream (parFilename); 저장 (parImage, parWidth, parHeight); fo.close (); } catch (예외 saveEx) {saveEx.printStackTrace (); }} / * * saveMethod는 프로세스의 주요 메소드입니다. 이 메서드는 * convertImage 메서드를 호출하여 메모리 이미지를 바이트 배열로 변환합니다. writeBitmapFileHeader 메소드는 비트 맵 파일 헤더를 작성하고 씁니다. writeBitmapInfoHeader는 * 정보 헤더를 생성합니다. writeBitmap은 이미지를 씁니다.* * / private void save (Image parImage, int parWidth, int parHeight) {try {convertImage (parImage, parWidth, parHeight); writeBitmapFileHeader (); writeBitmapInfoHeader (); writeBitmap (); } catch (예외 saveEx) {saveEx.printStackTrace (); }} / * * convertImage는 메모리 이미지를 비트 맵 형식 (BRG)으로 변환합니다. * 또한 비트 맵 정보 헤더에 대한 일부 정보를 계산합니다. * * / private boolean convertImage (Image parImage, int parWidth, int parHeight) {int pad; 비트 맵 = new int [parWidth * parHeight]; PixelGrabber pg = 새로운 PixelGrabber (parImage, 0, 0, parWidth, parHeight, 비트 맵, 0, parWidth); {pg.grabPixels (); } catch (InterruptedException e) {e.printStackTrace (); 반환 (거짓); } pad = (4-((parWidth * 3) % 4)) * parHeight; biSizeImage = ((parWidth * parHeight) * 3) + pad;bfSize = biSizeImage + BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; biWidth = parWidth; biHeight = parHeight; 반환 (true); } / * * writeBitmap은 픽셀 그래버에서 반환 된 이미지를 필요한 형식으로 * 변환합니다. 기억하십시오 : 스캔 라인은 * 비트 맵 파일에서 반전됩니다! * * 각 스캔 라인은 4 바이트 경계까지 채워 져야합니다. * / private void writeBitmap () {int size; int 값; int j; int i; int rowCount; int rowIndex; int lastRowIndex; int 패드; int padCount; 바이트 rgb [] = 새 바이트 [3]; 크기 = (biWidth * biHeight)-1; 패드 = 4-((biWidth * 3) % 4); if (pad == 4) // <==== 버그 수정 패드 = 0; // <==== 버그 수정 rowCount = 1; padCount = 0; rowIndex = 크기-biWidth; lastRowIndex = rowIndex; {for (j = 0; j> 8) & 0xFF); rgb [2] = (바이트) ((값 >> 16) & 0xFF); fo.write (rgb);if (rowCount == biWidth) {padCount + = pad; for (i = 1; i> 8) & 0x00FF); 반환 (retValue); } / * * * intToDWord는 int를 더블 워드로 변환합니다. 여기서 * 반환 값은 4 바이트 배열에 저장됩니다. * * / private byte [] intToDWord (int parValue) {byte retValue [] = 새로운 byte [4]; retValue [0] = (바이트) (parValue & 0x00FF); retValue [1] = (바이트) ((parValue >> 8) & 0x000000FF); retValue [2] = (바이트) ((parValue >> 16) & 0x000000FF); retValue [3] = (바이트) ((parValue >> 24) & 0x000000FF); 반환 (retValue); }}0x00FF); retValue [1] = (바이트) ((parValue >> 8) & 0x000000FF); retValue [2] = (바이트) ((parValue >> 16) & 0x000000FF); retValue [3] = (바이트) ((parValue >> 24) & 0x000000FF); 반환 (retValue); }}0x00FF); retValue [1] = (바이트) ((parValue >> 8) & 0x000000FF); retValue [2] = (바이트) ((parValue >> 16) & 0x000000FF); retValue [3] = (바이트) ((parValue >> 24) & 0x000000FF); 반환 (retValue); }}

결론

그게 전부입니다. JDK 1.1.6부터 Java는 널리 사용되는 형식의 이미지 저장을 지원하지 않기 때문에이 클래스가 매우 유용하다고 확신합니다. JDK 1.2는 JPEG 이미지 생성을 지원하지만 비트 맵은 지원하지 않습니다. 따라서이 클래스는 JDK 1.2에서 여전히 공백을 채울 것입니다.

이 클래스를 가지고 놀고 개선 할 방법을 찾으면 알려주세요! 내 이메일은 내 약력과 함께 아래에 표시됩니다.

Jean-Pierre Dubé는 독립적 인 Java 컨설턴트입니다. 그는 1988 년에 등록 된 Infocom을 설립했습니다. 그 이후로 Infocom은 제조, 문서 관리 및 대규모 전력선 관리에 이르는 여러 맞춤형 애플리케이션을 개발했습니다. 그는 C, Visual Basic 및 가장 최근에 회사에서 사용하는 기본 언어 인 Java에 대한 광범위한 프로그래밍 경험을 가지고 있습니다. Infocom의 최근 프로젝트 중 하나는 곧 베타 릴리스로 제공 될 다이어그램 API입니다.

이 스토리 "Java Tip 60 : Java에서 비트 맵 파일 저장"은 원래 JavaWorld에서 게시했습니다.