1/*****************************************************************************/
2// bmpinfo
3// Written by Michael Wilber, Haiku Translation Kit Team
4//
5// Version:
6//
7// bmpinfo is a command line program for displaying information about
8// BMP images.
9//
10//
11// This application and all source files used in its construction, except
12// where noted, are licensed under the MIT License, and have been written
13// and are:
14//
15// Copyright (c) 2003 Haiku Project
16//
17// Permission is hereby granted, free of charge, to any person obtaining a
18// copy of this software and associated documentation files (the "Software"),
19// to deal in the Software without restriction, including without limitation
20// the rights to use, copy, modify, merge, publish, distribute, sublicense,
21// and/or sell copies of the Software, and to permit persons to whom the
22// Software is furnished to do so, subject to the following conditions:
23//
24// The above copyright notice and this permission notice shall be included
25// in all copies or substantial portions of the Software.
26//
27// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33// DEALINGS IN THE SOFTWARE.
34/*****************************************************************************/
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <ByteOrder.h>
39#include <Catalog.h>
40#include <File.h>
41#include <TranslatorFormats.h>
42#include <StorageDefs.h>
43
44#undef B_TRANSLATION_CONTEXT
45#define B_TRANSLATION_CONTEXT "bmpinfo"
46
47#define BMP_NO_COMPRESS 0
48#define BMP_RLE8_COMPRESS 1
49#define BMP_RLE4_COMPRESS 2
50
51struct BMPFileHeader {
52	// for both MS and OS/2 BMP formats
53	uint16 magic;			// = 'BM'
54	uint32 fileSize;		// file size in bytes
55	uint32 reserved;		// equals 0
56	uint32 dataOffset;		// file offset to actual image
57};
58
59struct MSInfoHeader {
60	uint32 size;			// size of this struct (40)
61	uint32 width;			// bitmap width
62	uint32 height;			// bitmap height
63	uint16 planes;			// number of planes, always 1?
64	uint16 bitsperpixel;	// bits per pixel, (1,4,8,16 or 24)
65	uint32 compression;		// type of compression
66	uint32 imagesize;		// size of image data if compressed
67	uint32 xpixperm;		// horizontal pixels per meter
68	uint32 ypixperm;		// vertical pixels per meter
69	uint32 colorsused;		// number of actually used colors
70	uint32 colorsimportant;	// number of important colors, zero = all
71};
72
73struct OS2InfoHeader {
74	uint32 size;			// size of this struct (12)
75	uint16 width;			// bitmap width
76	uint16 height;			// bitmap height
77	uint16 planes;			// number of planes, always 1?
78	uint16 bitsperpixel;	// bits per pixel, (1,4,8,16 or 24)
79};
80
81void
82print_bmp_info(BFile &file)
83{
84	uint8 buf[40];
85	BMPFileHeader fh;
86
87	ssize_t size = 14;
88	if (file.Read(buf, size) != size) {
89		printf(B_TRANSLATE("Error: unable to read BMP file header\n"));
90		return;
91	}
92
93	// convert fileHeader to host byte order
94	memcpy(&fh.magic, buf, 2);
95	memcpy(&fh.fileSize, buf + 2, 4);
96	memcpy(&fh.reserved, buf + 6, 4);
97	memcpy(&fh.dataOffset, buf + 10, 4);
98	swap_data(B_UINT16_TYPE, &fh.magic, sizeof(uint16),
99		B_SWAP_BENDIAN_TO_HOST);
100	swap_data(B_UINT32_TYPE, (reinterpret_cast<uint8 *> (&fh)) + 2,
101		12, B_SWAP_LENDIAN_TO_HOST);
102
103	printf(B_TRANSLATE("\nFile Header:\n"));
104	printf(B_TRANSLATE("      magic: 0x%.4x (should be: 0x424d)\n"), fh.magic);
105	printf(B_TRANSLATE("  file size: 0x%.8lx (%lu)\n"), fh.fileSize,
106		fh.fileSize);
107	printf(B_TRANSLATE("   reserved: 0x%.8lx (should be: 0x%.8x)\n"),
108		fh.reserved, 0);
109	printf(B_TRANSLATE("data offset: 0x%.8lx (%lu) (should be: >= 54 for MS "
110		"format and >= 26 for OS/2 format)\n"), fh.dataOffset, fh.dataOffset);
111
112	uint32 headersize = 0;
113	if (file.Read(&headersize, 4) != 4) {
114		printf(B_TRANSLATE("Error: unable to read info header size\n"));
115		return;
116	}
117	swap_data(B_UINT32_TYPE, &headersize, 4, B_SWAP_LENDIAN_TO_HOST);
118
119	if (headersize == sizeof(MSInfoHeader)) {
120		// MS format
121		MSInfoHeader msh;
122		msh.size = headersize;
123		if (file.Read(reinterpret_cast<uint8 *> (&msh) + 4, 36) != 36) {
124			printf(B_TRANSLATE("Error: unable to read entire MS info header\n"));
125			return;
126		}
127
128		// convert msheader to host byte order
129		swap_data(B_UINT32_TYPE, reinterpret_cast<uint8 *> (&msh) + 4, 36,
130			B_SWAP_LENDIAN_TO_HOST);
131
132		printf(B_TRANSLATE("\nMS Info Header:\n"));
133		printf(B_TRANSLATE("     header size: 0x%.8lx (%lu) (should be: "
134			"40)\n"), msh.size, msh.size);
135		printf(B_TRANSLATE("           width: %lu\n"), msh.width);
136		printf(B_TRANSLATE("          height: %lu\n"), msh.height);
137		printf(B_TRANSLATE("          planes: %u (should be: 1)\n"),
138			msh.planes);
139		printf(B_TRANSLATE("  bits per pixel: %u (should be: 1,4,8,16,24 or "
140			"32)\n"), msh.bitsperpixel);
141		if (msh.compression == BMP_NO_COMPRESS)
142			printf(B_TRANSLATE("     compression: none (%lu)\n"),
143				msh.compression);
144		else if (msh.compression == BMP_RLE8_COMPRESS)
145			printf(B_TRANSLATE("     compression: RLE8 (%lu)\n"),
146				msh.compression);
147		else if (msh.compression == BMP_RLE4_COMPRESS)
148			printf(B_TRANSLATE("     compression: RLE4 (%lu)\n"),
149				msh.compression);
150		else
151			printf(B_TRANSLATE("     compression: unknown (%lu)\n"),
152				msh.compression);
153		printf(B_TRANSLATE("      image size: 0x%.8lx (%lu)\n"), msh.imagesize,
154			msh.imagesize);
155		printf(B_TRANSLATE("  x pixels/meter: %lu\n"), msh.xpixperm);
156		printf(B_TRANSLATE("  y pixels/meter: %lu\n"), msh.ypixperm);
157		printf(B_TRANSLATE("     colors used: %lu\n"), msh.colorsused);
158		printf(B_TRANSLATE("colors important: %lu\n"), msh.colorsimportant);
159
160	} else if (headersize == sizeof(OS2InfoHeader)) {
161		// OS/2 format
162
163		OS2InfoHeader os2;
164		os2.size = headersize;
165		if (file.Read(reinterpret_cast<uint8 *> (&os2) + 4, 8) != 8) {
166			printf(B_TRANSLATE("Error: unable to read entire OS/2 info "
167				"header\n"));
168			return;
169		}
170
171		// convert os2header to host byte order
172		swap_data(B_UINT32_TYPE, reinterpret_cast<uint8 *> (&os2) + 4, 8,
173			B_SWAP_LENDIAN_TO_HOST);
174
175		printf(B_TRANSLATE("\nOS/2 Info Header:\n"));
176		printf(B_TRANSLATE("   header size: 0x%.8lx (%lu) (should be: 12)\n"),
177			os2.size, os2.size);
178		printf(B_TRANSLATE("         width: %u\n"), os2.width);
179		printf(B_TRANSLATE("        height: %u\n"), os2.height);
180		printf(B_TRANSLATE("        planes: %u (should be: 1)\n"), os2.planes);
181		printf(B_TRANSLATE("bits per pixel: %u (should be: 1,4,8 or 24)\n"),
182			os2.bitsperpixel);
183
184	} else
185		printf(B_TRANSLATE("Error: info header size (%lu) does not match MS "
186			"or OS/2 info header size\n"), headersize);
187}
188
189int
190main(int argc, char **argv)
191{
192	printf("\n");
193
194	if (argc == 1) {
195		printf(B_TRANSLATE("bmpinfo - reports information about a BMP image "
196			"file\n"));
197		printf(B_TRANSLATE("\nUsage:\n"));
198		printf(B_TRANSLATE("bmpinfo filename.bmp\n"));
199	}
200	else {
201		BFile file;
202
203		for (int32 i = 1; i < argc; i++) {
204			if (file.SetTo(argv[i], B_READ_ONLY) != B_OK)
205				printf(B_TRANSLATE("\nError opening %s\n"), argv[i]);
206			else {
207				printf(B_TRANSLATE("\nBMP image information for: %s\n"),
208					argv[i]);
209				print_bmp_info(file);
210			}
211		}
212
213	}
214
215	printf("\n");
216
217	return 0;
218}
219
220