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