Java Tip 60: Menyimpan file bitmap di Java

Tip ini melengkapi Tip 43 Java, yang mendemonstrasikan proses memuat file bitmap dalam aplikasi Java. Bulan ini, saya mengikuti tutorial tentang cara menyimpan gambar dalam file bitmap 24-bit dan kode snip yang dapat Anda gunakan untuk menulis file bitmap dari objek gambar.

Kemampuan untuk membuat file bitmap membuka banyak pintu jika Anda bekerja di lingkungan Microsoft Windows. Pada proyek terakhir saya, misalnya, saya harus menghubungkan Java dengan Microsoft Access. Program Java memungkinkan pengguna menggambar peta di layar. Peta tersebut kemudian dicetak dalam laporan Microsoft Access. Karena Java tidak mendukung OLE, satu-satunya solusi saya adalah membuat file bitmap peta dan memberi tahu laporan Microsoft Access tempat mengambilnya. Jika Anda pernah menulis aplikasi untuk mengirim gambar ke clipboard, tip ini mungkin berguna bagi Anda - terutama jika informasi ini diteruskan ke aplikasi Windows lainnya.

Format file bitmap

Format file bitmap mendukung 4-bit RLE (run length encoding), serta encoding 8-bit dan 24-bit. Karena kita hanya berurusan dengan format 24-bit, mari kita lihat struktur filenya.

File bitmap dibagi menjadi tiga bagian. Saya telah menyusunnya untuk Anda di bawah ini.

Bagian 1: Header file Bitmap

Header ini berisi informasi tentang ukuran jenis dan tata letak file bitmap. Strukturnya adalah sebagai berikut (diambil dari definisi struktur bahasa C):

