第一部「プロジェクト作成&デバッグ方法の説明」の続き、第2部「HSV色変換DLLの作成」を説明していきます。
C#プロジェクトのプログラム実装、C言語のDLLプロジェクトのプログラム実装の順で説明していきます。
C#プロジェクトのプログラム実装
第一回で作成した「hsv_test」プロジェクトにプログラム実装をします。
表示用画像の準備
表示用画像はBMP画像をデバッグフォルダに準備します。
ここでは赤枠のBMPファイルをコピーしています。
実際に用意した画像はブログのアイコンを少し変更した300x300のBMP画像です。
フォームへコントロールの配置
フォームへ「pictureBox」を2つ、「trackBar」を1つ、「label」は元々のlabelを移動して配置します。
プロパティーのNameは張り付けたままの状態でOKです。
各種プロパティーの設定です。
「pictureBox1」、「pictureBox2」のプロパティー設定。
・SizeMode : Zoom
「label1」のプロパティー設定。
・AutoSize : false
・BorderStyle : FixedSingle
・TextAlign : MiddleCenter
プロパティーの設定後、タイマーの貼り付けを行い、「trackBar1」と「timer1」のコントロールをダブルクリックし、イベントを作成して下さい。
タイマーを配置後の画面はこの様になります。
Form1.csへプログラムの実装
先ずはプログラム全体です。(100行目以降は行数が表示されません)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace hsv_test
{
public partial class Form1 : Form
{
private const string BMP_FILE_NAME = "test_image.bmp"; //画像ファイル名
private bool image_flash_flag; //画像更新フラグ
private byte[] img_bs; //ベース画像バッファ
private System.Drawing.Bitmap bmp_bf_bs; //ベース画像BMP
private System.Drawing.Bitmap bmp_bf_change; //カラー変更画像BMP
public Form1()
{
InitializeComponent();
}
//フォームロード
private void Form1_Load(object sender, EventArgs e)
{
string fname;
fname = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + BMP_FILE_NAME;
image_flash_flag = true;
//画像読み込み
using (FileStream fs = new FileStream(fname, FileMode.Open, FileAccess.Read))
{
img_bs = new byte[fs.Length];
fs.Read(img_bs, 0, img_bs.Length);
}
//jpeg画像またはpng画像を読み込む場合はコメントアウトの4行を使用する
//Bitmap tmp = new Bitmap(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "jpeg or png FileName");
//MemoryStream tms = new MemoryStream();
//tmp.Save(tms,System.Drawing.Imaging.ImageFormat.Bmp);
//img_bs = tms.ToArray();
//pictureBox1に画像をセット
MemoryStream ms = new MemoryStream(img_bs);
bmp_bf_bs = new Bitmap(ms);
ms.Close();
ms = null;
pictureBox1.Image = bmp_bf_bs;
label1.Text = "0";
trackBar1.Maximum = 359;
timer1.Interval = 1000 / 60;
timer1.Start();
}
//タイマーイベント
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
if (image_flash_flag)
{
image_flash_flag = false;
//HSV色変換
Dll_Import.HSV_ChangeColor_Wk wk;
wk.angle = (UInt16)trackBar1.Value;
wk.src_bmp_ptr = img_bs;
wk.dst_bmp_ptr = new byte[0];
Dll_Import.HSV_ChangeColor(ref wk);
//HSV色変換画像の更新
if (wk.dst_bmp_ptr.Length != 0)
{
//古い画像の破棄
if (bmp_bf_change != null)
{
bmp_bf_change.Dispose();
bmp_bf_change = null;
pictureBox2.Image = null;
}
//新しい画像のセット
MemoryStream ms = new MemoryStream(wk.dst_bmp_ptr);
bmp_bf_change = new Bitmap(ms);
ms.Close();
ms = null;
pictureBox2.Image = bmp_bf_change;
}
}
timer1.Enabled = true;
}
//トラックバースクロールイベント
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (img_bs != null)
{
label1.Text = ((TrackBar)sender).Value.ToString();
image_flash_flag = true;
}
}
}
}
フォームロードではBMP画像の読み込み等を行っています。
使用する画像をjpegやpngにしたい場合は44行から47行のコメントアウトを外してプログラムを有効にして下さい。
タイマーイベントでは画面の更新フラグのセット時に、画像のHSV色変換を行い表示をしています。
トラックバースクロールイベントではHSV色変換用の角度の表示と画面の更新フラグのセットを行っています。
ここでプログラムを実行して、このような画面が表示されればOKです。
DLLプロジェクトのプログラム実装
前回作成した「msf_util」プロジェクトにプログラム実装をします。
「malloc_ex」、「m_util」、「HSV_ChangeColor」の順で作成します。
malloc_exの作成
malloc_exはメモリーリークを防ぐためのクラスとなります。
mallocでカウントアップ、freeでカウントダウンをする単純なプログラムです。
全ての処理の終了時にこのカウントが0ならば、メモリーリークは発生しないという事になります。
「malloc_ex.h」の記述です。
#include <Windows.h>
#pragma once
typedef struct {
BOOL use; // 使用フラグ
void* adr; // 確保アドレス
INT16 count; // カウンター
} M_Dic_St;
ref class malloc_ex
{
public:
static const int M_DIC_MAX = 30; // バッファ確保数
INT16 malloc_count; // メモリー確保数
M_Dic_St* m_dic_buff; // 使用状況
//----- プロトタイプ -----
void* ex_malloc(LONG sz); // メモリー確保
void ex_free(void* ptr); // メモリー解放
INT16 get_count();
malloc_ex(); // コンストラクター
~malloc_ex(); // デストラクター
};
続いて、「malloc_ex.cpp」の記述です。
#include "pch.h"
#include <malloc.h>
#include "malloc_ex.h"
//****************************************************************************************************************
//*
//* void *malloc_ex::ex_malloc(LONG sz)
//*
//* メモリー確保
//*
//* in. LONG sz 確保サイズ
//*
//* out. void * メモリーアドレス
//*
//****************************************************************************************************************
void* malloc_ex::ex_malloc(LONG sz)
{
void* ptr;
ptr = malloc(sz);
if (ptr != NULL) {
malloc_count++;
int i;
M_Dic_St* tmp = m_dic_buff;
for (i = 0; i < M_DIC_MAX; i++) {
if (tmp->use == FALSE) {
tmp->use = TRUE;
tmp->adr = ptr;
tmp->count = malloc_count;
break;
}
tmp++;
}
}
return ptr;
}
//****************************************************************************************************************
//*
//* void malloc_ex::ex_free(void *ptr)
//*
//* メモリー解放
//*
//* in. void *ptr mallocポインタ
//*
//* out. なし
//*
//****************************************************************************************************************
void malloc_ex::ex_free(void* ptr)
{
int i;
M_Dic_St* tmp = m_dic_buff;
for (i = 0; i < M_DIC_MAX; i++) {
if (tmp->use == TRUE && tmp->adr == ptr) {
tmp->use = FALSE;
tmp->adr = NULL;
tmp->count = 0;
break;
}
tmp++;
}
free(ptr);
malloc_count--;
}
//****************************************************************************************************************
//*
//* INT16 malloc_ex::get_count()
//*
//* メモリー確保数を返す
//*
//* in. なし
//*
//* out. INT16 メモリー確保数
//*
//****************************************************************************************************************
INT16 malloc_ex::get_count()
{
return malloc_count;
}
//----- コンストラクター -----
malloc_ex::malloc_ex()
{
malloc_count = 0;
m_dic_buff = (M_Dic_St*)malloc(sizeof(M_Dic_St) * M_DIC_MAX);
if (m_dic_buff != NULL) {
memset(m_dic_buff, 0, _msize(m_dic_buff));
}
}
//----- デストラクター -----
malloc_ex::~malloc_ex()
{
free(m_dic_buff);
}
malloc_ex::ex_malloc(LONG sz)がメモリーの確保。
malloc_ex::ex_free(void* ptr)がメモリーの解放。
malloc_ex::get_count()がメモリーの確保回数。
m_utilの作成
m_utilはHSV色変換用のユーティリティープログラムです。
「m_util.h」の記述です。
#pragma once
#include <windows.h>
#include "malloc_ex.h"
//------------------------------------------------------------------------------------------------------------------------------
//構造体定義
//------------------------------------------------------------------------------------------------------------------------------
//HSV構造体
typedef struct
{
UINT16 h; // 色相 0 - 360度
double s; // 彩度 0.0 - 1.0
UINT16 v; // 明度 0-255
} Hsv;
//----- Color MAP 定義用構造体 -----
typedef struct {
//----- 入力用メンバー -----
RGBTRIPLE* data_ptr; // RGB DATA pointer
INT32 x_size; // X Size
INT32 y_size; // Y Size
INT16 h_range; // 許容色相レンジ± 0-179 基本は0-60までの範囲
//----- 出力用メンバー(選択可能カラーのインデックスに1が入る) -----
BYTE* map_r; // R Color Map 256Byteを確保したポインタを入れる
BYTE* map_g; // G Color Map 256Byteを確保したポインタを入れる
BYTE* map_b; // B Color Map 256Byteを確保したポインタを入れる
}Color_Map_Work;
#define COLOR_MAP_SIZE 256 // カラーマップサイズ(1チャンネル分)
//------------------------------------------------------------------------------------------------------------------------------
//prototype
//------------------------------------------------------------------------------------------------------------------------------
void rgb_2_hsv(RGBTRIPLE* rgb_ptr, Hsv* hsv_ptr); // RGB → HSV 変換
void hsv_2_rgb(Hsv* hsv_ptr, RGBTRIPLE* rgb_ptr); // HSV → RGB 変換
UINT8* reverse_image(UINT8* ptr, malloc_ex^ malloc_ptr, BOOL free_flag = TRUE); // BMPの反転
UINT8* mk_bmp_buffer(INT32 sx, INT32 sy, INT32 color, malloc_ex^ malloc_ptr); // BMPバッファ生成
続いて「m_util.cpp」の記述です。
#include "pch.h"
#include <math.h>
#include "m_util.h"
//*************************************************************************************
//
// RGB → HSV変換
//
// rgb_2_hsv()
// in: RGBTRIPLE *rgb_ptr BMP DATA Pointer(B,G,Rの順)
// Hsv *hsv_ptr HSV DATA Pointer(HSVデータが入る)
//
// out: なし
//
//*************************************************************************************
void rgb_2_hsv(RGBTRIPLE* rgb_ptr, Hsv* hsv_ptr)
{
INT16 c_max, c_min, c_code;
double ans_d, ans, cal_r, cal_g, cal_b;
hsv_ptr->h = 0;
hsv_ptr->s = 0;
hsv_ptr->v = 0;
c_code = 0;
c_max = rgb_ptr->rgbtRed;
c_min = c_max;
if (c_max < rgb_ptr->rgbtGreen) {
c_max = rgb_ptr->rgbtGreen;
c_code = 1;
}
if (c_max < rgb_ptr->rgbtBlue) {
c_max = rgb_ptr->rgbtBlue;
c_code = 2;
}
if (c_min > rgb_ptr->rgbtGreen) {
c_min = rgb_ptr->rgbtGreen;
}
if (c_min > rgb_ptr->rgbtBlue) {
c_min = rgb_ptr->rgbtBlue;
}
if (c_max > 0) {
hsv_ptr->v = c_max;
ans_d = (double)(c_max - c_min);
hsv_ptr->s = (double)ans_d / (double)c_max;
cal_r = (double)(c_max - rgb_ptr->rgbtRed) / ans_d;
cal_g = (double)(c_max - rgb_ptr->rgbtGreen) / ans_d;
cal_b = (double)(c_max - rgb_ptr->rgbtBlue) / ans_d;
switch (c_code)
{
case 0:
ans = 6 + cal_b - cal_g;
break;
case 1:
ans = 6 + 2 + cal_r - cal_b;
break;
case 2:
ans = 6 + 4 + cal_g - cal_r;
break;
}
hsv_ptr->h = (UINT16)fmod(((ans * 60.0) + 0.5), 360);
}
}
//*************************************************************************************
//
// HSV → RGB変換
//
// hsv_2_rgb()
// in: Hsv *hsv_ptr HSV DATA Pointer
// RGBTRIPLE *rgb_ptr BMP DATA Pointer(RGBデータが入る B,G,Rの順)
//
// out: なし
//
//*************************************************************************************
void hsv_2_rgb(Hsv* hsv_ptr, RGBTRIPLE* rgb_ptr)
{
INT16 tmp_i, tmp_m, tmp_n, tmp_k;
double tmp_f;
if (hsv_ptr->s == 0.0) {
rgb_ptr->rgbtRed = rgb_ptr->rgbtGreen = rgb_ptr->rgbtBlue = (UINT8)hsv_ptr->v;
}
else {
tmp_i = (INT16)floor((double)hsv_ptr->h / 60.0);
tmp_f = (double)hsv_ptr->h / 60.0 - tmp_i;
tmp_m = (INT16)((double)hsv_ptr->v * (1.0 - hsv_ptr->s / 1.0));
tmp_n = (INT16)((double)hsv_ptr->v * (1.0 - (hsv_ptr->s / 1.0) * (double)tmp_f) + 0.5);
tmp_k = (INT16)((double)hsv_ptr->v * (1.0 - (hsv_ptr->s / 1.0) * (1.0 - (double)tmp_f)) + 0.5);
switch (tmp_i) {
case 0:
rgb_ptr->rgbtRed = (BYTE)hsv_ptr->v;
rgb_ptr->rgbtGreen = (BYTE)tmp_k;
rgb_ptr->rgbtBlue = (BYTE)tmp_m;
break;
case 1:
rgb_ptr->rgbtRed = (BYTE)tmp_n;
rgb_ptr->rgbtGreen = (BYTE)hsv_ptr->v;
rgb_ptr->rgbtBlue = (BYTE)tmp_m;
break;
case 2:
rgb_ptr->rgbtRed = (BYTE)tmp_m;
rgb_ptr->rgbtGreen = (BYTE)hsv_ptr->v;
rgb_ptr->rgbtBlue = (BYTE)tmp_k;
break;
case 3:
rgb_ptr->rgbtRed = (BYTE)tmp_m;
rgb_ptr->rgbtGreen = (BYTE)tmp_n;
rgb_ptr->rgbtBlue = (BYTE)hsv_ptr->v;
break;
case 4:
rgb_ptr->rgbtRed = (BYTE)tmp_k;
rgb_ptr->rgbtGreen = (BYTE)tmp_m;
rgb_ptr->rgbtBlue = (BYTE)hsv_ptr->v;
break;
case 5:
rgb_ptr->rgbtRed = (BYTE)hsv_ptr->v;
rgb_ptr->rgbtGreen = (BYTE)tmp_m;
rgb_ptr->rgbtBlue = (BYTE)tmp_n;
break;
}
}
}
//****************************************************************************************************************
//*
//* UINT8 *reverse_image(UINT8 *ptr, malloc_ex ^malloc_ptr, BOOL free_flag)
//*
//* BMP画像の上下反転(free_flag=FALSEの場合、元のバッファは開放)
//*
//* in. UINT8 *ptr BMPデータポインタ
//* malloc_ex ^malloc_ptr メモリ確保クラスポインタ
//* BOOL free_flag 元バッファ解放フラグ デフォルト=TRUE
//*
//* out. UINT8 * 上下反転BMPバッファポインタ
//*
//****************************************************************************************************************
UINT8* reverse_image(UINT8* ptr, malloc_ex^ malloc_ptr, BOOL free_flag)
{
BITMAPFILEHEADER* bmp_file_header;
BITMAPINFOHEADER* bmp_info_header;
DWORD x_line_size;
WORD rgb_size;
UINT8* new_bmp_ptr, * set_ptr, * data_ptr;
INT32 i;
bmp_file_header = (BITMAPFILEHEADER*)ptr;
bmp_info_header = (BITMAPINFOHEADER*)(ptr + sizeof(BITMAPFILEHEADER));
rgb_size = bmp_info_header->biBitCount / 8;
x_line_size = bmp_info_header->biWidth * rgb_size;
if ((x_line_size & 3) != 0) {
x_line_size = ((x_line_size + 4) & -4);
}
new_bmp_ptr = mk_bmp_buffer(bmp_info_header->biWidth, bmp_info_header->biHeight, rgb_size, malloc_ptr);
set_ptr = new_bmp_ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
data_ptr = ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if (rgb_size == 1) {
data_ptr += sizeof(RGBQUAD) * 256; // パレット分進める
set_ptr += sizeof(RGBQUAD) * 256; // パレット分進める
}
for (i = bmp_info_header->biHeight - 1; i >= 0; i--) {
UINT8* tmp_ptr;
tmp_ptr = data_ptr + x_line_size * i;
memcpy_s(set_ptr, x_line_size, tmp_ptr, x_line_size);
set_ptr += x_line_size;
}
if (free_flag == TRUE) {
malloc_ptr->ex_free(ptr);
}
return new_bmp_ptr;
}
//****************************************************************************************************************
//*
//* UINT8 *mk_bmp_buffer(INT32 sx,INT32 sy,INT32 color, malloc_ex ^malloc_ptr)
//*
//* BMPバッファの作成
//*
//* in. INT32 sx x size
//* INT32 sy y size
//* INT32 color color size (8BitColor = 1 , 24Bitcolor = 3 , 32Bitcolor = 4)
//* malloc_ex ^malloc_ptr メモリ確保クラスポインタ
//*
//* out. UINT8 * BMPバッファポインタ
//*
//****************************************************************************************************************
UINT8* mk_bmp_buffer(INT32 sx, INT32 sy, INT32 color, malloc_ex^ malloc_ptr)
{
UINT8* bmp_buff, * set_ptr;
DWORD bmp_fheader_size, bmp_iheader_size, bmp_total_size, image_offset;
LONG x_line_size;
UINT32 i;
bmp_fheader_size = sizeof(BITMAPFILEHEADER);
bmp_iheader_size = sizeof(BITMAPINFOHEADER);
image_offset = bmp_fheader_size + bmp_iheader_size;
//----- x sizeを4の倍数にする -----
x_line_size = sx * color;
if ((x_line_size & 3) != 0) {
x_line_size = ((x_line_size + 4) & -4);
}
bmp_total_size = bmp_fheader_size + bmp_iheader_size + x_line_size * sy;
if (color == 1) {
bmp_total_size += sizeof(RGBQUAD) * 256;
image_offset += sizeof(RGBQUAD) * 256;
}
bmp_buff = (UINT8*)malloc_ptr->ex_malloc(bmp_total_size);
memset(bmp_buff, 0, bmp_total_size);
set_ptr = bmp_buff;
*set_ptr++ = 'B';
*set_ptr++ = 'M';
*set_ptr++ = (unsigned char)(bmp_total_size); // file size
*set_ptr++ = (unsigned char)(bmp_total_size >> 8);
*set_ptr++ = (unsigned char)(bmp_total_size >> 16);
*set_ptr++ = (unsigned char)(bmp_total_size >> 24);
*set_ptr++ = 0; // 予約 1,2
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = (unsigned char)(image_offset); // file size
*set_ptr++ = (unsigned char)(image_offset >> 8);
*set_ptr++ = (unsigned char)(image_offset >> 16);
*set_ptr++ = (unsigned char)(image_offset >> 24);
//----- BMP INFO HEADER セット -----
*set_ptr++ = (unsigned char)(bmp_iheader_size); // info header size
*set_ptr++ = (unsigned char)(bmp_iheader_size >> 8);
*set_ptr++ = (unsigned char)(bmp_iheader_size >> 16);
*set_ptr++ = (unsigned char)(bmp_iheader_size >> 24);
*set_ptr++ = (unsigned char)(sx); // x size
*set_ptr++ = (unsigned char)(sx >> 8);
*set_ptr++ = (unsigned char)(sx >> 16);
*set_ptr++ = (unsigned char)(sx >> 24);
*set_ptr++ = (unsigned char)(sy); // y size
*set_ptr++ = (unsigned char)(sy >> 8);
*set_ptr++ = (unsigned char)(sy >> 16);
*set_ptr++ = (unsigned char)(sy >> 24);
*set_ptr++ = (unsigned char)(1); // プレーン数 1
*set_ptr++ = (unsigned char)(0);
*set_ptr++ = (unsigned char)(color * 8); // 1画素のビット数
*set_ptr++ = (unsigned char)(0);
*set_ptr++ = 0; // 圧縮タイプ
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = (unsigned char)(x_line_size * sy); // 画像データサイズ
*set_ptr++ = (unsigned char)((x_line_size * sy) >> 8);
*set_ptr++ = (unsigned char)((x_line_size * sy) >> 16);
*set_ptr++ = (unsigned char)((x_line_size * sy) >> 24);
*set_ptr++ = 0; // 水平解像度
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0; // 垂直解像度
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0;
if (color == 1) {
*set_ptr++ = 0; // カラーパレット index数
*set_ptr++ = 1;
*set_ptr++ = 0;
*set_ptr++ = 0;
}
else {
*set_ptr++ = 0; // カラーパレット index数
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0;
}
*set_ptr++ = 0; // 重要 index数
*set_ptr++ = 0;
*set_ptr++ = 0;
*set_ptr++ = 0;
if (color == 1) {
for (i = 0; i < 256; i++) {
*set_ptr++ = i; // カラーパレット
*set_ptr++ = i;
*set_ptr++ = i;
*set_ptr++ = i;
}
}
return bmp_buff;
}
void rgb_2_hsv(RGBTRIPLE* rgb_ptr, Hsv* hsv_ptr)がRGB → HSV変換。
void hsv_2_rgb(Hsv* hsv_ptr, RGBTRIPLE* rgb_ptr)がHSV → RGB変換。
UINT8* reverse_image(UINT8* ptr, malloc_ex^ malloc_ptr, BOOL free_flag)がBMP画像の上下反転。
UINT8* mk_bmp_buffer(INT32 sx, INT32 sy, INT32 color, malloc_ex^ malloc_ptr)がBMPデータバッファ作成。
HSV_ChangeColorの作成
HSV_ChangeColorは実際にC#から呼び出される関数になります。
「HSV_ChangeColor.h」の記述です。
#pragma once
#include <windows.h>
#include "m_util.h"
//----- HSV_ChangeColor()引き数の構造体 -----
typedef struct {
WORD angle; //HSV 変換角度
void* src_bmp_ptr; //source BMP ポインター
void* byte_buff; //HSV変換済みデータ ポインター
} HSV_VhangeColor_Wk;
INT16 HSV_ChangeColor(HSV_VhangeColor_Wk* in_ptr);
続いて「HSV_ChangeColor.cpp」の記述です。
#include "pch.h"
#include <windows.h>
#include <OAIdl.h>
#include "HSV_ChangeColor.h"
#include "malloc_ex.h"
//************************************************
//*
//* INT16 HSV_ChangeColor(HSV_ChangeColor_Wk *in_ptr)
//*
//* HSV色変換を行う
//*
//* in. HSV_ChangeColor_Wk *in_ptr 画像変換ワークポインター
//*
//* out. INT16 0=成功 : 1=失敗
//*
//************************************************
INT16 HSV_ChangeColor(HSV_VhangeColor_Wk* in_ptr)
{
malloc_ex^ malloc_ex_ptr;
SAFEARRAY* src_buff_ptr, * byte_buff_ptr;
DWORD bmp_fheader_size, bmp_iheader_size, bmp_total_size, image_offset;
UINT8* src_bmp_ptr, * byte_bmp_ptr;
SAFEARRAYBOUND rgsabound[1];
HRESULT hr;
unsigned char* buff_ptr = NULL;
DWORD bmp_sx, bmp_sy;
BITMAPINFOHEADER* info_header_ptr;
DWORD x_line_size1;
LONG i, j;
RGBTRIPLE* data_ptr1, * data_ptr2;
Hsv hsv_dt;
malloc_ex_ptr = gcnew malloc_ex;
src_buff_ptr = (SAFEARRAY*)in_ptr->src_bmp_ptr;
byte_buff_ptr = (SAFEARRAY*)in_ptr->byte_buff;
bmp_fheader_size = sizeof(BITMAPFILEHEADER);
bmp_iheader_size = sizeof(BITMAPINFOHEADER);
image_offset = bmp_fheader_size + bmp_iheader_size;
//----- 加工用BMPをコピー -----
src_bmp_ptr = reverse_image((UINT8*)src_buff_ptr->pvData, malloc_ex_ptr, FALSE);
//----- BMPデータ生成 -----
info_header_ptr = (BITMAPINFOHEADER*)(src_bmp_ptr + bmp_fheader_size);
bmp_sx = info_header_ptr->biWidth;
bmp_sy = info_header_ptr->biHeight;
//----- x sizeを4の倍数にする -----
x_line_size1 = bmp_sx * sizeof(RGBTRIPLE);
if ((bmp_sx & 3) != 0) {
x_line_size1 = ((x_line_size1 + 4) & -4); // 24Bit Color
}
bmp_total_size = bmp_fheader_size + bmp_iheader_size + x_line_size1 * bmp_sy;
//----- カラー変更バッファの作成 -----
byte_bmp_ptr = (UINT8*)malloc_ex_ptr->ex_malloc((LONG)_msize(src_bmp_ptr));
memcpy_s(byte_bmp_ptr, _msize(src_bmp_ptr), src_bmp_ptr, _msize(src_bmp_ptr));
//----- カラー変更 -----
//B,G,R 24Bit Color
data_ptr1 = (RGBTRIPLE*)(src_bmp_ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
data_ptr2 = (RGBTRIPLE*)(byte_bmp_ptr + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
RGBTRIPLE* ptr1;
RGBTRIPLE* ptr2;
for (i = 0; i < info_header_ptr->biHeight; i++) {
ptr1 = (RGBTRIPLE*)((UINT8*)(data_ptr1)+(x_line_size1 * i));
ptr2 = (RGBTRIPLE*)((UINT8*)(data_ptr2)+(x_line_size1 * i));
for (j = 0; j < info_header_ptr->biWidth; j++) {
rgb_2_hsv(ptr1, &hsv_dt);
hsv_dt.h = (hsv_dt.h + in_ptr->angle) % 360;
hsv_2_rgb(&hsv_dt, ptr2);
ptr1++;
ptr2++;
}
}
//----- 編集バッファをSAFEARRAYにコピー -----
byte_bmp_ptr = reverse_image(byte_bmp_ptr, malloc_ex_ptr);
//----- SAFEARRAYのサイズ変更 -----
rgsabound[0].cElements = bmp_total_size; // 配列サイズ
rgsabound[0].lLbound = 0; // 先頭 index
hr = SafeArrayRedim(byte_buff_ptr, rgsabound);
//----- 配列の先頭ポインタを取得(ロックされる) -----
hr = SafeArrayAccessData(byte_buff_ptr, (void**)&buff_ptr);
memcpy_s(buff_ptr, bmp_total_size, byte_bmp_ptr, bmp_total_size);
//----- 配列のアンロック -----
SafeArrayUnlock(byte_buff_ptr);
malloc_ex_ptr->ex_free(byte_bmp_ptr);
malloc_ex_ptr->ex_free(src_bmp_ptr);
int cnt = malloc_ex_ptr->get_count();
delete malloc_ex_ptr;
return 0;
}
ポイントとしてはC#から渡された配列(マネージド配列)をC言語のDLLで処理をする場合は「SAFEARRAY」ポインターで処理を行う事です。
また、加工したデータを格納する配列はサイズが0バイトの配列をC#側から渡すようにします。
C#側で作成した配列のリサイズも可能だと思いますが、メモリーリークが絶対に起きないという確証が持てないので、0バイト配列で処理をするのが安全だと考えます。
実行してみましょう。
角度を100にした状態で、左側がHSV色変換後の画像となります。
角度を200にした状態です。
プログラムの難易度的にはそれほど高くありませんので、試してみて下さい。
「SAFEARRAY」を使用する事で配列の操作なら何でもできます。
C#で大きな配列でデータ加工を行うのは速度的に遅すぎますので、C言語のDLLで処理をするのもありだと思います。
それではまた。
コメント