+// SavePCX:
+//  Saves a PCX file into the wxImage object pointed by image.
+//  Returns wxPCX_OK on success, or an error code otherwise
+//  (see above for error codes). Will try to save as 8-bit
+//  PCX if possible, and then fall back to 24-bit if there
+//  are more than 256 different colours.
+//
+int SavePCX(wxImage *image, wxOutputStream& stream)
+{
+    unsigned char hdr[128];         // PCX header
+    unsigned char pal[768];         // palette for 8 bit images
+    unsigned char *p;               // space to store one scanline
+    unsigned char *src;             // pointer into wxImage data
+    unsigned int width, height;     // size of the image
+    unsigned int bytesperline;      // bytes per line (each plane)
+    unsigned char nplanes = 3;      // number of planes
+    int format = wxPCX_24BIT;       // image format (8 bit, 24 bit)
+    wxImageHistogram histogram;     // image histogram
+    unsigned long key;              // key in the hashtable
+    unsigned int i;
+
+    // See if we can save as 8 bit.
+
+    if (image->CountColours(256) <= 256)
+    {
+        image->ComputeHistogram(histogram);
+        format = wxPCX_8BIT;
+        nplanes = 1;
+    }
+
+    // Get image dimensions, calculate bytesperline (must be even,
+    // according to PCX specs) and allocate space for one complete
+    // scanline.
+
+    if (!image->Ok())
+        return wxPCX_INVFORMAT;
+
+    width = image->GetWidth();
+    height = image->GetHeight();
+    bytesperline = width;
+    if (bytesperline % 2)
+        bytesperline++;
+
+    if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL)
+        return wxPCX_MEMERR;
+
+    // Build header data and write it to the stream. Initially,
+    // set all bytes to zero (most values default to zero).
+
+    memset(hdr, 0, sizeof(hdr));
+
+    hdr[HDR_MANUFACTURER]     = 10;
+    hdr[HDR_VERSION]          = 5;
+    hdr[HDR_ENCODING]         = 1;
+    hdr[HDR_NPLANES]          = nplanes;
+    hdr[HDR_BITSPERPIXEL]     = 8;
+    hdr[HDR_BYTESPERLINE]     = (unsigned char)(bytesperline % 256);
+    hdr[HDR_BYTESPERLINE + 1] = (unsigned char)(bytesperline / 256);
+    hdr[HDR_XMAX]             = (unsigned char)((width - 1)  % 256);
+    hdr[HDR_XMAX + 1]         = (unsigned char)((width - 1)  / 256);
+    hdr[HDR_YMAX]             = (unsigned char)((height - 1) % 256);
+    hdr[HDR_YMAX + 1]         = (unsigned char)((height - 1) / 256);
+    hdr[HDR_PALETTEINFO]      = 1;
+
+    stream.Write(hdr, 128);
+
+    // Encode image data line by line and write it to the stream
+
+    src = image->GetData();
+
+    for (; height; height--)
+    {
+        switch (format)
+        {
+            case wxPCX_8BIT:
+            {
+                unsigned char r, g, b;
+
+                for (i = 0; i < width; i++)
+                {
+                    r = *(src++);
+                    g = *(src++);
+                    b = *(src++);
+                    key = (r << 16) | (g << 8) | b;
+
+                    p[i] = (unsigned char)histogram[key].index;
+                }
+                break;
+            }
+            case wxPCX_24BIT:
+            {
+                for (i = 0; i < width; i++)
+                {
+                    p[i] = *(src++);
+                    p[i + bytesperline] = *(src++);
+                    p[i + 2 * bytesperline] = *(src++);
+                }
+                break;
+            }
+        }
+
+        RLEencode(p, bytesperline * nplanes, stream);
+    }
+
+    free(p);
+
+    // For 8 bit images, build the palette and write it to the stream:
+    if (format == wxPCX_8BIT)
+    {
+        // zero unused colours
+        memset(pal, 0, sizeof(pal));
+
+        unsigned long index;
+
+        for (wxImageHistogram::iterator entry = histogram.begin();
+             entry != histogram.end(); ++entry )
+        {
+            key = entry->first;
+            index = entry->second.index;
+            pal[3 * index]     = (unsigned char)(key >> 16);
+            pal[3 * index + 1] = (unsigned char)(key >> 8);
+            pal[3 * index + 2] = (unsigned char)(key);
+        }
+
+        stream.PutC(12);
+        stream.Write(pal, 768);
+    }
+
+    return wxPCX_OK;
+}