[[20160510141006]] 『ドット絵変換を楽にしたい。』(ひろりん) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『ドット絵変換を楽にしたい。』(ひろりん)

お世話になります。
手芸の好きな方から写真をドット絵に変換してビーズの配列を作りたいとの相談を受け
渡されたのが下記のコードです。
会社では、マクロの記録で帳票出力の改善する程度なので正直分りません。

彼女が言うにはフォルダ内の写真をドット絵にしたいそうなので Sheet1のB3に拡張子も
含めた写真のパスを入れ、Sheet2にドット絵が出る様にしたいと言っていました。
何をどういじくって良いかわからず、丸投げで恐縮ですが、宜しくお願い致します。

Option Explicit
'画像ファイルをシート上に展開するプログラム
Sub bitmap()

    Dim filename As String 'ファイル名
        filename = ThisWorkbook.Path + "\00002.bmp" '読み込むファイル
    Dim ff As Long 'フリーファイル
        ff = FreeFile 'フリーファイル変数
    Dim databuf() As Byte 'バイト配列

    Open filename For Binary As #ff 'バイナリモードでファイルを開く
        ReDim databuf(LOF(ff)) 'バイト配列のサイズをセット
        Get #ff, 1, databuf 'バイト配列にデータを格納
    Close #ff

    '=====================================================================================
    Dim image_power As Long '画像の倍率
    '=====================================================================================
        image_power = 2    '倍率を1/image_powerで指定
    '=====================================================================================
    Dim bmp_width As Long '画像の横サイズ
        bmp_width = HexToDec(databuf, 18, 21) '4バイト
    Dim bmp_height As Long '画像の縦サイズ
        bmp_height = HexToDec(databuf, 22, 25) '4バイト
    Dim bmp_bit As Integer '画像のビットサイズ
        bmp_bit = HexToDec(databuf, 28, 29) '2バイト
    Dim file_size As Long 'ファイルサイズ
        file_size = HexToDec(databuf, 2, 5) '4バイト

    Cells.Clear 'セルをクリア

    Range(Columns(1), Columns(bmp_width / image_power)).ColumnWidth = 0.31 'セルの横幅
    Range(Rows(1), Rows(bmp_height / image_power)).RowHeight = 3 'セルの縦幅

    Dim width_size As Long 'セル上の横サイズ
        width_size = Fix(bmp_width / image_power)
    Dim height_size As Long 'セル上の縦サイズ
        height_size = Fix(bmp_height / image_power)
        If height_size = 0 Then
            MsgBox "指定した倍率が小さすぎます", vbExclamation
            Exit Sub '高さが0になる場合、終了
        End If

    '=====================================================================================
    '倍率を考慮して補正するバイト数を調整
    '=====================================================================================
    Dim widthcount As Long '横のデータ数
    Dim addpos As Integer '埋めるバイト数
    widthcount = Fix(bmp_width * 3)
    If widthcount Mod 4 > 0 Then '※widthが4の倍数に満たない場合、横の実データ数を求める
        widthcount = Fix(widthcount / 4 + 1) * 4
        '例
        'widthcount = 192 * 3 = 576 → widthcount Mod 4 = 0バイト埋める → 1列 = 576バイト
        'widthcount = 191 * 3 = 573 → widthcount Mod 4 = 3バイト埋める → 1列 = 576バイト
        'widthcount = 190 * 3 = 570 → widthcount Mod 4 = 2バイト埋める → 1列 = 572バイト
        'widthcount = 189 * 3 = 567 → widthcount Mod 4 = 1バイト埋める → 1列 = 568バイト
    End If
    addpos = widthcount - width_size * image_power * 3 '倍率に応じた不足分を調整
    '=====================================================================================

    Dim pos As Long 'データオフセット
    Dim w_index As Long 'ビットマップの横位置
    Dim h_index As Long 'ビットマップの縦位置
        w_index = 1 '横の初期位置座標(左)をセット
        h_index = height_size '縦の初期位置座標(下)をセット

    pos = 54 '初期値(データ先頭位置)
    For h_index = h_index To 1 Step -1 '高さのループ
        For w_index = 1 To width_size '幅のループ
            Cells(h_index, w_index).Interior.Color = _
                RGB(HexToDec(databuf, pos + 2, pos + 2), _
                HexToDec(databuf, pos + 1, pos + 1), _
                HexToDec(databuf, pos, pos)) 'データに対応するセル背景色にRGBを指定
            pos = pos + 3 * image_power '横移動
        Next
        pos = pos + addpos '4バイト区切りの不足分を加算(posを調整)
        pos = pos + widthcount * (image_power - 1) '列×倍率分飛ばす(縦移動)
    Next
    MsgBox "画像の展開が完了しました" '処理完了
