HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2006
0918
Drip2色ビットマップの書き出し6解決


Drip

リンク

2006/9/18(Mon) 17:04:41|NO.2496

Dripです。

 縦横1000ピクセルを超える巨大なビットマップを扱うプログラムを作っているのですが、
使用する色が2色なため、保存するときは2色ビットマップを用いることで
データサイズを256色の画像よりも約8倍軽くすることができるのですが、
HSPから2色ビットマップを書き出すことはできないでしょうか。
2色ビットマップはあまり使用されないのか、情報が少なく困っています。

 大きな画像でも素早く2色ビットマップを書き出す
何か良い方法がありましたら教えていただければ幸いです。



この記事に返信する


Bomb

リンク

2006/9/22(Fri) 20:04:10|NO.2557

> 大きな画像でも素早く2色ビットマップを書き出す
>何か良い方法がありましたら教えていただければ幸いです。

2色というのがモノクロ(白黒2色)限定であるなら "GetDIBits" 関数が簡単、
そうでないなら "CreateDIBSection" 関数を使うのが良いと思います。

下記サンプルの頭で定義している MONOCHROME_IMAGE という定数が
0 なら "CreateDIBSection" 関数で、
1 なら "GetDIBits" 関数で実行ファイルのあるディレクトリに
"1ビット.bmp" という名前のファイルを出力する(そのように作ったつもり)ので
試してみて下さい。

