画像ファイル保存時にサイズを小さくするには?

解決


のん  2005-07-11 23:15:34  No: 123424

はじめまして。
VB6.0でSaveAsでPictureBoxの画像を保存すると
元のFileの大きさは1,000KB程度だったのに、
保存されたファイルの大きさは25,000KBぐらいまで
大きくなってしまいます。

元のFileとの違いは、Imageを経由して
非表示になっているPictureBoxに線や文字を書き込んでいるくらいなのですが、
何も書き込まずに、そのまま保存しても、サイズは25,000KBぐらいになります。

また、画像はスキャナで取り込んだ画像で、
実行時にPictureBoxを表示すると、
非常に大きくて画面にはとても入りきりません。
かといって解像度を下げてしったりすると、
元の紙(スキャナした紙)自体のインクが薄かったり、
汚かったりしているので、Imageに表示したときや、
印刷するときに影響が出てしまいます。

概要としては、
Image・・・PreView用のコントロール(表示)
           画像の縦横比を計算して表示範囲一杯に表示しています。
PictureBox・・・編集用のコントロール(非表示)
                Image上で行ったイベントやアクションを
                プログラムで制御してPictureBoxで編集し、
                編集後、Imageに再表示させています。
                AutoSize=True
                AutoRedraw=True
                Visible=True
となっています。
画像の解像度の事はよく分かりませんが、ほとんどが1,000KB前後です。
種類はJpegです。

登録する数が非常に多いので、
画像のサイズはできれば1,000KB〜1,500KB程度に収めたいのですが、
何か方法はあるのでしょうか?

宜しくお願いします。


のん  2005-07-11 23:18:18  No: 123425

すいません。
PictureBoxの
Visible=Trueとなっていますが、
通常は
Visible=Falseです。
テストで実行した時にTrueにしてました。


ねろ  2005-07-12 00:00:55  No: 123426

>VB6.0でSaveAsでPictureBoxの画像を保存すると
SaveAsって? ひょとしてVB.NET?
変なこと言ってるのは私の方か??


魔界の仮面弁士  2005-07-12 00:06:03  No: 123427

SavePicture の解説をよく読んでみましょう。
http://www.microsoft.com/japan/developer/library/vb98/vbstmSavePicture.htm

》デザイン時または実行時にオブジェクトの Picture プロパティにファイルから
》ピクチャをロードしたとき、そのピクチャがビットマップ、アイコン、メタファイル、
》または拡張メタファイルであれば、元のファイルと同じ形式で保管されます。

ここには、「元のファイルと同じ形式」とありますが、それはPictureプロパティや
Pictureオブジェクトの場合である事に注意してください。

> 元のFileとの違いは、Imageを経由して
> 非表示になっているPictureBoxに線や文字を書き込んでいるくらいなのですが、

まずこれが、第一の原因です。画像を Image プロパティ経由で取り出した場合は、
画像の形式が異なってしまいます。実際、ヘルプの SavePicture の解説にも、

『Image プロパティ内のピクチャは、元のファイルの形式にかかわらず、
  常にビットマップ (.BMP) ファイルとして保管されます。』

とあります。ビットマップゆえ、データサイズが大きくなってしまうわけです。
(ちなみに画像の色数は、画面の設定に依存します)

> 種類はJpegです。

これが第二の原因でしょう。再び、ヘルプの SavePicture の項を読むと、
『GIF ファイルまたは JPEG ファイルであれば、ビットマップ ファイルとして保管されます』
という一文があります。

> 何か方法はあるのでしょうか?
再圧縮しても構わないなら、GDI+ を使って、PNG や JPEG にしてみては如何でしょう。

http://yaplog.jp/orator/archive/29


のん  2005-07-12 01:49:28  No: 123428

ねろさんすみません。
SaveAsじゃなくて、SavePictureでした。

魔界の仮面弁士さんありがとうございます。

第一の原因ではなく、第二の原因の方ではないかと思います。
Imageを経由してと書きましたが、
Imageはユーザーのイベントを認識させるために表示させているだけで、
実際にはImageで受け取ったイベントで
実際の画像との縮小率なんかを計算してPictureの画像を変更し、
その後、Pictureを指定のFilePathで保存し、
すぐに、Imageに同じFilePathを使用して読み込んでいます。
ですので、Imageからの保存は一切行っていません。

http://yaplog.jp/orator/archive/29を
参考にしてみましたが、Sizeが0のFileが生成されてしまいました。

ここで用意するのはImage1というPictureと、ボタンだけでいいのでしょうか?
GDI+を使用するときに、何か設定とかはいるのでしょうか?


通ってみた  2005-07-12 02:30:10  No: 123429

フルカラーになっちゃうからじゃない?


魔界の仮面弁士  2005-07-12 03:23:40  No: 123430

> 実際にはImageで受け取ったイベントで
すみません、それはどういう事でしょうか?

「Imageプロパティ」でイベントを受け取る……だと意味が通りませんし、
「Imageコントロール」の意味だとすると、Pictureとの関連性が不明です。

> 実際の画像との縮小率なんかを計算してPictureの画像を変更し、
この場合の「Picture」とは、
  1. PictureBoxコントロール
  2.Pictureオブジェクト
  3. Pictureプロパティ
  4. Imageプロパティ
のいずれでしょうか?

> 参考にしてみましたが、Sizeが0のFileが生成されてしまいました。
うわっと。ソースが化けてますね……。すみません。

誤)  .Guid = ToCLSID("")
正)  .Guid = ToCLSID("{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}")

誤)  SavePictureJpeg = GdipSaveImageToFile(lngBitmap, StrPtr(filename), ToCLSID(""), VarPtr(udtEncoderParameters))
正)  SavePictureJpeg = GdipSaveImageToFile(lngBitmap, StrPtr(filename), ToCLSID("{557CF401-1A04-11D3-9A73-0000F81EF32E}"), VarPtr(udtEncoderParameters))

のようにしておいてください。(提示した URL 先の内容も、仮修正しておきました)

# ソース中の {……} と書いた部分が、yaplogでは表示されないらしい。(泣


のん  2005-07-13 21:17:43  No: 123431

魔界の仮面弁士さん、ありがとうございます。

ImageはImageコントロールです。
当初は画像の表示のみだったので、
表示させたい画像の縦横比を計算して、
画面の表示範囲内いっぱいに拡大/縮小表示させていました。

ところが、途中で仕様が変更になり、画像に取消線や文字(赤色)を
追加できるようにして欲しいとの要望がありました。

自分なりに調べたところ、
Imageコントロールでは画像の描画はできないとあったので
Imageコントロールと同時に
PictureBoxコントロールを非表示で配置し(AutoSizeはTrue)、
Imageコントロールで発生したイベント(MouseDown/Up)で座標を取得し、
そこからImageコントロール表示時に割出した拡大/縮小率を使用して
PictureBoxコントロールに.Lineや.Printを使って描画後、
別File名で保存し、再度Imageコントロールに表示しています。

別File名で保存するのは『一つ前(後)の動作に戻る(進む)』の
機能を持たせるための仮保存です。
描画した画像は保存ボタンでデータベースに登録します。
一番最初の画像もデータベースから読み込んでいます。

そこで仮保存した時のデータが大きくなってしまうのです。

>・・・・・のようにしておいてください。(提示した URL 先の内容も、仮修正しておきました)

この通り修正したら出来ました。ありがとうございます。

もう一つ問題があるのですが、同じ所なので別のスレを立てずに追加で質問させていただきます。

上記に<PictureBoxコントロールに.Lineや.Printを使って描画>とありますが、
ここは選択方式で普通の線か楕円かを選らんで描画するというプログラムにしています。

文字や線だと問題ないのですが、楕円を描画する時に、Ellipseを
使用すると、どうしても正しい位置に描画されません。

たぶん、TwipsとPixelsの問題だと思うのですが、
ImageコントロールMouseDown/Upイベントで取得する座標がTwipsで、
EllipseではPixelsで判断しているからではないかと考えています。

そこで、MouseDown/Upイベントで取得した座標をPixelsに変換して
Ellipseを実行したいのですが、変換の仕方がよくわかりません。
(自分が考えている問題やこのやり方が正しいのかも分かっていないのですが)

説明不足や誤字が多くて申し訳ありませんでした。
続けての質問で恐縮ですが、宜しくお願いします。


魔界の仮面弁士  2005-07-13 21:57:58  No: 123432

> 文字や線だと問題ないのですが、楕円を描画する時に、Ellipseを
> 使用すると、どうしても正しい位置に描画されません。
標準のCircleメソッドでも、楕円は描画できますね。
# 座標の指定方法が異なりますけど。

> 変換の仕方がよくわかりません。
ScaleX, ScaleYメソッドをどうぞ。あるいは、自前で演算しても良いかと。


特攻隊長まるるう  2005-07-13 22:16:19  No: 123433

>ScaleX, ScaleYメソッドをどうぞ。あるいは、自前で演算しても良いかと。
過去ログ検索『Twips』で具体的な演算方法まで引っ掛かったりします(^^)


のん  2005-07-14 01:34:52  No: 123434

魔界の仮面弁士さん
特攻隊長まるるうさん
ありがとう御座います。

>ScaleX, ScaleYメソッドをどうぞ。あるいは、自前で演算しても良いかと。

ScaleX/Yは、HELPで見てもよく意味が分からなかったので、
TwipsPerPixelX/Yを使ったら、表示することが出来ました。

解決しました。
ありがとう御座いました。


Dental  2005-07-14 02:28:15  No: 123435

> ScaleX/Yは、HELPで見てもよく意味が分からなかったので、

W = 1500
Debug.Print W; "Twips は"; Me.ScaleX(W, vbTwips, vbPixels); "Pixels です。"
Debug.Print W; "Twips は"; Me.ScaleX(W, vbTwips, vbCentimeters); "cm です。"
Debug.Print W; "Twips は"; Me.ScaleX(W, vbTwips, vbPoints); "pt. です。"

> 解決しました。
であれば、[解決]チェックを付けるべきなのでは。


のん  2005-07-14 02:59:03  No: 123436

すいません。解決チェック忘れてました。


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加