Petua Java 60: Menyimpan fail bitmap di Java

Tip ini melengkapkan Java Tip 43, yang menunjukkan proses memuat file bitmap dalam aplikasi Java. Bulan ini, saya mengikuti tutorial cara menyimpan gambar dalam fail bitmap 24-bit dan potongan kod yang boleh anda gunakan untuk menulis fail bitmap dari objek gambar.

Keupayaan untuk membuat fail bitmap membuka banyak pintu jika anda bekerja di persekitaran Microsoft Windows. Sebagai contoh, pada projek terakhir saya, saya terpaksa menghubungkan Java dengan Microsoft Access. Program Java memungkinkan pengguna menggambar peta di layar. Peta itu kemudian dicetak dalam laporan Microsoft Access. Oleh kerana Java tidak menyokong OLE, satu-satunya penyelesaian saya ialah membuat fail peta bitmap dan memberitahu laporan Microsoft Access di mana mengambilnya. Sekiranya anda pernah menulis aplikasi untuk menghantar gambar ke papan keratan, tip ini mungkin berguna untuk anda - terutamanya jika maklumat ini dihantar ke aplikasi Windows yang lain.

Format fail bitmap

Format fail bitmap menyokong RLE 4-bit (pengekodan jangka panjang), serta pengekodan 8-bit dan 24-bit. Kerana kita hanya berurusan dengan format 24-bit, mari kita lihat struktur failnya.

Fail bitmap terbahagi kepada tiga bahagian. Saya telah membentangkannya untuk anda di bawah.

Bahagian 1: Tajuk fail Bitmap

Header ini mengandungi maklumat mengenai jenis ukuran dan susun atur fail bitmap. Strukturnya adalah seperti berikut (diambil dari definisi struktur bahasa C):

tag typedef structBITMAPFILEHEADER {UINT bfType; DWORD bfSize; UINT bfDisimpan1; UINT bfDisimpan2; DWORD bfOffBits; } BITMAPFILEHEADER;

Berikut adalah penerangan elemen kod dari senarai di atas:

  • bfType: Menunjukkan jenis fail dan selalu ditetapkan ke BM.
  • bfSize: Menentukan ukuran keseluruhan fail dalam bait.
  • bfReserved1: Terpelihara - mesti ditetapkan ke 0.
  • bfReserved2: Terpelihara - mesti ditetapkan ke 0.
  • bfOffBits: Menentukan offset bait dari BitmapFileHeaderawal gambar.

Di sini anda telah melihat bahawa tujuan pengepala bitmap adalah untuk mengenal pasti fail bitmap. Setiap program yang membaca fail bitmap menggunakan tajuk bitmap untuk pengesahan fail.

Bahagian 2: Tajuk maklumat Bitmap

Header seterusnya, yang disebut header maklumat, mengandungi semua sifat gambar itu sendiri.

Inilah cara anda menentukan maklumat mengenai dimensi dan format warna bitmap bebas peranti (3.0 atau lebih tinggi) (DIB):

tag typedef structBITMAPINFOHEADER {DWORD biSize; BiWidth PANJANG; BiHeight PANJANG; Kata Kunci biPlan; KATA biBitCount; DWORD biCompression; DWORD biSizeImage; BiXPelsPerMeter PANJANG; BiYPelsPerMeter PANJANG; DWORD biClrUsed; DWORD biClrIpenting; } BITMAPINFOHEADER;