End Sub

'連続したバイト配列の値を10進数に変換する関数
Function HexToDec(ByRef databuf, first, last) As Long

    Dim i As Long 'ループカウンタ
    Dim temp As String '16進数を格納する文字列配列
        temp = ""
    For i = last To first Step -1 '後ろから処理
        temp = temp + Right("00" & Hex(databuf(i)), 2) '10進数を16進数に変換
    Next
    HexToDec = Val("&H" & temp) '16進数を10進数に変換
End Function

< 使用 Excel:Excel2007、使用 OS:Windows7 >


http://vbasokkou.dokkoisho.com/bmp.html

 VBAは上記のリンク先のもののようだ。

 なぜ依頼者に「私のレベルでは無理」と断らないのだろう?
(ねむねむ) 2016/05/10(火) 14:22

 >        filename = ThisWorkbook.Path + "\00002.bmp" '読み込むファイル

 それを下の2文に変えるだけじゃないですか? 当方でテストはしておりません <(_ _)>

         Filename = ThisWorkbook.Sheets("Sheet1").Range("B3").Value '読み込むファイル
         ThisWorkbook.Sheets("Sheet2").Select

(半平太) 2016/05/10(火) 14:32


 ねむねむさんと同じ感想を持ちました。
 というか、その依頼した人も、このコードを見つけるぐらいなら、それを元に自分でできないのでしょうか?
 できないので、ひろりんさんに相談したということは、その人から見て、ひろりんさんは、VBAの達人で
 頼めば何とかなると そう思ったんでしょうね。

 で、ひろりんさんは? 【まかしといて! かんたんだよ〜!】とでも答えたんですかね?

 ちなみに、バージョンによって制限値は異なってくると思いますが、xl2013の場合、
 新規ブックで、以下のコードを走らせると 65430個目の書式設定で、エラーになりますね。

Sub test()

    Dim i As Long
    On Error GoTo bye
    For i = 1 To 100000
        Cells(i, 1).Interior.Color = i
    Next
bye:
    MsgBox i
End Sub

 ★世の中にはフリーソフトでドット絵を描くものがたくさんでまわっているようです。
  なぜ、そういったものを使わないのでしょうか?

(β) 2016/05/10(火) 16:26


