]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/src/_image.i
Added autoconf makefiles for FoldBar extended samples
[wxWidgets.git] / wxPython / src / _image.i
index 7c3ea504671eebe2f56254d198c96cb861b0a8d2..cb39a8c0a372012c1e0c7c9f267cb5ed256d6303 100644 (file)
@@ -68,46 +68,164 @@ public:
         "Find first colour that is not used in the image and has higher RGB
 values than startR, startG, startB.  Returns a tuple consisting of a
 success flag and rgb values.", "");
         "Find first colour that is not used in the image and has higher RGB
 values than startR, startG, startB.  Returns a tuple consisting of a
 success flag and rgb values.", "");
+
+    %extend {
+        DocStr(GetCount,
+               "Returns the pixel count for the given key.  Use `MakeKey` to create a
+key value from a RGB tripple.", "");
+        unsigned long GetCount(unsigned long key) {
+            wxImageHistogramEntry e = (*self)[key];
+            return e.value;
+        }
+
+        DocStr(GetCountRGB,
+               "Returns the pixel count for the given RGB values.", "");
+        unsigned long GetCountRGB(unsigned char r,
+                                  unsigned char g,
+                                  unsigned char b) {
+            unsigned long key = wxImageHistogram::MakeKey(r, g, b);
+            wxImageHistogramEntry e = (*self)[key];
+            return e.value;
+        }
+        
+        DocStr(GetCountColour,
+               "Returns the pixel count for the given `wx.Colour` value.", "");
+        unsigned long GetCountColour(const wxColour& colour) {
+            unsigned long key = wxImageHistogram::MakeKey(colour.Red(),
+                                                          colour.Green(),
+                                                          colour.Blue());
+            wxImageHistogramEntry e = (*self)[key];
+            return e.value;
+        }
+    }
+    
 };
 
 
 //---------------------------------------------------------------------------
 
 };
 
 
 //---------------------------------------------------------------------------
 