Setiap elemen penyenaraian kod di atas dijelaskan di bawah:

  • biSize: Menentukan bilangan bait yang diperlukan oleh BITMAPINFOHEADERstruktur.
  • biWidth: Menentukan lebar bitmap dalam piksel.
  • biHeight: Menentukan ketinggian bitmap dalam piksel.
  • biPlanes: Menentukan bilangan pesawat untuk peranti sasaran. Ahli ini mesti ditetapkan ke 1.
  • biBitCount: Menentukan bilangan bit per piksel. Nilai ini mestilah 1, 4, 8 atau 24.
  • biCompression: Menentukan jenis pemampatan untuk bitmap yang dimampatkan. Dalam format 24-bit, pemboleh ubah ditetapkan ke 0.
  • biSizeImage: Menentukan ukuran dalam bait gambar. Adalah sah untuk menetapkan anggota ini ke 0 jika bitmap dalam BI_RGBformat.
  • biXPelsPerMeter: Menentukan resolusi mendatar, dalam piksel per meter, dari peranti sasaran untuk bitmap. Aplikasi boleh menggunakan nilai ini untuk memilih peta bit dari kumpulan sumber yang paling sesuai dengan ciri-ciri peranti semasa.
  • biYPelsPerMeter: Menentukan resolusi menegak, dalam piksel per meter, dari peranti sasaran untuk bitmap.
  • biClrUsed: Menentukan bilangan indeks warna dalam jadual warna yang sebenarnya digunakan oleh bitmap. Jika biBitCountdiatur ke 24, biClrUsedtentukan ukuran tabel warna rujukan yang digunakan untuk mengoptimumkan prestasi palet warna Windows.
  • biClrImportant: Menentukan bilangan indeks warna yang dianggap penting untuk memaparkan bitmap. Sekiranya nilai ini adalah 0, semua warna adalah penting.

Sekarang semua maklumat yang diperlukan untuk membuat gambar telah ditentukan.

Bahagian 3: Gambar

Dalam format 24-bit, setiap piksel dalam gambar diwakili oleh rangkaian tiga byte RGB yang disimpan sebagai BRG. Setiap garis imbasan dilekatkan pada batas genap 4-byte. Untuk menyukarkan prosesnya sedikit lagi, gambar disimpan dari bawah ke atas, yang bermaksud bahawa garis imbasan pertama adalah garis imbasan terakhir dalam gambar. Gambar berikut menunjukkan kedua-dua tajuk ( BITMAPHEADER) dan ( BITMAPINFOHEADER) dan sebahagian gambar. Setiap bahagian dibatasi oleh bar menegak:

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, teruskan kodnya

Sekarang setelah kita mengetahui semua tentang struktur fail bitmap 24-bit, inilah yang anda nantikan: kod untuk menulis fail bitmap dari objek gambar.

