Programování

Tip Java 60: Ukládání bitmapových souborů v Javě

Tento tip doplňuje Java Tip 43, který demonstroval proces načítání bitmapových souborů v aplikacích Java. Tento měsíc navazuji na výukový program, jak ukládat obrázky do 24bitových bitmapových souborů, a fragment kódu, který můžete použít k zápisu bitmapového souboru z obrazového objektu.

Možnost vytvořit bitmapový soubor otevírá mnoho dveří, pokud pracujete v prostředí Microsoft Windows. Například na mém posledním projektu jsem musel propojit prostředí Java s aplikací Microsoft Access. Program Java umožnil uživateli nakreslit mapu na obrazovku. Mapa byla poté vytištěna ve zprávě Microsoft Access. Protože Java nepodporuje OLE, mým jediným řešením bylo vytvořit bitmapový soubor mapy a říct sestavě Microsoft Access, kde ji vyzvednout. Pokud jste někdy museli psát aplikaci pro odeslání obrázku do schránky, tento tip vám může být užitečný - zejména pokud jsou tyto informace předávány jiné aplikaci Windows.

Formát bitmapového souboru

Formát bitmapového souboru podporuje 4bitové RLE (kódování délky běhu), stejně jako 8bitové a 24bitové kódování. Protože máme co do činění pouze s 24bitovým formátem, podívejme se na strukturu souboru.

Bitmapový soubor je rozdělen do tří částí. Rozložil jsem je pro vás níže.

Část 1: Záhlaví bitmapového souboru

Tato hlavička obsahuje informace o velikosti typu a rozložení bitmapového souboru. Struktura je následující (převzato z definice struktury jazyka C):

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

Zde je popis prvků kódu z výše uvedeného seznamu:

  • bfType: Označuje typ souboru a je vždy nastaven na BM.
  • bfSize: Určuje velikost celého souboru v bajtech.
  • bfReserved1: Rezervováno - musí být nastaveno na 0.
  • bfReserved2: Rezervováno - musí být nastaveno na 0.
  • bfOffBits: Určuje posunutí bajtu od BitmapFileHeader na začátek obrazu.

Zde jste viděli, že účelem záhlaví bitmapy je identifikovat bitmapový soubor. Každý program, který čte bitmapové soubory, používá záhlaví bitmapy pro ověření souboru.

Část 2: Záhlaví bitmapových informací

Další záhlaví s názvem informační záhlaví, obsahuje všechny vlastnosti samotného obrázku.

Tady je způsob, jakým určíte informace o dimenzi a barevném formátu bitmapy nezávislé na zařízení Windows 3.0 (nebo vyšší) (DIB):

typedef struct tagBITMAPINFOHEADER {DWORD biSize; DLOUHÁ ŠÍŘKA; DLOUHÁ biHeight; Slovní dvojplošníky; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; DLOUHÝ biXPelsPerMeter; DLOUHÝ biYPelsPerMeter; DWORD biClrUsed; DWORD biClrDůležité; } BITMAPINFOHEADER; 

Každý prvek výše uvedeného výpisu kódu je popsán níže:

  • biSize: Určuje počet bajtů požadovaný parametrem BITMAPINFOHEADER struktura.
  • biWidth: Určuje šířku bitmapy v pixelech.
  • biHeight: Určuje výšku bitmapy v pixelech.
  • dvojplošníky: Určuje počet letadel pro cílové zařízení. Tento člen musí být nastaven na 1.
  • biBitCount: Určuje počet bitů na pixel. Tato hodnota musí být 1, 4, 8 nebo 24.
  • biCompression: Určuje typ komprese pro komprimovanou bitmapu. Ve 24bitovém formátu je proměnná nastavena na 0.
  • biSizeImage: Určuje velikost obrázku v bajtech. Je platné nastavit tohoto člena na 0, pokud je bitmapa v BI_RGB formát.
  • biXPelsPerMeter: Určuje horizontální rozlišení cílového zařízení pro bitmapu v pixelech na metr. Aplikace může pomocí této hodnoty vybrat bitmapu ze skupiny prostředků, která nejlépe odpovídá charakteristikám aktuálního zařízení.
  • biYPelsPerMeter: Určuje vertikální rozlišení cílového zařízení pro bitmapu v pixelech na metr.
  • biClrUsed: Určuje počet indexů barev v tabulce barev, které bitmapa skutečně používá. Li biBitCount je nastavena na 24, biClrUsed Určuje velikost tabulky referenčních barev použitých k optimalizaci výkonu barevných palet Windows.
  • biClrImportant: Určuje počet barevných indexů považovaných za důležité pro zobrazení bitmapy. Pokud je tato hodnota 0, jsou důležité všechny barvy.

Nyní jsou definovány všechny informace potřebné k vytvoření obrazu.

Část 3: Obrázek

Ve 24bitovém formátu je každý pixel v obraze představován řadou tří bajtů RGB uložených jako BRG. Každý řádek skenování je vyplněn rovnoměrnou hranicí 4 bajtů. Aby se proces ještě více zkomplikoval, obraz se ukládá zdola nahoru, což znamená, že první řádek skenování je poslední řádek skenování v obrázku. Následující obrázek ukazuje obě záhlaví (BITMAPHEADER) a (BITMAPINFOHEADER) a část obrázku. Každá sekce je ohraničena svislou čarou:

 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 * 

Nyní ke kódu