typedef struct tagBITMAPFILEHEADER {UINT bfType; DWORD bfSize; UINT bfReserved1; UINT bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER;

Berikut deskripsi elemen kode dari daftar di atas:

  • bfType: Menunjukkan jenis file dan selalu disetel ke BM.
  • bfSize: Menentukan ukuran seluruh file dalam byte.
  • bfReserved1: Dicadangkan - harus disetel ke 0.
  • bfReserved2: Dicadangkan - harus disetel ke 0.
  • bfOffBits: Menentukan offset byte dari BitmapFileHeaderawal gambar.

Di sini Anda telah melihat bahwa tujuan dari bitmap header adalah untuk mengidentifikasi file bitmap. Setiap program yang membaca file bitmap menggunakan header bitmap untuk validasi file.

Bagian 2: Header informasi Bitmap

Header berikutnya, disebut header informasi, berisi semua properti gambar itu sendiri.

Berikut cara Anda menentukan informasi tentang dimensi dan format warna bitmap (DIB) independen perangkat Windows 3.0 (atau lebih tinggi):

typedef struct tagBITMAPINFOHEADER {DWORD biSize; LONG biWidth; PANJANG biHeight; WORD biPlanes; KATA biBitCount; DWORD biCompression; DWORD biSizeImage; BiXPelsPerMeter PANJANG; BiYPelsPerMeter PANJANG; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER;

Setiap elemen dari daftar kode di atas dijelaskan di bawah ini:

  • biSize: Menentukan jumlah byte yang dibutuhkan oleh BITMAPINFOHEADERstruktur.
  • biWidth: Menentukan lebar bitmap dalam piksel.
  • biHeight: Menentukan tinggi bitmap dalam piksel.
  • biPlanes: Menentukan jumlah pesawat untuk perangkat target. Anggota ini harus disetel ke 1.
  • biBitCount: Menentukan jumlah bit per piksel. Nilai ini harus 1, 4, 8, atau 24.
  • biCompression: Menentukan jenis kompresi untuk bitmap terkompresi. Dalam format 24-bit, variabel disetel ke 0.
  • biSizeImage: Menentukan ukuran gambar dalam byte. Ini sah untuk menetapkan anggota ini ke 0 jika bitmap dalam BI_RGBformat.
  • biXPelsPerMeter: Menentukan resolusi horizontal, dalam piksel per meter, dari perangkat target untuk bitmap. Aplikasi dapat menggunakan nilai ini untuk memilih bitmap dari grup sumber daya yang paling cocok dengan karakteristik perangkat saat ini.
  • biYPelsPerMeter: Menentukan resolusi vertikal, dalam piksel per meter, dari perangkat target untuk bitmap.
  • biClrUsed: Menentukan jumlah indeks warna dalam tabel warna yang sebenarnya digunakan oleh bitmap. Jika biBitCountdisetel ke 24, biClrUsedtentukan ukuran tabel warna referensi yang digunakan untuk mengoptimalkan kinerja palet warna Windows.
  • biClrImportant: Menentukan jumlah indeks warna yang dianggap penting untuk menampilkan bitmap. Jika nilainya 0, semua warna penting.

Sekarang semua informasi yang diperlukan untuk membuat gambar telah ditentukan.

Bagian 3: Gambar

Dalam format 24-bit, setiap piksel pada gambar diwakili oleh rangkaian tiga byte RGB yang disimpan sebagai BRG. Setiap baris pemindaian dilapisi hingga batas 4-byte. Untuk memperumit prosesnya, gambar disimpan dari bawah ke atas, artinya baris pindai pertama adalah baris pindai terakhir pada gambar. Gambar berikut menunjukkan header ( BITMAPHEADER) dan ( BITMAPINFOHEADER) dan bagian dari gambar. Setiap bagian dibatasi oleh bilah vertikal:

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 *

Sekarang, ke kode

Sekarang kita tahu semua tentang struktur file bitmap 24-bit, inilah yang Anda tunggu-tunggu: kode untuk menulis file bitmap dari objek gambar.

import java.awt. *; impor java.io. *; import java.awt.image. *; public class BMPFile extends Komponen {// --- Konstanta private private final static int BITMAPFILEHEADER_SIZE = 14; private int static final BITMAPINFOHEADER_SIZE = 40; // --- Deklarasi variabel privat // --- File header bitmap byte privat bitmapFileHeader [] = byte baru [14]; byte pribadi bfType [] = {'B', 'M'}; private int bfSize = 0; private int bfReserved1 = 0; private int bfReserved2 = 0; private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; // --- Header info bitmap byte pribadi bitmapInfoHeader [] = byte baru [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; // --- Bitmap data mentah private int bitmap []; // --- Bagian file pribadi FileOutputStream fo; // --- Konstruktor default public BMPFile () {} public void saveBitmap (String parFilename, Image parImage, int parWidth, int parHeight) {coba {fo = new FileOutputStream (parFilename); simpan (parImage, parWidth, parHeight); fo.close (); } catch (Exception saveEx) {saveEx.printStackTrace (); }} / * * SaveMethod adalah metode utama dari proses tersebut. Metode ini * akan memanggil metode convertImage untuk mengubah gambar memori menjadi * array byte; metode writeBitmapFileHeader membuat dan menulis * header file bitmap; writeBitmapInfoHeader membuat * informasi header; dan writeBitmap menulis gambarnya.* * / private void save (Image parImage, int parWidth, int parHeight) {coba {convertImage (parImage, parWidth, parHeight); writeBitmapFileHeader (); writeBitmapInfoHeader (); writeBitmap (); } catch (Exception saveEx) {saveEx.printStackTrace (); }} / * * convertImage mengubah gambar memori ke format bitmap (BRG). * Ini juga menghitung beberapa informasi untuk header info bitmap. * * / convertImage boolean pribadi (Image parImage, int parWidth, int parHeight) {int pad; bitmap = new int [parWidth * parHeight]; PixelGrabber pg = PixelGrabber baru (parImage, 0, 0, parWidth, parHeight, bitmap, 0, parWidth); coba {pg.grabPixels (); } menangkap (InterruptedException e) {e.printStackTrace (); kembali (salah); } pad = (4 - ((parWidth * 3)% 4)) * parHeight; biSizeImage = ((parWidth * parHeight) * 3) + pad;bfSize = biSizeImage + BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; biWidth = parWidth; biHeight = parHeight; kembali (benar); } / * * writeBitmap mengubah gambar yang dikembalikan dari pengambil piksel ke * format yang diperlukan. Ingat: garis pindai dibalik dalam * file bitmap! * * Setiap baris pemindaian harus dimasukkan ke dalam batas genap 4-byte. * / private void writeBitmap () {int size; nilai int; int j; int i; int rowCount; int rowIndex; int lastRowIndex; int pad; int padCount; byte rgb [] = byte baru [3]; size = (biWidth * biHeight) - 1; pad = 4 - ((biWidth * 3)% 4); if (pad == 4) // <==== Pad koreksi bug = 0; // <==== Koreksi bug rowCount = 1; padCount = 0; rowIndex = size - biWidth; lastRowIndex = rowIndex; coba {untuk (j = 0; j> 8) & 0xFF); rgb [2] = (byte) ((nilai >> 16) & 0xFF); fo.write (rgb);if (rowCount == biWidth) {padCount + = pad; untuk (i = 1; i> 8) & 0x00FF); kembali (retValue); } / * * * intToDWord mengonversi int menjadi kata ganda, di mana nilai kembalian * disimpan dalam larik 4 byte. * * / byte pribadi [] intToDWord (int parValue) {byte retValue [] = byte baru [4]; retValue [0] = (byte) (parValue & 0x00FF); retValue [1] = (byte) ((parValue >> 8) & 0x000000FF); retValue [2] = (byte) ((parValue >> 16) & 0x000000FF); retValue [3] = (byte) ((parValue >> 24) & 0x000000FF); kembali (retValue); }}0x00FF); retValue [1] = (byte) ((parValue >> 8) & 0x000000FF); retValue [2] = (byte) ((parValue >> 16) & 0x000000FF); retValue [3] = (byte) ((parValue >> 24) & 0x000000FF); kembali (retValue); }}0x00FF); retValue [1] = (byte) ((parValue >> 8) & 0x000000FF); retValue [2] = (byte) ((parValue >> 16) & 0x000000FF); retValue [3] = (byte) ((parValue >> 24) & 0x000000FF); kembali (retValue); }}

Kesimpulan

Itu saja yang ada untuk itu. Saya yakin Anda akan menemukan kelas ini sangat berguna, karena, mulai JDK 1.1.6, Java tidak mendukung penyimpanan gambar dalam format populer mana pun. JDK 1.2 akan menawarkan dukungan untuk membuat gambar JPEG, tetapi tidak mendukung bitmap. Jadi kelas ini masih akan mengisi celah di JDK 1.2.

Jika Anda bermain-main dengan kelas ini dan menemukan cara untuk memperbaikinya, beri tahu saya! E-mail saya muncul di bawah, bersama bio saya.

Jean-Pierre Dubé adalah konsultan Java independen. Ia mendirikan Infocom, terdaftar pada tahun 1988. Sejak itu, Infocom telah mengembangkan beberapa aplikasi kustom mulai dari manufaktur, manajemen dokumen, dan manajemen saluran listrik berskala besar. Dia memiliki pengalaman pemrograman yang luas di C, Visual Basic, dan yang terbaru Java, yang sekarang menjadi bahasa utama yang digunakan oleh perusahaannya. Salah satu proyek terbaru Infocom adalah API diagram yang akan segera tersedia sebagai rilis beta.

Artikel ini, "Java Tip 60: Menyimpan file bitmap di Java" pada awalnya diterbitkan oleh JavaWorld.