Add ability to directly convert between two pixel formats

This is a lot easier and cheaper than having to set up a complete
PixelTransformer object.
diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx
index 366c0a3..53b7ea5 100644
--- a/common/rfb/PixelFormat.cxx
+++ b/common/rfb/PixelFormat.cxx
@@ -343,6 +343,56 @@
 }
 
 
+Pixel PixelFormat::pixelFromPixel(const PixelFormat &srcPF, Pixel src) const
+{
+  rdr::U16 r, g, b;
+  srcPF.rgbFromPixel(src, &r, &g, &b);
+  return pixelFromRGB(r, g, b);
+}
+
+
+void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
+                                   const rdr::U8* src, int pixels) const
+{
+  bufferFromBuffer(dst, srcPF, src, pixels, 1, pixels, pixels);
+}
+
+void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
+                                   const rdr::U8* src, int w, int h,
+                                   int dstStride, int srcStride) const
+{
+  if (equal(srcPF)) {
+    // Trivial case
+    while (h--) {
+      memcpy(dst, src, w * bpp/8);
+      dst += dstStride * bpp/8;
+      src += srcStride * srcPF.bpp/8;
+    }
+  } else {
+    // Generic code
+    int dstPad = (dstStride - w) * bpp/8;
+    int srcPad = (srcStride - w) * srcPF.bpp/8;
+    while (h--) {
+      int w_ = w;
+      while (w_--) {
+        Pixel p;
+        rdr::U8 r, g, b;
+
+        p = srcPF.pixelFromBuffer(src);
+        srcPF.rgbFromPixel(p, &r, &g, &b);
+        p = pixelFromRGB(r, g, b);
+        bufferFromPixel(dst, p);
+
+        dst += bpp/8;
+        src += srcPF.bpp/8;
+      }
+      dst += dstPad;
+      src += srcPad;
+    }
+  }
+}
+
+
 void PixelFormat::print(char* str, int len) const
 {
   // Unfortunately snprintf is not widely available so we build the string up
diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h
index db12988..b18045f 100644
--- a/common/rfb/PixelFormat.h
+++ b/common/rfb/PixelFormat.h
@@ -75,6 +75,14 @@
     void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src,
                        int w, int stride, int h) const;
 
+    Pixel pixelFromPixel(const PixelFormat &srcPF, Pixel src) const;
+
+    void bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
+                          const rdr::U8* src, int pixels) const;
+    void bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
+                          const rdr::U8* src, int w, int h,
+                          int dstStride, int srcStride) const;
+
     void print(char* str, int len) const;
     bool parse(const char* str);
 
diff --git a/tests/pixelconv.cxx b/tests/pixelconv.cxx
index 92011d3..a30ed90 100644
--- a/tests/pixelconv.cxx
+++ b/tests/pixelconv.cxx
@@ -42,6 +42,12 @@
                     dst, fbsize, rfb::Point(0, 0));
 }
 
+static void testBuffer(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf,
+                       rdr::U8 *dst, rdr::U8 *src)
+{
+  dstpf.bufferFromBuffer(dst, srcpf, src, tile, tile, fbsize, fbsize);
+}
+
 static void testToRGB(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf,
                       rdr::U8 *dst, rdr::U8 *src)
 {
@@ -86,6 +92,7 @@
 struct TestEntry tests[] = {
   {"memcpy", testMemcpy},
   {"PixelTransformer", testPixelTransformer},
+  {"bufferFromBuffer", testBuffer},
   {"rgbFromBuffer", testToRGB},
   {"bufferFromRGB", testFromRGB},
 };