Nyní, když víme vše o struktuře 24bitového bitmapového souboru, je tady to, na co jste čekali: kód pro zápis bitmapového souboru z obrazového objektu.

importovat java.awt. *; importovat java.io. *; importovat java.awt.image. *; public class BMPFile extends Component {// --- Private constants private final static int BITMAPFILEHEADER_SIZE = 14; soukromá konečná statická int BITMAPINFOHEADER_SIZE = 40; // --- Deklarace soukromé proměnné // --- Záhlaví bitmapového souboru soukromý bajt bitmapFileHeader [] = nový bajt [14]; private byte bfType [] = {'B', 'M'}; private int bfSize = 0; private int bfReserved1 = 0; private int bfReserved2 = 0; private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; // --- Bitmapová informační hlavička soukromý bajt bitmapInfoHeader [] = nový bajt [40]; private int biSize = BITMAPINFOHEADER_SIZE; private int biWidth = 0; soukromý 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; // --- Bitmapová surová data soukromá int bitmapa []; // --- File file private FileOutputStream fo; // --- Výchozí konstruktor public BMPFile () {} public void saveBitmap (String parFilename, Image parImage, int parWidth, int parHeight) {try {fo = new FileOutputStream (parFilename); save (parImage, parWidth, parHeight); fo.close (); } catch (Výjimka saveEx) {saveEx.printStackTrace (); }} / * * SaveMethod je hlavní metodou procesu. Tato metoda * zavolá metodu convertImage pro převod obrazu paměti na * bajtové pole; metoda writeBitmapFileHeader vytvoří a zapíše * záhlaví souboru bitmapy; writeBitmapInfoHeader vytvoří záhlaví * informace; a writeBitmap zapíše obrázek. * * / private void save (Image parImage, int parWidth, int parHeight) {try {convertImage (parImage, parWidth, parHeight); writeBitmapFileHeader (); writeBitmapInfoHeader (); writeBitmap (); } catch (Výjimka saveEx) {saveEx.printStackTrace (); }} / * * convertImage převádí obraz paměti do bitmapového formátu (BRG). * Také počítá některé informace pro hlavičku bitmapové informace. * * / private boolean convertImage (Image parImage, int parWidth, int parHeight) {int pad; bitmap = new int [parWidth * parHeight]; PixelGrabber pg = nový PixelGrabber (parImage, 0, 0, parWidth, parHeight, bitmapa, 0, parWidth); try {pg.grabPixels (); } catch (InterruptedException e) {e.printStackTrace (); návrat (false); } pad = (4 - ((parWidth * 3)% 4)) * parHeight; biSizeImage = ((parWidth * parHeight) * 3) + podložka; bfSize = biSizeImage + BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; biWidth = parWidth; biHeight = parHeight; návrat (true); } / * * writeBitmap převádí obraz vrácený z grabberu pixelů na * požadovaný formát. Pamatujte: řádky skenování jsou invertovány v * bitmapovém souboru! * * Každý řádek skenování musí být vyplněn rovnoměrnou hranicí 4 bajtů. * / private void writeBitmap () {int velikost; hodnota int; int j; int i; int rowCount; int rowIndex; int lastRowIndex; int pad; int padCount; byte rgb [] = nový bajt [3]; size = (biWidth * biHeight) - 1; podložka = 4 - ((biWidth * 3)% 4); if (pad == 4) // <==== Pad na opravu chyb = 0; // <==== Oprava chyby rowCount = 1; padCount = 0; rowIndex = velikost - biWidth; lastRowIndex = rowIndex; zkuste {for (j = 0; j> 8) & 0xFF); rgb [2] = (byte) ((hodnota >> 16) & 0xFF); fo.write (rgb); if (rowCount == biWidth) {padCount + = pad; pro (i = 1; i> 8) & 0x00FF); návrat (retValue); } / * * * intToDWord převede int na dvojité slovo, kde je návratová * hodnota uložena ve 4bajtovém poli. * * / private byte [] intToDWord (int parValue) {byte retValue [] = nový bajt [4]; retValue [0] = (byte) (parValue & 0x00FF); retValue [1] = (byte) ((parValue >> 8) & 0x000000FF); retValue [2] = (byte) ((parValue >> 16) & 0x000000FF); retValue [3] = (byte) ((parValue >> 24) & 0x000000FF); návrat (retValue); }} 

Závěr

To je vše. Jsem si jistý, že tato třída bude pro vás velmi užitečná, protože od verze JDK 1.1.6 Java nepodporuje ukládání obrázků v žádném z populárních formátů. JDK 1.2 nabídne podporu pro vytváření obrázků JPEG, ale nepodporuje bitmapy. Takže tato třída bude stále vyplňovat mezeru v JDK 1.2.

Pokud si s touto třídou pohráváte a hledáte způsoby, jak ji vylepšit, dejte mi vědět! Níže se objeví můj e-mail a moje bio.

Jean-Pierre Dubé je nezávislý konzultant v oblasti Java. Založil Infocom, registrovaný v roce 1988. Od té doby vyvinul Infocom několik zakázkových aplikací od výroby, správy dokumentů a rozsáhlé správy elektrického vedení. Má rozsáhlé zkušenosti s programováním v jazycích C, Visual Basic a naposledy v jazyce Java, který je nyní primárním jazykem používaným jeho společností. Jedním z posledních projektů Infocomu je API diagramu, které by mělo být brzy k dispozici jako beta verze.

Tento příběh, „Java Tip 60: Saving bitmap files in Java“, původně publikoval JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found