人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Visual C# 2005 または Visual Basic 2005 において、Graphics で加工した画像を 8Bit のビットマップとして保存する方法を教えてください。

下記は試して NG だった方法です。
1. コンストラクタ Bitmap (Int32, Int32, PixelFormat) で System.Drawing.Imaging.PixelFormat.Format8bppIndexed を指定する → Graphics を生成できない

2. 非パレットのビットマップに描画してから Bitmap.Clone(Rectangle, PixelFormat) で 8 Bit化 → "メモリ不足"の旨を告げるエラーが出てしまう。

3. SetPixel/GetPixel を使ってピクセルごとにコピー → パレットのビットマップでは SetPixel が例外を投げる。


宜しくお願いします。

●質問者: Takel
●カテゴリ:コンピュータ
✍キーワード:BIT C# ng Visual Basic エラー
○ 状態 :終了
└ 回答数 : 1/1件

▽最新の回答へ

1 ● mj99
●60ポイント

いろいろ探したのですけど、使えそうなものがありませんね。。。

Visual C#を使用すると、 .gif ファイルに新しいカラー テーブルを保存する方法

上記URLは、グレースケールのGIF(モノクロ256階調)を作成するサンプルです。

----

結局、8bitで保存するには、自分で変換プログラムを書くしかなさそうです。

上記URLを参考に、フルカラーを256色に減色するコードを作ってみました。

(手元にVB.NETしかなかったので、申し訳ありませんが、VBのコードでカンベン)

Imports system.Drawing.Imaging

Public Class Form1

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

 ' 下準備
 Dim bm As New Bitmap(300, 300) ' これが保存するサイズになる。とりあえず適当
 Dim gs As Graphics = Graphics.FromImage(bm)

 ' ここからGraphicsに描画するものとします。この例は24bitのpngをGraphicsに載せる
 Dim im As Image = Image.FromFile("c:\users\test_24bit.png")
 gs.DrawImage(im, New Point(0, 0))
 gs.Dispose()
 ' ここでGraphicsに描画が終わったものとします

 ' 8bppIndexedで保存する
 Save8bppIndexedBMP(bm, "c:\users\test_8bit.bmp")

 MsgBox("完了", MsgBoxStyle.Information)

 End Sub

 Public Sub Save8bppIndexedBMP(ByVal image As Image, ByVal filename As String)

 ' 目的のイメージと同じ大きさの8bitビットマップを作る
 Dim Width As Integer = image.Width
 Dim Height As Integer = image.Height
 Dim bitmap As Bitmap = New Bitmap(Width, Height, PixelFormat.Format8bppIndexed)

 ' 減色パレットを作る
 Dim pal As ColorPalette = bitmap.Palette
 Dim wr() As Byte = {0, 36, 72, 108, 144, 180, 216, 255} ' 赤8階調
 Dim wg() As Byte = {0, 36, 72, 108, 144, 180, 216, 255} ' 緑8階調
 Dim wb() As Byte = {0, 84, 168, 255} ' 青4階調(悲惨)
 Dim x As Integer = 0
 For i As Integer = 0 To 7
 For j As Integer = 0 To 7
 For k As Integer = 0 To 3
 pal.Entries(x) = Color.FromArgb(0, wr(i), wg(j), wb(k))
 x = x + 1
 Next
 Next
 Next
 bitmap.Palette = pal

 ' 保存したい対象を24bitに展開
 Dim BmpCopy As Bitmap = New Bitmap(Width, Height, PixelFormat.Format24bppRgb)
 Dim g As Graphics = Graphics.FromImage(BmpCopy)
 g.PageUnit = GraphicsUnit.Pixel
 g.DrawImage(image, 0, 0, Width, Height)
 g.Dispose()

 Dim rect As Rectangle = New Rectangle(0, 0, Width, Height)

 ' 24bitの画像を総スキャン(RGB値が3バイトで1組のバイト列になる)
 Dim bitmapData24 As BitmapData = BmpCopy.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb)
 Dim bufsize As Integer = bitmapData24.Width * bitmapData24.Stride
 Dim buf(bufsize - 1) As Byte
 System.Runtime.InteropServices.Marshal.Copy(bitmapData24.Scan0, buf, 0, bufsize)

 ' 8bitピクセルデータ配列を作成する(ここにパレットインデックスを書き込む)
 Dim bitmapData8 As BitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed)
 Dim stride As UInteger = Math.Abs(bitmapData8.Stride)
 Dim pixels8 As IntPtr = bitmapData8.Scan0

 ' 24bitから8bitへの減色を行う
 Dim nOffset8 As Integer = 0
 For nOffset24 As Integer = 0 To bufsize - 1 Step 3
 Dim wrx As Integer = Fix((buf(nOffset24 + 0)) / 32) ' 赤8階調に減色
 Dim wgx As Integer = Fix((buf(nOffset24 + 1)) / 32) ' 緑8階調に減色
 Dim wbx As Integer = Fix((buf(nOffset24 + 2)) / 64) ' 青4階調に減色

 ' パレットインデックスを算出
 Dim src(0) As Byte
 src(0) = CByte(wrx * 32 + wgx * 4 + wbx)

 ' 8bitピクセルアドレスへパレットインデックスを書き込む
 System.Runtime.InteropServices.Marshal.Copy(src, 0, pixels8.ToInt32 + nOffset8, 1)
 nOffset8 = nOffset8 + 1
 Next
 BmpCopy.UnlockBits(bitmapData24)
 bitmap.UnlockBits(bitmapData8)

 bitmap.Save(filename, ImageFormat.Bmp)
 BmpCopy.Dispose()
 bitmap.Dispose()

 End Sub

End Class
◎質問者からの返答

ありがとうございます。

時間がなくてまだ試せていませんが、やっぱり自力でパレット化しなくては駄目そうなんですね。

それだけわかっただけでも十分な情報でした。

もともと使う必要があるのが VB2005 用なので VB のコードで大丈夫です。

ありがとうございました。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