+%{
+    typedef unsigned char* buffer;
+%}    
+
+%typemap(in) (buffer data, int DATASIZE)
+    { if (!PyArg_Parse($input, "t#", &$1, &$2)) SWIG_fail; }
+
+%typemap(in) (buffer alpha, int ALPHASIZE)
+    { if (!PyArg_Parse($input, "t#", &$1, &$2)) SWIG_fail; }
+
+//---------------------------------------------------------------------------
+
 
 class wxImage : public wxObject {
 public:
 
 class wxImage : public wxObject {
 public:
-    wxImage( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 );
+    DocCtorStr(
+        wxImage( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 ),
+        "", "");
+    
     ~wxImage();
 
     // Alternate constructors
     ~wxImage();
 
     // Alternate constructors
-    %name(ImageFromMime) wxImage(const wxString& name, const wxString& mimetype, int index = -1);
-    %name(ImageFromStream) wxImage(wxInputStream& stream, long type = wxBITMAP_TYPE_ANY, int index = -1);
-    %name(ImageFromStreamMime) wxImage(wxInputStream& stream, const wxString& mimetype, int index = -1 );
+    DocCtorStrName(
+        wxImage(const wxString& name, const wxString& mimetype, int index = -1),
+        "", "",
+        ImageFromMime);
+    
+    DocCtorStrName(
+        wxImage(wxInputStream& stream, long type = wxBITMAP_TYPE_ANY, int index = -1),
+        "", "",
+        ImageFromStream);
+    
+    DocCtorStrName(
+        wxImage(wxInputStream& stream, const wxString& mimetype, int index = -1 ),
+        "", "",
+        ImageFromStreamMime);
+    
     %extend {
     %extend {
-        %name(EmptyImage) wxImage(int width=0, int height=0, bool clear = true) {
-            if (width > 0 && height > 0)
-                return new wxImage(width, height, clear);
-            else
-                return new wxImage;
-        }
+        %RenameDocCtor(
+            EmptyImage,
+            "Construct an empty image of a given size, optionally setting all
+pixels to black.", "",
+            wxImage(int width=0, int height=0, bool clear = true))
+            {
+                if (width > 0 && height > 0)
+                    return new wxImage(width, height, clear);
+                else
+                    return new wxImage;
+            }
 
 
-        MustHaveApp(wxImage(const wxBitmap &bitmap));
-        %name(ImageFromBitmap) wxImage(const wxBitmap &bitmap) {
-            return new wxImage(bitmap.ConvertToImage());
-        }
+        
+       MustHaveApp(wxImage(const wxBitmap &bitmap));
+        
+        %RenameDocCtor(
+            ImageFromBitmap,
+            "Construct an Image from a `wx.Bitmap`.", "",
+            wxImage(const wxBitmap &bitmap))
+            {
+                return new wxImage(bitmap.ConvertToImage());
+            }
 
 
-        %name(ImageFromData) wxImage(int width, int height, unsigned char* data) {
-            // Copy the source data so the wxImage can clean it up later
-            unsigned char* copy = (unsigned char*)malloc(width*height*3);
-            if (copy == NULL) {
-                PyErr_NoMemory();
-                return NULL;
+        %RenameDocCtor(
+            ImageFromData,
+            "Construct an Image from a buffer of RGB bytes.  Accepts either a
+string or a buffer object holding the data and the length of the data
+must be width*height*3.", "",
+            wxImage(int width, int height, buffer data, int DATASIZE))
+            {
+                if (DATASIZE != width*height*3) {
+                    wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+                    return NULL;
+                }
+            
+                // Copy the source data so the wxImage can clean it up later
+                buffer copy = (buffer)malloc(DATASIZE);
+                if (copy == NULL) {
+                    wxPyBLOCK_THREADS(PyErr_NoMemory());
+                    return NULL;
+                }            
+                memcpy(copy, data, DATASIZE);
+                return new wxImage(width, height, copy, false);
+            }
+
+        
+        %RenameDocCtor(
+            ImageFromDataWithAlpha,
+            "Construct an Image from a buffer of RGB bytes with an Alpha channel.
+Accepts either a string or a buffer object holding the data and the
+length of the data must be width*height*3.", "",
+            wxImage(int width, int height, buffer data, int DATASIZE, buffer alpha, int ALPHASIZE))
+            {
+                if (DATASIZE != width*height*3) {
+                    wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+                    return NULL;
+                }
+                if (ALPHASIZE != width*height) {
+                    wxPyErr_SetString(PyExc_ValueError, "Invalid alpha buffer size.");
+                    return NULL;
+                }
+
+                // Copy the source data so the wxImage can clean it up later
+                buffer dcopy = (buffer)malloc(DATASIZE);
+                if (dcopy == NULL) {
+                    wxPyBLOCK_THREADS(PyErr_NoMemory());
+                    return NULL;
+                }
+                memcpy(dcopy, data, DATASIZE);
+            
+                buffer acopy = (buffer)malloc(ALPHASIZE);
+                if (acopy == NULL) {
+                    wxPyBLOCK_THREADS(PyErr_NoMemory());
+                    return NULL;
+                }
+                memcpy(acopy, alpha, ALPHASIZE);
+            
+                return new wxImage(width, height, dcopy, acopy, false);
             }
             }
-            memcpy(copy, data, width*height*3);
-            return new wxImage(width, height, copy, false);
-        }
     }
 
     }
 
+    // TODO: wxImage( char** xpmData );
+
+
     void Create( int width, int height );
     void Destroy();
 
     void Create( int width, int height );
     void Destroy();
 
@@ -115,7 +233,16 @@ public:
     wxImage ShrinkBy( int xFactor , int yFactor ) const ;
     wxImage& Rescale(int width, int height);
 
     wxImage ShrinkBy( int xFactor , int yFactor ) const ;
     wxImage& Rescale(int width, int height);
 
+    // resizes the image in place
+    wxImage& Resize( const wxSize& size, const wxPoint& pos, 
+                     int r = -1, int g = -1, int b = -1 );
+    
     void SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b );
     void SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b );