セルにフルパスを書いてしまうと、ドット絵で上書きしてセルが小さくなってしまうので、ファイル選択ダイアログを使う案。
ついでに、データ開始位置が固定だったり、無駄な関数使用で遅かったりした部分を修正。
更に、縮小時に間引くのではなく、画素の平均を取ることで、少しはなめらかな画像に変えてみました。

 Sub test()
    Const IMAGE_POWER = 2
    Dim filename As String
    Dim ff As Integer
    Dim databuf() As Byte
    Dim file_size As Long
    Dim data_offset As Long
    Dim bmp_width As Long
    Dim bmp_height As Long
    Dim bmp_bit As Integer
    Dim widthcount As Long
    Dim i As Long
    Dim j As Long
    Dim i2 As Long
    Dim j2 As Long
    Dim iR As Long
    Dim iG As Long
    Dim iB As Long

    With Application.FileDialog(msoFileDialogOpen)
        .Filters.Clear
        .Filters.Add "BMPファイル", "*.bmp"
        .InitialView = msoFileDialogViewLargeIcons
        If Not .Show Then Exit Sub

        filename = .SelectedItems(1)
    End With

    ff = FreeFile
    Open filename For Binary As #ff
        Get #ff, 3, file_size
        Get #ff, 11, data_offset
        Get #ff, 19, bmp_width
        Get #ff, 23, bmp_height
        Get #ff, 29, bmp_bit
        ReDim databuf(file_size - data_offset - 1)
        Get #ff, data_offset + 1, databuf
    Close #ff

    If bmp_bit <> 24 Then
        MsgBox bmp_bit & "bitカラーには対応していません。", vbCritical, "色数エラー"
        End
    End If

    widthcount = Int((bmp_width + 3) / 4) * 4

    With Sheets(1)
        .Cells.Clear
        With .Range("A1").Resize(bmp_height / IMAGE_POWER, bmp_width / IMAGE_POWER)
            .ColumnWidth = 0.3
            .RowHeight = 2.5
        End With

        Application.ScreenUpdating = False
        For i = 0 To bmp_height - 1 Step IMAGE_POWER
            For j = 0 To widthcount - 1 Step IMAGE_POWER
                iR = 0
                iG = 0
                iB = 0
                For i2 = 0 To IMAGE_POWER - 1
                    For j2 = 0 To IMAGE_POWER - 1
                        iB = iB + databuf((i + i2) * widthcount * 3 + (j + j2) * 3 + 0)
                        iG = iG + databuf((i + i2) * widthcount * 3 + (j + j2) * 3 + 1)
                        iR = iR + databuf((i + i2) * widthcount * 3 + (j + j2) * 3 + 2)
                    Next j2
                Next i2
                iR = iR / IMAGE_POWER / IMAGE_POWER
                iG = iG / IMAGE_POWER / IMAGE_POWER
                iB = iB / IMAGE_POWER / IMAGE_POWER
                .Cells((bmp_height - i) / IMAGE_POWER, j / IMAGE_POWER + 1).Interior.Color = RGB(iR, iG, iB)
            Next j
        Next i
        Application.ScreenUpdating = True
    End With

    MsgBox "画像の展開が完了しました", vbInformation, "処理終了"
 End Sub

こういうロジックは、自分で作って動かすところが面白いのですけどねぇ。
(???) 2016/05/10(火) 17:30


注意点。画素数が倍率で割りきれない場合を考慮していませんので、元画像は倍率で割りきれるサイズにしておいてください。
(???) 2016/05/10(火) 17:43

ねむねむ様、半平太様、β様、???様
回答ありがとうございます。
実は手芸のオバサンは会社の創業者の娘で肩書きは専務です。
以前同じ様なことで、断ったら減給された人がいました。
今日も残業で明日迄には無理と思いたよってしまいました。
返事が遅れてすみませんでした。
また、いろいろ考えて頂きありがとうございました。
(ひろりん) 2016/05/10(火) 20:50

 であればフリーソフトを教えてあげれば、もっと喜ばれるかもしれませんよ。
 ところで、こんなコードもありました。

http://i-break.net/article/68821422.html

(β) 2016/05/10(火) 22:04


もう見ないかも知れませんが、懸案事項なぞ。

目的がビーズ細工との事なので、使えるビーズの色数は限りがあるかと思います。
また、今回のマクロでは、フルカラーでセルを塗るだけなので、セル毎にどんなRGB値なのか調べていくのはかなり面倒ではないかと思います。
つまり、フルカラーのままでは使い物にならないのではないか、と。

欲しいのは、予めビーズ番号とRGBを列挙しておくと、セル毎に最も近い色のビーズ番号を表示してくれるような機能ではないかと思います。
これを実現するには、今回のロジックだけでは足りず、特定の色に合わせた減色機能が必要になり、市販アプリ作成並の難易度になります。
専務さんにこれを作れ、と言われたら、どうするのでしょうね?

安上がりな案としては、GIMPのようなフリーの画像編集アプリを利用し、ビーズ種類分の色パレット作成。256色に減色(使うパレット数はビーズ種類分だけ)まで実現する事。
そして、Excel側はパレット付き8bitカラーに対応させ、色塗りだけでなく、番号表示も行う事です。
(???) 2016/05/11(水) 09:24


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.