import java.awt. *; import java.io. *; import java.awt.image. *; kelas awam BMPFile meluaskan Komponen {// --- Pemalar persendirian persendirian akhir statik int BITMAPFILEHEADER_SIZE = 14; stat statik persendirian int BITMAPINFOHEADER_SIZE = 40; // --- Pengisytiharan pemboleh ubah peribadi // --- Bitmap header fail byte peribadi bitmapFileHeader [] = bait baru [14]; bfType byte peribadi [] = {'B', 'M'}; int bfSize peribadi = 0; int peribadi bfReserve1 = 0; int peribadi bfReserve2 = 0; int bfOffBits peribadi = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; // --- Bitmap info header byte peribadi bitmapInfoHeader [] = bait baru [40]; int int biSize = BITMAPINFOHEADER_SIZE; int biWidth peribadi = 0; int intHHight = 0; intPeringkat int peribadi = 1; int biBitCount swasta = 24; intCompression int peribadi = 0; int int biSizeImage = 0x030000;int biXPelsPerMeter peribadi = 0x0; int int biYPelsPerMeter = 0x0; int int biClrUsed = 0; int intClClImportant = 0; // --- bitmap data peribadi int bitmap peribadi []; // --- Bahagian fail peribadi FileOutputStream fo; // --- BMPFile awam konstruktor lalai () {} public void saveBitmap (String parFilename, Image parImage, int parWidth, int parHeight) {cuba {fo = new FileOutputStream (parFilename); simpan (parImage, parWidth, parHeight); fo.tutup (); } tangkapan (Pengecualian saveEx) {saveEx.printStackTrace (); }} / * * Kaedah save adalah kaedah utama proses. Kaedah ini * akan memanggil kaedah convertImage untuk menukar imej memori menjadi * array byte; kaedah writeBitmapFileHeader membuat dan menulis * tajuk fail bitmap; writeBitmapInfoHeader membuat * maklumat pengepala; dan writeBitmap menulis gambar.* * / save void peribadi (Image parImage, int parWidth, int parHeight) {cuba {convertImage (parImage, parWidth, parHeight); tulisBitmapFileHeader (); tulisBitmapInfoHeader (); tulisBitmap (); } tangkapan (Pengecualian saveEx) {saveEx.printStackTrace (); }} / * * convertImage menukar imej memori ke format bitmap (BRG). * Ia juga mengumpulkan beberapa maklumat untuk tajuk maklumat bitmap. * * / peribadi boolean convertImage (Image parImage, int parWidth, int parHeight) {int pad; bitmap = int baru [parWidth * parHeight]; PixelGrabber pg = PixelGrabber baru (parImage, 0, 0, parWidth, parHeight, bitmap, 0, parWidth); cuba {pg.grabPixels (); } tangkapan (InterruptException e) {e.printStackTrace (); kembali (palsu); } pad = (4 - ((parWidth * 3)% 4)) * parHeight; biSizeImage = ((parWidth * parHeight) * 3) + pad;bfSize = biSizeImage + BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; biWidth = parWidth; biHeight = parHeight; kembali (benar); } / * * writeBitmap menukar gambar yang dikembalikan dari piksel piksel ke * format yang diperlukan. Ingat: garis imbasan terbalik dalam * fail bitmap! * * Setiap baris imbasan mesti dilapisi ke batas 4-bait yang sama rata. * / persendirian kosongBitmap () {int saiz; nilai int; int j; int i; int rowCount; int rowIndex; int lastRowIndex; pad int; int padCount; bait rgb [] = bait baru [3]; saiz = (biWidth * biHeight) - 1; pad = 4 - ((biWidth * 3)% 4); if (pad == 4) // <==== Pad pembetulan pepijat = 0; // <==== Baris pembetulan pepijatCount = 1; padCount = 0; rowIndex = size - biWidth; lastRowIndex = rowIndex; cuba {untuk (j = 0; j> 8) & 0xFF); rgb [2] = (bait) ((nilai >> 16) & 0xFF); fo.write (rgb);jika (rowCount == biWidth) {padCount + = pad; untuk (i = 1; i> 8) & 0x00FF); pulangan (retValue); } / * * * intToDWord menukar int ke kata ganda, di mana nilai return * disimpan dalam tatasusunan 4-bait. * * / bait peribadi [] intToDWord (int parValue) {byte retValue [] = bait baru [4]; retValue [0] = (bait) (nilai par & 0x00FF); retValue [1] = (bait) ((nilai par >> 8) & 0x000000FF); retValue [2] = (bait) ((nilai par >> 16) & 0x000000FF); retValue [3] = (bait) ((nilai par >> 24) & 0x000000FF); pulangan (retValue); }}0x00FF); retValue [1] = (bait) ((nilai par >> 8) & 0x000000FF); retValue [2] = (bait) ((nilai par >> 16) & 0x000000FF); retValue [3] = (bait) ((nilai par >> 24) & 0x000000FF); pulangan (retValue); }}0x00FF); retValue [1] = (bait) ((nilai par >> 8) & 0x000000FF); retValue [2] = (bait) ((nilai par >> 16) & 0x000000FF); retValue [3] = (bait) ((nilai par >> 24) & 0x000000FF); pulangan (retValue); }}

Kesimpulannya

Itu sahaja yang ada. Saya pasti anda akan mendapat kelas ini sangat berguna, kerana, mulai JDK 1.1.6, Java tidak menyokong menyimpan gambar dalam format yang popular. JDK 1.2 akan menawarkan sokongan untuk membuat gambar JPEG, tetapi tidak menyokong bitmap. Jadi kelas ini masih akan mengisi jurang di JDK 1.2.

Sekiranya anda bermain-main dengan kelas ini dan mencari kaedah untuk memperbaikinya, beritahu saya! E-mel saya muncul di bawah, bersama dengan bio saya.

Jean-Pierre Dubé adalah perunding bebas Java. Dia mendirikan Infocom, yang didaftarkan pada tahun 1988. Sejak itu, Infocom telah mengembangkan beberapa aplikasi khusus mulai dari pembuatan, pengurusan dokumen, dan pengurusan talian kuasa elektrik skala besar. Dia memiliki pengalaman pengaturcaraan yang luas dalam C, Visual Basic, dan baru-baru ini Java, yang sekarang menjadi bahasa utama yang digunakan oleh syarikatnya. Salah satu projek Infocom baru-baru ini adalah API diagram yang akan tersedia sebagai peluncuran beta tidak lama lagi.

Kisah ini, "Petua Java 60: Menyimpan fail bitmap di Java" awalnya diterbitkan oleh JavaWorld.