+
+    %Rename(SetRGBRect,
+            void, SetRGB( const wxRect& rect,
+                          unsigned char r, unsigned char g, unsigned char b ));
+
     unsigned char GetRed( int x, int y );
     unsigned char GetGreen( int x, int y );
     unsigned char GetBlue( int x, int y );
     unsigned char GetRed( int x, int y );
     unsigned char GetGreen( int x, int y );
     unsigned char GetBlue( int x, int y );
@@ -124,6 +251,14 @@ public:
     unsigned char GetAlpha(int x, int y);
     bool HasAlpha();
 
     unsigned char GetAlpha(int x, int y);
     bool HasAlpha();
 
+    DocDeclStr(
+        void , InitAlpha(),
+        "Initializes the image alpha channel data. It is an error to call it if
+the image already has alpha data. If it doesn't, alpha data will be by
+default initialized to all pixels being fully opaque. But if the image
+has a a mask colour, all mask pixels will be completely transparent.", "");
+    
+    
     // find first colour that is not used in the image and has higher
     // RGB values than <startR,startG,startB>
     DocDeclAStr(
     // find first colour that is not used in the image and has higher
     // RGB values than <startR,startG,startB>
     DocDeclAStr(
@@ -146,6 +281,17 @@ If the image image doesn't have alpha channel, ConvertAlphaToMask does
 nothing.", "");
     
 
 nothing.", "");
     
 
+    DocDeclStr(
+        bool , ConvertColourToAlpha( unsigned char r, unsigned char g, unsigned char b ),
+        "This method converts an image where the original alpha information is
+only available as a shades of a colour (actually shades of grey)
+typically when you draw anti-aliased text into a bitmap. The DC
+drawing routines draw grey values on the black background although
+they actually mean to draw white with differnt alpha values.  This
+method reverses it, assuming a black (!) background and white text.
+The method will then fill up the whole image with the colour given.", "");
+    
+
     
     // Set image's mask to the area of 'mask' that has <mr,mg,mb> colour
     bool SetMaskFromImage(const wxImage & mask,
     
     // Set image's mask to the area of 'mask' that has <mr,mg,mb> colour
     bool SetMaskFromImage(const wxImage & mask,
@@ -161,14 +307,14 @@ nothing.", "");
     static int GetImageCount( const wxString& name, long type = wxBITMAP_TYPE_ANY );
 
     bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 );
     static int GetImageCount( const wxString& name, long type = wxBITMAP_TYPE_ANY );
 
     bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 );
-    %name(LoadMimeFile)bool LoadFile( const wxString& name, const wxString& mimetype, int index = -1 );
+    %Rename(LoadMimeFile, bool,  LoadFile( const wxString& name, const wxString& mimetype, int index = -1 ));
 
     bool SaveFile( const wxString& name, int type );
 
     bool SaveFile( const wxString& name, int type );
-    %name(SaveMimeFile)bool SaveFile( const wxString& name, const wxString& mimetype );
+    %Rename(SaveMimeFile, bool,  SaveFile( const wxString& name, const wxString& mimetype ));
 
 
-    %name(CanReadStream) static bool CanRead( wxInputStream& stream );
-    %name(LoadStream) bool LoadFile( wxInputStream& stream, long type = wxBITMAP_TYPE_ANY, int index = -1 );
-    %name(LoadMimeStream) bool LoadFile( wxInputStream& stream, const wxString& mimetype, int index = -1 );
+    %Rename(CanReadStream, static bool,  CanRead( wxInputStream& stream ));
+    %Rename(LoadStream, bool,  LoadFile( wxInputStream& stream, long type = wxBITMAP_TYPE_ANY, int index = -1 ));
+    %Rename(LoadMimeStream, bool,  LoadFile( wxInputStream& stream, const wxString& mimetype, int index = -1 ));
 
     bool Ok();
     int GetWidth();
 
     bool Ok();
     int GetWidth();
@@ -182,6 +328,14 @@ nothing.", "");
     }
 
     wxImage GetSubImage(const wxRect& rect);
     }
 
     wxImage GetSubImage(const wxRect& rect);
+
+    // Paste the image or part of this image into an image of the given size at the pos
+    //  any newly exposed areas will be filled with the rgb colour
+    //  by default if r = g = b = -1 then fill with this image's mask colour or find and 
+    //  set a suitable mask colour
+    wxImage Size( const wxSize& size, const wxPoint& pos, 
+                  int r = -1, int g = -1, int b = -1 ) const;
+    
     wxImage Copy();
     void Paste( const wxImage &image, int x, int y );
 
     wxImage Copy();
     void Paste( const wxImage &image, int x, int y );
 
@@ -189,59 +343,68 @@ nothing.", "");
     //void SetData( unsigned char *data );
 
     %extend {
     //void SetData( unsigned char *data );
 
     %extend {
-        PyObject* GetData() {
-            unsigned char* data = self->GetData();
+        DocStr(GetData,
+               "Returns a string containing a copy of the RGB bytes of the image.", "");
+        PyObject* GetData()
+        {
+            buffer data = self->GetData();
             int len = self->GetWidth() * self->GetHeight() * 3;
             PyObject* rv;
             wxPyBLOCK_THREADS( rv = PyString_FromStringAndSize((char*)data, len));
             return rv;
         }
             int len = self->GetWidth() * self->GetHeight() * 3;
             PyObject* rv;
             wxPyBLOCK_THREADS( rv = PyString_FromStringAndSize((char*)data, len));
             return rv;
         }
-        void SetData(PyObject* data) {
-            unsigned char* dataPtr;
-
-            if (! PyString_Check(data)) {
-                wxPyBLOCK_THREADS(PyErr_SetString(PyExc_TypeError,
-                                                  "Expected string object"));
-                return /* NULL */ ;
-            }
-
-            size_t len = self->GetWidth() * self->GetHeight() * 3;
-            dataPtr = (unsigned char*) malloc(len);
-            wxPyBLOCK_THREADS( memcpy(dataPtr, PyString_AsString(data), len) );
-            self->SetData(dataPtr);
-            // wxImage takes ownership of dataPtr...
+        DocStr(SetData,
+               "Resets the Image's RGB data from a buffer of RGB bytes.  Accepts
+either a string or a buffer object holding the data and the length of
+the data must be width*height*3.", "");
+        void SetData(buffer data, int DATASIZE)
+        {
+            if (DATASIZE != self->GetWidth() * self->GetHeight() * 3) {
+                wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+                return;
+            }            
+            buffer copy = (buffer)malloc(DATASIZE);
+            if (copy == NULL) {
+                wxPyBLOCK_THREADS(PyErr_NoMemory());
+                return;
+            }            
+            memcpy(copy, data, DATASIZE);
+            self->SetData(copy, false);
+            // wxImage takes ownership of copy...
         }
 
 
         }
 
 
-
-        PyObject* GetDataBuffer() {
-            unsigned char* data = self->GetData();
+        DocStr(GetDataBuffer,
+               "Returns a writable Python buffer object that is pointing at the RGB
+image data buffer inside the wx.Image.", "");
+        PyObject* GetDataBuffer()
+        {
+            buffer data = self->GetData();
             int len = self->GetWidth() * self->GetHeight() * 3;
             PyObject* rv;
             wxPyBLOCK_THREADS( rv = PyBuffer_FromReadWriteMemory(data, len) );
             return rv;
         }
             int len = self->GetWidth() * self->GetHeight() * 3;
             PyObject* rv;
             wxPyBLOCK_THREADS( rv = PyBuffer_FromReadWriteMemory(data, len) );
             return rv;
         }
-        void SetDataBuffer(PyObject* data) {
-            unsigned char* buffer;
-            int size;
 
 
-            bool blocked = wxPyBeginBlockThreads();
-            if (!PyArg_Parse(data, "t#", &buffer, &size))
-                goto done;
-
-            if (size != self->GetWidth() * self->GetHeight() * 3) {
-                PyErr_SetString(PyExc_TypeError, "Incorrect buffer size");
-                goto done;
+        DocStr(SetDataBuffer,
+               "Sets the internal image data pointer to point at a Python buffer
+object.  This can save a copy of the data but you must ensure that the
+buffer object lives longer than the wx.Image does.", "");
+        void SetDataBuffer(buffer data, int DATASIZE)
+        {
+            if (DATASIZE != self->GetWidth() * self->GetHeight() * 3) {
+                wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+                return;
             }
             }
-            self->SetData(buffer);
-        done:
-            wxPyEndBlockThreads(blocked);
+            self->SetData(data, true);
         }
 
 
 
         }
 
 
 
+        DocStr(GetAlphaData,
+               "Returns a string containing a copy of the alpha bytes of the image.", "");
         PyObject* GetAlphaData() {
         PyObject* GetAlphaData() {
-            unsigned char* data = self->GetAlpha();
+            buffer data = self->GetAlpha();
             if (! data) {
                 RETURN_NONE();
             } else {
             if (! data) {
                 RETURN_NONE();
             } else {
@@ -251,49 +414,66 @@ nothing.", "");
                 return rv;
             }
         }
                 return rv;
             }
         }
-        void SetAlphaData(PyObject* data) {
-            unsigned char* dataPtr;
 
 
-            if (! PyString_Check(data)) {
-                PyErr_SetString(PyExc_TypeError, "Expected string object");
-                return /* NULL */ ;
+        DocStr(SetAlphaData,
+               "Resets the Image's alpha data from a buffer of bytes.  Accepts either
+a string or a buffer object holding the data and the length of the
+data must be width*height.", ""); 
+        void SetAlphaData(buffer alpha, int ALPHASIZE)
+        {
+            if (ALPHASIZE != self->GetWidth() * self->GetHeight()) {
+                wxPyErr_SetString(PyExc_ValueError, "Invalid alpha buffer size.");
+                return;
             }
             }
-
-            size_t len = self->GetWidth() * self->GetHeight();
-            dataPtr = (unsigned char*) malloc(len);
-            wxPyBLOCK_THREADS( memcpy(dataPtr, PyString_AsString(data), len) );
-            self->SetAlpha(dataPtr);
-            // wxImage takes ownership of dataPtr...
+            buffer acopy = (buffer)malloc(ALPHASIZE);
+            if (acopy == NULL) {
+                wxPyBLOCK_THREADS(PyErr_NoMemory());
+                return;
+            }
+            memcpy(acopy, alpha, ALPHASIZE);
+            self->SetAlpha(acopy, false);
+            // wxImage takes ownership of acopy...
         }
 
 
         }
 
 
-
-        PyObject* GetAlphaBuffer() {
-            unsigned char* data = self->GetAlpha();
+        
+        DocStr(GetDataBuffer,
+               "Returns a writable Python buffer object that is pointing at the Alpha
+data buffer inside the wx.Image.", "");
+        PyObject* GetAlphaBuffer()
+        {
+            buffer data = self->GetAlpha();
             int len = self->GetWidth() * self->GetHeight();
             PyObject* rv;
             wxPyBLOCK_THREADS( rv = PyBuffer_FromReadWriteMemory(data, len) );
             return rv;
         }
             int len = self->GetWidth() * self->GetHeight();
             PyObject* rv;
             wxPyBLOCK_THREADS( rv = PyBuffer_FromReadWriteMemory(data, len) );
             return rv;
         }
-        void SetAlphaBuffer(PyObject* data) {
-            unsigned char* buffer;
-            int size;
-
-            bool blocked = wxPyBeginBlockThreads();
-            if (!PyArg_Parse(data, "t#", &buffer, &size))
-                goto done;
 
 
-            if (size != self->GetWidth() * self->GetHeight()) {
-                PyErr_SetString(PyExc_TypeError, "Incorrect buffer size");
-                goto done;
+        
+        DocStr(SetDataBuffer,
+               "Sets the internal image alpha pointer to point at a Python buffer
+object.  This can save a copy of the data but you must ensure that the
+buffer object lives longer than the wx.Image does.", "");
+        void SetAlphaBuffer(buffer alpha, int ALPHASIZE)
+        {
+            if (ALPHASIZE != self->GetWidth() * self->GetHeight()) {
+                wxPyErr_SetString(PyExc_ValueError, "Invalid alpha buffer size.");
+                return;
             }
             }
-            self->SetAlpha(buffer);
-        done:
-            wxPyEndBlockThreads(blocked);
+            self->SetAlpha(alpha, true);
         }
     }
 
     void SetMaskColour( unsigned char r, unsigned char g, unsigned char b );
         }
     }
 
     void SetMaskColour( unsigned char r, unsigned char g, unsigned char b );
+
+    DocDeclAStr(
+        /*bool*/ void , GetOrFindMaskColour( unsigned char *OUTPUT,
+                                             unsigned char *OUTPUT,
+                                             unsigned char *OUTPUT ) const,
+        "GetOrFindMaskColour() -> (r,g,b)",
+        "Get the current mask colour or find a suitable colour.", "");
+    
+
     unsigned char GetMaskRed();
     unsigned char GetMaskGreen();
     unsigned char GetMaskBlue();
     unsigned char GetMaskRed();
     unsigned char GetMaskGreen();
     unsigned char GetMaskBlue();
@@ -312,7 +492,7 @@ nothing.", "");
     wxImage ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const;
 
     void SetOption(const wxString& name, const wxString& value);
     wxImage ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const;
 
     void SetOption(const wxString& name, const wxString& value);
-    %name(SetOptionInt)void SetOption(const wxString& name, int value);
+    %Rename(SetOptionInt, void,  SetOption(const wxString& name, int value));
     wxString GetOption(const wxString& name) const;
     int GetOptionInt(const wxString& name) const;
     bool HasOption(const wxString& name) const;
     wxString GetOption(const wxString& name) const;
     int GetOptionInt(const wxString& name) const;
     bool HasOption(const wxString& name) const;
@@ -369,12 +549,15 @@ const wxImage    wxNullImage;
 
 //---------------------------------------------------------------------------
 
 
 //---------------------------------------------------------------------------
 
-
+MAKE_CONST_WXSTRING(IMAGE_OPTION_FILENAME);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_BMP_FORMAT);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_CUR_HOTSPOT_X);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_CUR_HOTSPOT_Y);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_RESOLUTION);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_BMP_FORMAT);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_CUR_HOTSPOT_X);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_CUR_HOTSPOT_Y);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_RESOLUTION);
+MAKE_CONST_WXSTRING(IMAGE_OPTION_RESOLUTIONX);
+MAKE_CONST_WXSTRING(IMAGE_OPTION_RESOLUTIONY);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_RESOLUTIONUNIT);
 MAKE_CONST_WXSTRING(IMAGE_OPTION_RESOLUTIONUNIT);
+MAKE_CONST_WXSTRING(IMAGE_OPTION_QUALITY);
 
 enum
 {
 
 enum
 {
@@ -383,6 +566,21 @@ enum
 };
 
 
 };
 
 
+MAKE_CONST_WXSTRING(IMAGE_OPTION_BITSPERSAMPLE);
+MAKE_CONST_WXSTRING(IMAGE_OPTION_SAMPLESPERPIXEL); 
+MAKE_CONST_WXSTRING(IMAGE_OPTION_COMPRESSION);
+MAKE_CONST_WXSTRING(IMAGE_OPTION_IMAGEDESCRIPTOR);
+
+MAKE_CONST_WXSTRING(IMAGE_OPTION_PNG_FORMAT);
+MAKE_CONST_WXSTRING(IMAGE_OPTION_PNG_BITDEPTH);
+
+enum
+{
+    wxPNG_TYPE_COLOUR = 0,
+    wxPNG_TYPE_GREY = 2,
+    wxPNG_TYPE_GREY_RED = 3
+};
+
 enum
 {
     wxBMP_24BPP        = 24, // default, do not need to set
 enum
 {
     wxBMP_24BPP        = 24, // default, do not need to set