LoginSignup
1
0

C言語で作る Windows DICOM Viewer

Last updated at Posted at 2024-03-01

2024-03-01.png

Visual Studio の設定箇所

・C++で空のプロジェクトを作る

・一点だけ注意があります。
デフォルトだと、コンソールアプリを作ろうとするので、
[プロジェクト]-[プロパティ]-[構成のプロパティ]-[リンカー]-[システム]の一番上の行の[サブシステム]で、リンカエラーが出ます。Windows (/SUBSYSTEM:WINDOWS)を選ぶと、GUIのWindowsアプリケーションをビルドする準備を整えてくれるので、そこだけ注意してください。

エキシプリシット・リトル・エンディアンのファイルなら大丈夫なはずです。
プラナーインプリメンテーションは、RGBの標準配列に対応しています。
RRRRRGGGGGBBBBBとかはダメです。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#pragma warning(disable:4996)

PSTR filename;

int get_file_size(const char* file_name)
{
	FILE* fp = fopen(file_name, "rb");
	if (fp == NULL) {
		return -1LL;
	}

	if (fseek(fp, 0L, SEEK_END) == 0) {
		fpos_t pos;

		if (fgetpos(fp, &pos) == 0) {
			fclose(fp);
			return (int)pos;
		}
	}

	fclose(fp);
	return -1LL;
}


void func(HDC hdc)
{
	int k = 0;

	k = get_file_size(filename);

	unsigned char* data = (unsigned char*)malloc(k);

	FILE* fp = fopen(filename, "rb");

	fread(data, 1, k, fp);

	int s = 0;

	int rows = 0;
	int columns = 0;
	int w_center = 0;
	int w_width = 0;

	for (int i = 0; i < k; i++)
	{
		if (data[i] == 0x28 && data[i + 1] == 0x00 && data[i + 2] == 0x10 && data[i + 3] == 0x00)
		{
			rows = data[i + 8];
			rows += data[i + 9] * 256;
			continue;
		}

		if (data[i] == 0x28 && data[i + 1] == 0x00 && data[i + 2] == 0x11 && data[i + 3] == 0x00)
		{
			columns = data[i + 8];
			columns += data[i + 9] * 256;
			continue;
		}

		if (data[i] == 0x28 && data[i + 1] == 0x00 && data[i + 2] == 0x50 && data[i + 3] == 0x10)
		{
			int array[4];
			array[0] = data[i + 8] - (3 * 16);
			array[1] = data[i + 8] - (3 * 16);
			array[2] = data[i + 8] - (3 * 16);
			array[3] = data[i + 8] - (3 * 16);
			w_center = (array[0] * 1000) + (array[1] * 100) + (array[2] * 10) + (array[3]);
			continue;
		}

		if (data[i] == 0x28 && data[i + 1] == 0x00 && data[i + 2] == 0x51 && data[i + 3] == 0x10)
		{
			int array[4];
			array[0] = data[i + 8] - (3 * 16);
			array[1] = data[i + 8] - (3 * 16);
			array[2] = data[i + 8] - (3 * 16);
			array[3] = data[i + 8] - (3 * 16);
			w_width = (array[0] * 1000) + (array[1] * 100) + (array[2] * 10) + (array[3]);
			continue;
		}

		if (data[i] == 0xE0 && data[i + 1] == 0x7F && data[i + 2] == 0x10 && data[i + 3] == 0x00)
		{
			s = i;
			s += 12;
			break;
		}
	}

	fclose(fp);
 
	int height = rows;
	int width = columns;
	int window_width = w_width;
	int window_center = w_center;

	unsigned char rgb[3];

	for (int i = 0; i < width * height; i++)
	{
		int value = data[2 * i + s] + data[2 * i + 1 + s] * 256;

		double val = value;

		if (value >= window_width)
		{
			val = 255;
		}
		else if (value < 0)
		{
			val = 0;
		}
		else
		{
			val = val / window_width;
			val = val * 256;
		}

		value = (int)val;

		rgb[0] = (unsigned char)value;
		rgb[1] = (unsigned char)value;
		rgb[2] = (unsigned char)value;

		long RGB = rgb[0] * 65536 + rgb[1] * 256 + rgb[2];

        //5で割ってるのは、Rows,Columnsが3000のファイルがあったので、画面に収まらなかったために圧縮しました。通常のサイズで表示したいときは、/ 5を削除してください。
		SetPixel(hdc, (i % width) / 5, (int)(i / width) / 5, RGB);
	}
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;

	int iCount;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		func(hdc);
		EndPaint(hwnd, &ps);
		return 0;
	}

	return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR lpCmdLine, int nCmdShow) {

	filename = lpCmdLine;

	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style = CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc = WndProc;
	winc.cbClsExtra = winc.cbWndExtra = 0;
	winc.hInstance = hInstance;
	winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	winc.hCursor = LoadCursor(NULL, IDC_ARROW);
	winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName = NULL;
	winc.lpszClassName = TEXT("konecom");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
		TEXT("konecom"), TEXT("konecom"),
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL
	);


	if (hwnd == NULL) return -1;

	while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
	return msg.wParam;
}

ビルドを通したら、

xxxx.exe <読影したいdcmファイル>

で、実行してください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0