APIだから大きな画像でも処理速度は遅くはないと思いますが、
どちらも減色やビット変換は全てAPI任せなので画質の方は...(-_-;?

#define MONOCHROME_IMAGE 1; // [ 0 = "CreateDIBSection" / 1 = "GetDIBits" ] #uselib "GDI32.DLL" #if MONOCHROME_IMAGE #func GetDIBits "GetDIBits" int, int, int, int, int, int, int #else #func CreateDIBSection "CreateDIBSection" int, int, int, int, int, int #func CreateCompatibleDC "CreateCompatibleDC" int #func SelectObject "SelectObject" int, int #func BitBlt "BitBlt" int, int, int, int, int, int, int, int, int #func DeleteDC "DeleteDC" int #func DeleteObject "DeleteObject" int #define SRCCOPY $00CC0020 #endif #define DIB_RGB_COLORS $0000 #define BI_RGB $0000 dialog "jpg;*.bmp;*.gif", 16, "セーブ元画像の選択" : if ( stat == 0 ) : end screen 0,,,,0,0 : picload refstr : width ginfo_dispx - 6 title " 1ビットでBMPセーブする元画像!" biSizeImage = ( ginfo_sx * 1 + 31 ) / 32 * 4 * ginfo_sy bfOffBits = 14 + 40 + 4 * 2; // sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 bfSize = biSizeImage + bfOffBits dim bmf, ( bfSize + 3 ) / 4 // BITMAPFILEHEADER wpoke bmf, 0, 'M' << 8 | 'B'; // bfType lpoke bmf, 2, bfSize wpoke bmf, 6, 0; // bfReserved1 wpoke bmf, 8, 0; // bfReserved2 lpoke bmf, 10, bfOffBits dupptr bmi, varptr(bmf) + 14, biSizeImage + 40 + 4 * 2, 4 // BITMAPINFOHEADER bmi(0) = 40; // biSize = sizeof(BITMAPINFOHEADER) bmi(1) = ginfo_sx; // biWidth bmi(2) = ginfo_sy; // biHeight bmi(3) = 1 << 16 | 1; // biBitCount << 16 | biPlanes bmi(4) = BI_RGB; // biCompression bmi(5) = biSizeImage bmi(6) = 0; // biXPixPerMeter bmi(7) = 0; // biYPixPerMeter bmi(8) = 2; // biClrUsed bmi(9) = 0; // biClrImporant #if MONOCHROME_IMAGE mref bmscr, 67 GetDIBits hdc, bmscr(7), 0, ginfo_sy, varptr(bmi) + 40 + 4 * 2, varptr(bmi), DIB_RGB_COLORS #else // RGBQUAD ( 下の2行で設定した2色の1ビットBMP画像が生成されます ) bmi(10) = 0x000000FF; // RGBQUAD[0] bmi(11) = 0x0080FF80; // RGBQUAD[1] CreateDIBSection 0, varptr(bmi), DIB_RGB_COLORS, varptr(pvBits), 0, 0 : hDIB = stat CreateCompatibleDC hdc : hMDC = stat SelectObject hMDC, hDIB : hOLD = stat BitBlt hMDC, 0, 0, ginfo_sx, ginfo_sy, hdc, 0, 0, SRCCOPY SelectObject hMDC, hOLD DeleteDC hMDC dupptr Bits, pvBits, biSizeImage, 4 memcpy bmi, Bits, biSizeImage, 40 + 4 * 2, 0 DeleteObject hDIB #endif bsave dir_exe +"\\1ビット.bmp", bmf, bfSize, -1 if ( strsize != bfSize ) : dialog "セーブ失敗!" : end screen 1,,,0,22,22 : picload dir_exe +"\\1ビット.bmp" title " セーブした1ビットBMP画像! ( ファイルサイズ = "+ bfSize +" bytes )"



Drip

リンク

2006/9/23(Sat) 13:40:55|NO.2572

Dripです。

 Bombさん、ご返信ありがとうございます。
なんとそんなやりかたがあったのですね;
2色ビットマップを書き出すソフトはWindowsPaintぐらいしか見かけないので、
WindowsPaintの2色書き出しはてっきりWindowsPaintの内部処理だと思ってました;

 大変参考になるアドバイス有難うございました。



Bomb

リンク

2006/9/26(Tue) 21:00:14|NO.2655

書くの忘れてたけど、"GetDIBits" 関数ならRLE(ランレングス)圧縮の
ビットマップファイルを作る事も可能なので、横方向に同じ色が連続して
いるような白黒2色画像なら1ビット無圧縮でセーブするより、
4ビットRLE圧縮でセーブした方がサイズを小さく出来る可能性が高いよ。

興味があれば、試行錯誤してみて下さい。



Drip

リンク

2006/10/1(Sun) 18:06:15|NO.2771

Dripです。

 ご返信が遅れてすみません。解決マークをつけてしまっていたのでbombさんのご返信に
全く気づきませんでした。2度にわたる情報提供本当に有難うございます。

 確かにランレングス圧縮を用いれば効率のよい保存ができそうですね。
今回の保存の仕方は初めてだったので、googleからGetDIBitsでBI_RLE4を指定して、
スクリーンの表示状態を圧縮する方法を探り実行してみたのですが、
どういうわけか破損したビットマップしか生成されず少し困ってます。

 単純な画像なのにファイルサイズが非圧縮時よりかなり大きかったり、
Windowsペイントでしか開けなかったりと、なんだか挙動が怪しいです。
biCompressionにBI_RLE4($0002)を指定した場合は、
biBitCount=4、biClrUsed=16、等とRLE4用に値を差し替えていったのですが、
そもそも圧縮後のファイルサイズが不明なのでbiSizeImageの値も特定できず、
うまくいきません。

 そう言えば参考にしたサイトの中で
RLE4とRLE8の値($0001と$0002)が逆に説明されているところもあったので、
なんだか参考元の情報も怪しいのかも・・。
http://www.kk.iij4u.or.jp/~kondo/bmp/

うぅん;



Bomb

リンク

2006/10/1(Sun) 23:46:11|NO.2790

> ご返信が遅れてすみません。解決マークをつけてしまっていたのでbombさんのご返信に
>全く気づきませんでした。2度にわたる情報提供本当に有難うございます。

いえいえ、私も最初の返信から4日もたってから思い出しているので気にしないで下さい。

> 単純な画像なのにファイルサイズが非圧縮時よりかなり大きかったり、
>Windowsペイントでしか開けなかったりと、なんだか挙動が怪しいです。

RLE圧縮は、画像によっては無圧縮よりサイズが大きくなったりしますよ...(^_^;

>そもそも圧縮後のファイルサイズが不明なのでbiSizeImageの値も特定できず、
>うまくいきません。

BITMAPINFOHEADER構造体の biSize メンバから biCompression メンバまでに値を設定して
"GetDIBits" 関数の lpvBits を NULL(0) で実行すれば RGBQUAD部分にパレットデータと
biSizeImage メンバにビットマップデータのサイズが代入されて返るので、
その値でRLE圧縮時のデータサイズ(biSizeImage)を知る事が出来ます。

#define global RLE_SUPPORT 1; // RLE圧縮サポート = [ 0 = 無効 / 1 = 有効 ] #module #ifndef __GDI32__ #uselib "GDI32.DLL" #func GetDIBits "GetDIBits" int, int, int, int, int, int, int #endif #define DIB_RGB_COLORS $0000 #define BI_RGB $0000 ;#define BI_RLE8 $0001 ;#define BI_RLE4 $0002 ;================================================================================= ; ○ 指定ビット数のビットマップファイルセーブ! ;================================================================================= #deffunc dibsave str fname, int bit // bit = セーブするビットマップファイルのビット数( 1 / 4 / 8 / 16 / 24 / 32 bit ) // ( RLE_SUPPORT が ON(1) なら 4/8ビットは圧縮効果がある時はRLE圧縮形式でセーブします ) // 戻り値 = 成功なら BITMAPINFOHEADER->biCompression の値をかえす。負の値ならセーブエラー! mref bmscr, 67 switch bit case 1 case 4 case 8 case 16 case 24 case 32 biBitCount = bit swbreak default biBitCount = 24 - bmscr(3) * 16 swbreak swend biSizeImage = ( ginfo_sx * biBitCount + 31 ) / 32 * 4 * ginfo_sy biClrUsed = ( biBitCount <= 8 ) << biBitCount bfOffBits = 14 + 40 + 4 * biClrUsed; // sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * biClrUsed bfSize = biSizeImage + bfOffBits dim bmf, ( bfSize + 3 ) / 4 // BITMAPFILEHEADER wpoke bmf, 0, 'M' << 8 | 'B'; // bfType lpoke bmf, 2, bfSize wpoke bmf, 6, 0; // bfReserved1 wpoke bmf, 8, 0; // bfReserved2 lpoke bmf, 10, bfOffBits dupptr bmi, varptr(bmf) + 14, biSizeImage + 40 + 4 * biClrUsed, 4 // BITMAPINFOHEADER bmi(0) = 40; // biSize = sizeof(BITMAPINFOHEADER) bmi(1) = ginfo_sx; // biWidth bmi(2) = ginfo_sy; // biHeight bmi(3) = biBitCount << 16 | 1; // biBitCount << 16 | biPlanes bmi(4) = BI_RGB; // biCompression bmi(5) = biSizeImage bmi(6) = 0; // biXPixPerMeter bmi(7) = 0; // biYPixPerMeter bmi(8) = biClrUsed; // ← ここは 0 でも可! bmi(9) = 0; // biClrImporant #if RLE_SUPPORT if ( biBitCount == 4 || biBitCount == 8 ) { // 4ビット or 8ビットの時はRLE圧縮時のサイズを調べる! bmi(4) = ( biBitCount == 4 ) * 2 + ( biBitCount == 8 ); // biCompression ( BI_RLE4 / BI_RLE8 ) GetDIBits hdc, bmscr(7), 0, ginfo_sy, 0, varptr(bmi), DIB_RGB_COLORS if ( stat != 0 && bmi(5) < biSizeImage ) { // 無圧縮よりもサイズが小さい時はRLE圧縮形式でセーブする! bfSize = bmi(5) + bfOffBits lpoke bmf, 2, bfSize } else { // メモリの再確保が面倒なので圧縮効果がない時は無圧縮BMP形式でセーブする! bmi(4) = BI_RGB bmi(5) = biSizeImage } } #endif GetDIBits hdc, bmscr(7), 0, ginfo_sy, varptr(bmi) + 40 + 4 * biClrUsed, varptr(bmi), DIB_RGB_COLORS if ( stat != ginfo_sy ) : return -1 bsave fname, bmf, bfSize, -1 : return ( ( strsize == bfSize ) * ( bmi(4) + 1 ) - 1 ) ;----------------------------------------------------------------------------------- #global ;=================================================================================== ; [ TEST SAMPLE ] dialog "jpg;*.bmp;*.gif", 16 : if ( stat == 0 ) : end screen 0,,,,0,0 : picload refstr : width ginfo_dispx - 6 : title " セーブ元画像!" dibsave dir_exe +"\\test.bmp", 1; // 1ビットでBMPセーブ! if ( stat < 0 ) : dialog "1ビットセーブ失敗!" : end; // -1 ならセーブエラー! screen 1,,,,22,22 : picload dir_exe +"\\test.bmp"; // セーブした1ビットBMPをロード! exist dir_exe +"\\test.bmp" title " 1ビットでセーブしたBMP画像 ( ファイルサイズ = "+ strsize +" bytes )" dibsave dir_exe +"\\test.bmp", 4; // 1ビットでセーブした白黒画像を4ビットRLE圧縮形式で上書きセーブ! biCompression = stat; // biCompression の値が返る! if ( biCompression < 0 ) : dialog "4ビットセーブ失敗!" : end; // -1 ならセーブエラー! screen 2,,,,44,44 : picload dir_exe +"\\test.bmp"; // セーブした4ビットBMPをロード! exist dir_exe +"\\test.bmp" if ( biCompression ) { title " RLE圧縮形式でセーブしたBMP画像 ( ファイルサイズ = "+ strsize +" bytes )" } else {// biCompression == 0 なら圧縮効果がないので無圧縮でセーブされています! title " 無圧縮でセーブしたBMP画像 ( ファイルサイズ = "+ strsize +" bytes )" }
# サンプル書いてて気付いたけどHSP3の picload は 16ビットやトップダウンの
# ビットマップファイルも読めるようになってますね。(*^o^*)V
# ヘルプは、相変わらず 4,8,24bitのデータってなったままですけど...



Drip

リンク

2006/10/2(Mon) 20:49:53|NO.2817

Dripです。

 Bombさん、詳しい説明とサンプルスクリプトまでご教授くださり、
本当に有難うございます。今少し忙しくて詳しく見れないのですが、取り急ぎお礼まで。
スクリプトには、識別子のコメントまで詳しく書かれているので、大変参考になりそうです。
今回は本当に色々と勉強になりました。
Bombさん、度々のご丁寧なご返信に心から感謝致します。



ONION software Copyright 1997-2023(c) All rights reserved.