⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 savebmp.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
字号:
#include "priv_precompiled.h"

/*
Copyright 2001 Bruce Dawson, Cygnus Software
For more information, visit http://www.cygnus-software.com/papers/
or e-mail: comments@cygnus-software.com

This code may be redistributed as long as this notice is kept intact.
*/

#include "csbitmap.h"
#include "bmpdefs.h"

// This file should be upgraded to use iostreams instead of standard io. Later.

// Returns true if the entire write succeeds, false otherwise.
static bool Write(FILE* pFile, void* ptr, size_t Amount)
{
	return fwrite(ptr, 1, Amount, pFile) == Amount;
}

static bool WriteBMPLine(FILE* pFile, CSBitmap *DestBitmap, int y)
{
	// A buffer to use to write the padding bytes from.
	char	PaddingBuffer[3] = {0};
	// We have to flip the y-coordinate because our bitmap class
	// puts line zero at the top of the screen, and the BMP format
	// on disk does the opposite.
	uint8_t *LinePtr = DestBitmap->GetLinePtr(DestBitmap->GetHeight() - 1 - y);
	unsigned int BytesPerLine = ((DestBitmap->GetWidth() * DestBitmap->GetChannels() + 3) & ~3);
	unsigned int UsedBytes = DestBitmap->GetWidth() * DestBitmap->GetChannels();
	unsigned int Padding = BytesPerLine - UsedBytes;
	// Read the precise number of bytes that the line requires into the bitmap.
	// Don't read the padding bytes, because the in memory alignment requirements
	// may vary - we don't want our reading code to depend on our bitmap class
	// implementation.
	if (!Write(pFile, LinePtr, UsedBytes))
		return false;
	// Write out any padding bytes.
	if (!Write(pFile, PaddingBuffer, Padding))
		return false;
	return true;
}

static bool InternalSaveBMPFile(FILE* pFile, CSBitmap *SourceBitmap)
{
	BITMAPFILEHEADER fileheader = {0};
	BITMAPINFOHEADER infoheader = {0};

	memcpy(&fileheader.bfType, "BM", 2);
	fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader);
	if (SourceBitmap->GetChannels() == 1)
		fileheader.bfOffBits += 256 * sizeof(RGBQUAD);

	infoheader.biSize = sizeof(infoheader);
	infoheader.biPlanes = 1;
	infoheader.biBitCount = SourceBitmap->GetChannels() * 8;
	infoheader.biWidth = SourceBitmap->GetWidth();
	infoheader.biHeight = SourceBitmap->GetHeight();
	infoheader.biCompression = BI_RGB;	// I'm not compressing it!
	// I don't need to set biSizeImage or biClrUsed.

	// Read the file header.
	if (!Write(pFile, &fileheader, sizeof(fileheader)))
		return false;

	// Read the info header.
	if (!Write(pFile, &infoheader, sizeof(infoheader)))
		return false;

	// Read the color map, if any.
	if (infoheader.biBitCount == 8)
	{
		RGBQUAD		Palette[256];
		if (!SourceBitmap->GetPalette(0, 256, Palette))
			return false;
		if (!Write(pFile, Palette, sizeof(Palette)))
			return false;
	}

	for (int y = 0; y < infoheader.biHeight; y++)
		if (!WriteBMPLine(pFile, SourceBitmap, y))
			return false;

	return true;
}

bool SaveBMPFile(const char* FileName, CSBitmap* SourceBitmap)
{
	bool	Result = false;
	assert(FileName);
	assert(SourceBitmap);
	FILE* pFile = fopen(FileName, "wb");

	// This is the cleanest way of making sure that the file always gets
	// closed.
	if (pFile)
	{
		Result = InternalSaveBMPFile(pFile, SourceBitmap);
		fclose(pFile);
	}
	return Result;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -