Tuesday, December 01, 2009

Stream Read Error

這兩個星期, 由於撰寫 IPCDMC範例程式 的緣故, 遭遇一個以前未曾發生過的問題: 我用 Photoshop CS 所儲存的 bmp 檔案, 用 C++ Builder 6 開啟, 會發生 Stream read error, 如下圖:



我的第一個反應也是問 Google 大神, 順利找到了一些相關討論[1, 2, 3], 但始終沒有人可以指出確切的問題點。

昨天晚上, 由於 對比度擴展(Contrast Stretching)範例程式 的實驗需要造一張低對比度的影像, 而我的電腦又只有灌 Photoshop CS, 因此逼得我一定要面對這個問題。



由於錯誤訊息是 Stream read error, 因此, 我直接排除是程式撰寫上的問題, 直接從有問題的 bmp 影像開始研究。為了比較, 我將可以順利用 C++ Builder 6 開啟的檔案 Carnivore.bmp 用 Photoshop CS 另存新檔 CarnivorePSCS.bmp, 然後再分別用 PSPad 用 Hex editor 開啟, 比較兩個檔案的異同。

BCB6-PS-bmp-StreamReadError.txt 在這個檔案中, 我列出了兩個 bmp 檔頭資料以供比對, 我發現兩個檔頭資料中, 只有第 34-37 位元組的影像原始大小有差異, 可以順利開啟的 Carnivore.bmp 並沒有儲存影像大小到檔頭之中, 而 CarnivorePSCS.bmp 則是存放了 0200 0C00 的資料, 我當下用 PSPas 將第 34-37 位元組修改成 0000 0000, 果然 CarnivorePSCS.bmp 就可以用 C++ Builder 6 順利開啟了。

接下來, 我當然先去完成 對比度擴展(Contrast Stretching)範例程式 的實驗, 把低對比度的彩色影像自動處理成高對比度的影像, 並完成 部落格範例程式的文章

今天, 在往學校的路上, 我一直在思考為何 Photoshop CS 會多此一舉把影像大小的值放進去, 而且還造成 C++ Builder 6 無法讀取? 難道 Photoshop CS 會把影像大小 Width * Height * BitCount / 8 這麼簡單的數學計算錯誤嗎?

晚上回到家後, 把 0200 0C00 換算, 得到 786434, 然而影像大小

 Width * Height * BitCount / 8
= 512 * 512 * 24 / 8
= 786432

果然就如同自己所推測的一樣, 影像大小差了 2 個 bytes。

我最後的一個實驗是將 CarnivorePSCS.bmp 的第 34-37 位元組 (影像大小) 修改成 0000 0C00, 果然 也可以用 C++ Builder 6 順利開啟。

真相大白了 !
 

Wednesday, November 25, 2009

CreatePalette function

The CreatePalette function creates a logical color palette.

HPALETTE CreatePalette(
 CONST LOGPALETTE *lplgpl   // pointer to logical color palette
 );

Parameters

lplgpl Points to a LOGPALETTE structure that contains information about the colors in the logical palette.

Return Values

If the function succeeds, the return value is a handle that identifies a logical palette.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant. Once an application creates a logical palette, it can select that palette into a device context by calling the SelectPalette function. A palette selected into a device context can be realized by calling the RealizePalette function.
When you no longer need the palette, call the DeleteObject function to delete it.
 

PALETTEENTRY structure

The PALETTEENTRY structure specifies the color and usage of an entry in a logical color palette. A logical palette is defined by a LOGPALETTE structure.

typedef struct tagPALETTEENTRY { // pe
 BYTE peRed;
 BYTE peGreen;
 BYTE peBlue;
 BYTE peFlags;
} PALETTEENTRY;

Members

 peRed Specifies a red intensity value for the palette entry.

 peGreen Specifies a green intensity value for the palette entry.

 peBlue Specifies a blue intensity value for the palette entry.

 peFlags Specifies how the palette entry is to be used.

The peFlags member may be set to NULL or one of the following values:

Value Meaning

PC_EXPLICIT Specifies that the low-order word of the logical palette entry designates a hardware palette index. This flag allows the application to show the contents of the display device palette.

PC_NOCOLLAPSE
Specifies that the color be placed in an unused entry in the system palette instead of being matched to an existing color in the system palette. If there are no unused entries in the system palette, the color is matched normally. Once this color is in the system palette, colors in other logical palettes can be matched to this color.

PC_RESERVED
Specifies that the logical palette entry be used for palette animation. This flag prevents other windows from matching colors to the palette entry since the color frequently changes. If an unused system-palette entry is available, the color is placed in that entry. Otherwise, the color is not available for animation.
 

LOGPALETTE structure

The LOGPALETTE structure defines a logical color palette.

typedef struct tagLOGPALETTE {  // lgpl
 WORD palVersion;
 WORD palNumEntries;
 PALETTEENTRY palPalEntry[1];
} LOGPALETTE;


Members

palVersion Specifies the Windows version number for the structure (currently 0x300).

palNumEntries Specifies the number of entries in the logical color palette.

palPalEntry Specifies an array of PALETTEENTRY structures that define the color and usage of each entry in the logical palette.

Remarks
 
The colors in the palette-entry table should appear in order of importance because entries earlier in the logical palette are most likely to be placed in the system palette.
 

Wednesday, November 18, 2009

TBrush

Determines the color and pattern for filling graphical shapes and backgrounds.

__property TBrush* Brush = {read=FBrush, write=SetBrush};

Description


Set the Brush property to specify the color and pattern to use when drawing the background or filling in graphical shapes. The value of Brush is a TBrush object. Set the properties of the TBrush object to specify the color and pattern or bitmap to use when filling in spaces on the canvas.

Note: Setting the Brush property assigns the specified TBrush object, rather than replacing the current TBrush object.
Note: Brush must have a Style of bsSolid before you can paint.


Example:
Image1->Canvas->Brush->Color =(TColor)RGB(130,67,33);
設定 Image1 畫布上筆刷的顏色為 (130,67,33)。

Tuesday, November 17, 2009

TCanvas::Pixels

TCanvas 有一個 property , 一般表示成 TCanvas::Pixels, 是我們常會用到的, Pixels 這個 property 可以讀出, 也可以寫入某個特定位置的色彩值, 因此這個 property 的類別為 TColor。在 BCB Help 中的說明如下:
TCanvas::Pixels
Specifies the color of the pixels within the current ClipRect.

__property TColor Pixels[int X][int Y] = {read=GetPixel, write=SetPixel};

Description
Read Pixels to learn the color on the drawing surface at a specific pixel position within the current clipping region. If the position is outside the clipping rectangle, reading the value of Pixels returns -1.

Write Pixels to change the color of individual pixels on the drawing surface. Use Pixels for detailed effects on an image. Pixels may also be used to determine the color that should be used for the FillRect method.

Not every device context supports the Pixels property. Reading the Pixels property for such a device context will return a value of -1. Setting the Pixels property for such a device context does nothing.

Thursday, October 22, 2009

如何將 AnsiString 轉成 char 資料型態?

.c_str(); // for 舊版 C++ Builder
.t_str(); // for 新版 C++ Builder 2009

Example:
fopen(OpenDialog1->FileName.t_str(),"r");

Thursday, October 15, 2009

TBitmap::PixelFormat

Indicates the bit format of the bitmap image, specifying how the image is displayed and how the pixels of the bitmap image are stored in memory.

enum TPixelFormat {pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom};
__property TPixelFormat PixelFormat = {read=GetPixelFormat, write=SetPixelFormat, nodefault};

Description

Use PixelFormat to change a TBitmap's internal image to a particular memory format and color depth, or to find out what memory format and color depth a TBitmap is using.

For example, PixelFormat can be used to set the pixel format of the bitmap image to 8-bit for video drivers that cannot display the native format of a bitmap image.

Changing the pixel format is most commonly used with ScanLine, because your code must decode the pixel data accessed by ScanLine. Image-editing tools usually use one pixel for all internal image operations and copy the results to the screen (in whatever format) as the last step.

Friday, September 25, 2009

如何取得影像某個像素的色彩值: GetRValue();

ucMR[i][j] =GetRValue(Image1->Canvas->Pixels[j][i]);

Tuesday, March 24, 2009

使用者自定之副程式如何存取物件之相關資料

在 C++ Builder 中撰寫副程式, 如果要存取物件中的相關資料, 必須從 Form1 開始描述起, 不可以直接寫物件之名稱, 否則會有 Undefined symbol 的錯誤訊息。

Example:

Form1->StatusBar1->Panels->Items[0]->Text = AnsiString(iFrameCount);

Monday, March 23, 2009

TBitmap::ScanLine

Provides indexed access to each line of pixels.

__property void * ScanLine[int Row] = {read=GetScanline};

Description

ScanLine is used only with DIBs (Device Independent Bitmaps) for image editing tools that do low-level pixel work.


基本上, ScanLine 是 TBitmap 元件中的一個 Property, 存放著 Bitmap 某一橫列的色彩值在記憶體中存放的起始指標, 有了這個指標, 我們就可以直接在記憶體中直接存取, 修改影像內容。
 
更新記憶體後的影像元件的外觀顯示, 有可能和記憶體中不相符, 我們可以用 Refresh() 這個 method 來將影像的外觀重新顯示。

  Image1->Refresh();
 

Tuesday, March 10, 2009

Win32 GDI: 取得裝置內容代碼 GetDC

圖形裝置介面 (GDI: Graphics Device Interface) 是 Windows 的子系統, 負責在螢幕或印表機上顯示圖形。Windows GDI 由幾百個函式呼叫組成, 也定義了相關的資料形態, 結構與巨集。

當我們想要在一個圖形輸出設備上繪圖, 或是做一些基本操作時, 首先我們必須要先獲得一個裝置內容(device context)的代碼。

取得顯示裝置代碼(display device context)的方式之一就是使用 GetDC 指令。

當 Windows 將顯示裝置代碼傳回給程式的同時, 也給了我們使用該顯示裝置的許可權限, 之後程式便是透過這個代碼告訴 Windows 要在這個裝置上進行繪圖, 因此, 這個代碼也將成為 GDI 函式中的一個輸入參數。

The GetDC function retrieves a handle of a display device context (DC) for the client area of the specified window. The display device context can be used in subsequent GDI functions to draw in the client area of the window.

This function retrieves a common, class, or private device context depending on the class style specified for the specified window. For common device contexts, GetDC assigns default attributes to the device context each time it is retrieved. For class and private device contexts, GetDC leaves the previously assigned attributes unchanged.

HDC GetDC(
HWND hWnd // handle of window
);

Parameters

hWnd

Identifies the window whose device context is to be retrieved.

Return Values

If the function succeeds, the return value identifies the device context for the given window's client area. If the function fails, the return value is NULL.

Remarks

After painting with a common device context, the ReleaseDC function must be called to release the device context. Class and private device contexts do not have to be released. The number of device contexts is limited only by available memory.