Index: FL/Fl_Bitmap.H
===================================================================
--- FL/Fl_Bitmap.H	(revision 10586)
+++ FL/Fl_Bitmap.H	(working copy)
@@ -69,6 +69,10 @@
   virtual void label(Fl_Widget*w);
   virtual void label(Fl_Menu_Item*m);
   virtual void uncache();
+
+  //Used only by device classes
+  static void destroy_data(Fl_Bitmap * b);
+
 };
 
 #endif
Index: FL/Fl_Device.H
===================================================================
--- FL/Fl_Device.H	(revision 10586)
+++ FL/Fl_Device.H	(working copy)
@@ -483,6 +483,7 @@
   const char *class_name() {return class_id;};
   void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
   void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy);
+  void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy);
 };
 #endif
 #if !(defined(__APPLE__) || defined(WIN32))
Index: FL/fl_draw.H
===================================================================
--- FL/fl_draw.H	(revision 10586)
+++ FL/fl_draw.H	(working copy)
@@ -32,6 +32,8 @@
 // Image class...
 class Fl_Image;
 
+class Fl_Shared_Image;
+
 // Label flags...
 FL_EXPORT extern char fl_draw_shortcut;
 
@@ -764,6 +766,25 @@
 FL_EXPORT int fl_measure_pixmap(/*const*/ char* const* data, int &w, int &h);
 FL_EXPORT int fl_measure_pixmap(const char* const* cdata, int &w, int &h);
 
+/**
+  Scalable drawing of shared image.
+  The function draws image in full stretched to given rectangle with maximum resolution
+  provided by the original  -if you want to draw part of the image, use clipping.
+  If \a w and \a h are zero, it draws image with sizes img->w() and img->h(). If either w
+  or h is 0, it takes the other parameter to define size, keeping aspect ratio of the original.
+  The function also obeys thansformation matrix for additional scalling.
+  Note that subsequent drawings upon the same image should not change w and h too often because
+  such a change might require resamping of the original. If you want to use the same image with
+  different scalings (or different transformation matrix) in number of places (like different
+  widgets, different parts of the document), it is better to create copies (copy is cheap now)
+  and use its own copy at each such place.
+  The call does not change img->w() or img->h(), however internal rescalled image might differ
+  in its dimensions (see  also Fl_Shared_Image::data_w(), Fl_Shared_Image::data_h()
+  Fl_Shared_Image::original_w(), Fl_Shared_Image::original_h()).
+
+*/
+FL_EXPORT void fl_draw(Fl_Shared_Image *im, int x, int y, int w = 0, int h = 0);
+
 // other:
 FL_EXPORT void fl_scroll(int X, int Y, int W, int H, int dx, int dy,
                          void (*draw_area)(void*, int,int,int,int), void* data);
Index: FL/Fl_Image.H
===================================================================
--- FL/Fl_Image.H	(revision 10586)
+++ FL/Fl_Image.H	(working copy)
@@ -167,6 +167,27 @@
 
   // get RGB image scaling method
   static Fl_RGB_Scaling RGB_scaling();
+
+  // Following functions apply only to implementation of drawing device classes and
+  // normal users di not need to care about
+
+  // If a device wants to draw "full" resolution, it can request full-resolution image using
+  // this method. This might return 0 but if it does not it is assured that returned image is
+  // of the same class as class as image passed to the drawing function so it can safely typecast
+  // and request its data (which for original are always available)
+  // - see Fl_Postscript_Graphics_Driver for an example.
+  static Fl_Image * original();
+
+  // This function applies to display devices. They usually draw from cache and once cache is build
+  // they dont need data any more. To save space they can delete data once the cache is build
+  // using one of the static functions
+  //    Fl_RGB_Image::destroy_data(Fl_RGB_Image *);
+  //    Fl_Bitmap::destroy_data(Fl_Bitmap *);
+  //    Fl_Bitmap::destroy_data(Fl_Bitmap *);
+  // must ask this function for permission to do that.
+
+
+
 };
 
 /**
@@ -245,6 +266,11 @@
    \sa  void Fl_RGB_Image::max_size(size_t)
    */
   static size_t max_size() {return max_size_;}
+
+  /// If particular does not need data for drawing it can call destroy_data(). Note that this does nothing if
+  /// Fl_Shared_Image::assure_data_mode() was switched on (default) or if for particular shared image
+  /// assure_data() was called.
+  static void destroy_data(Fl_RGB_Image * im);
 };
 
 #endif // !Fl_Image_H
Index: FL/Fl_Pixmap.H
===================================================================
--- FL/Fl_Pixmap.H	(revision 10586)
+++ FL/Fl_Pixmap.H	(working copy)
@@ -93,6 +93,9 @@
   virtual void label(Fl_Widget*w);
   virtual void label(Fl_Menu_Item*m);
   virtual void uncache();
+
+  // used only by devices
+  static void destroy_data(Fl_Pixmap * p);
 };
 
 #endif
Index: FL/Fl_PostScript.H
===================================================================
--- FL/Fl_PostScript.H	(revision 10586)
+++ FL/Fl_PostScript.H	(working copy)
@@ -63,6 +63,7 @@
   static const char *class_id;
   const char *class_name() {return class_id;};
   Fl_PostScript_Graphics_Driver();
+  Fl_PostScript_Graphics_Driver(int level);
 #ifndef FL_DOXYGEN
   enum SHAPE{NONE=0, LINE, LOOP, POLYGON, POINTS};
   
@@ -222,6 +223,7 @@
   static const char *class_id;
   const char *class_name() {return class_id;};
   Fl_PostScript_File_Device();
+  Fl_PostScript_File_Device(int level);
   ~Fl_PostScript_File_Device();
   int start_job(int pagecount, int* from, int* to);
   int start_job(int pagecount, enum Fl_Paged_Device::Page_Format format = Fl_Paged_Device::A4,
Index: src/Fl_Bitmap.cxx
===================================================================
--- src/Fl_Bitmap.cxx	(revision 10586)
+++ src/Fl_Bitmap.cxx	(working copy)
@@ -246,7 +246,7 @@
 int Fl_Bitmap::start(int XP, int YP, int WP, int HP, int &cx, int &cy, 
 		 int &X, int &Y, int &W, int &H)
 {
-  if (!array) {
+  if (!array && !id_) {
     draw_empty(XP, YP);
     return 1;
   }
@@ -283,6 +283,7 @@
 }
 
 #elif defined(WIN32)
+static int can_destroy_data = 1;
 void Fl_GDI_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
   int X, Y, W, H;
   if (bm->start(XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
@@ -297,6 +298,8 @@
   BitBlt(fl_gc, X, Y, W, H, tempdc, cx, cy, 0xE20746L);
   RestoreDC(tempdc, save);
   DeleteDC(tempdc);
+  if(can_destroy_data)
+    Fl_Bitmap::destroy_data(bm);
 }  
 
 void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
@@ -308,11 +311,37 @@
     hMod = LoadLibrary("MSIMG32.DLL");
     if (hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt");
   }
+  Fl_Bitmap * original = (Fl_Bitmap *)Fl_Image::original();
+  XFORM old_tr;
+  if(original){
+    float sw = float(bm->w())/float(original->w());
+    float sh = float(bm->h())/float(original->h());
+    GetWorldTransform(fl_gc, &old_tr); // storing old transform
+    XFORM tr;
+    tr.eM11 = (FLOAT)sw;
+    tr.eM22 = (FLOAT)sh;
+    tr.eM12 = tr.eM21 = 0;
+    tr.eDx =  (FLOAT) XP;
+    tr.eDy =  (FLOAT) YP;
+    XP = 0;
+    YP = 0;
+    ModifyWorldTransform(fl_gc, &tr, MWT_LEFTMULTIPLY);
+    WP = int(float(WP)/sw);
+    HP = int(float(HP)/sh);
+    cx = (int) (float(cx)/sw);
+    cy = (int) (float(cy)/sh);
+    bm = original;
+  }
+
   if (!fl_TransparentBlt) {
+    can_destroy_data = 0; // never destroy data of original
     Fl_GDI_Graphics_Driver::draw(bm,  XP,  YP,  WP,  HP,  cx,  cy);
+    if(original) SetWorldTransform(fl_gc, &old_tr);
+    can_destroy_data = 1;
     return;
     }
   if (bm->start(XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
+    if(original) SetWorldTransform(fl_gc, &old_tr);
     return;
   }
   
@@ -343,6 +372,7 @@
   fl_delete_offscreen(tmp_id);
   RestoreDC(tempdc, save);
   DeleteDC(tempdc);
+  if(original) SetWorldTransform(fl_gc, &old_tr);
 }  
 
 #else // Xlib
@@ -359,6 +389,7 @@
   XSetFillStyle(fl_display, fl_gc, FillStippled);
   XFillRectangle(fl_display, fl_window, fl_gc, X, Y, W, H);
   XSetFillStyle(fl_display, fl_gc, FillSolid);
+  Fl_Bitmap::destroy_data(bm);
 }
 #endif
 
Index: src/Fl_Image.cxx
===================================================================
--- src/Fl_Image.cxx	(revision 10586)
+++ src/Fl_Image.cxx	(working copy)
@@ -613,10 +613,11 @@
 }
 
 #elif defined(WIN32)
+static int is_gdi_printer = 0;
 void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) {
   int X, Y, W, H;
   // Don't draw an empty image...
-  if (!img->d() || !img->array) {
+  if (!img->d() &&  !img->id_) {
     img->draw_empty(XP, YP);
     return;
   }
@@ -652,8 +653,50 @@
   } else {
     copy_offscreen(X, Y, W, H, (Fl_Offscreen)img->id_, cx, cy);
   }
+  // Following does nothing if either:
+  // - it is not called from Fl_Registered_Image/Fl_Shared_Image
+  // - assure_data_mode() was ON during creation
+  // - assure_data() was called upon corresponding Fl_Shared_Image
+  if(!is_gdi_printer)
+    Fl_RGB_Image::destroy_data(img);
 }
 
+
+void Fl_GDI_Printer_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy){
+
+    Fl_RGB_Image * original = (Fl_RGB_Image *)Fl_Image::original();
+    XFORM old_tr;
+    if(original){
+       float sw = float(img->w())/float(original->w());
+       float sh = float(img->h())/float(original->h());
+       GetWorldTransform(fl_gc, &old_tr); // storing old transform
+       XFORM tr;
+       tr.eM11 = (FLOAT)sw;
+       tr.eM22 = (FLOAT)sh;
+       tr.eM12 = tr.eM21 = 0;
+       tr.eDx =  (FLOAT) XP;
+       tr.eDy =  (FLOAT) YP;
+       XP = 0;
+       YP = 0;
+       ModifyWorldTransform(fl_gc, &tr, MWT_LEFTMULTIPLY);
+       WP = int(float(WP)/sw);
+       HP = int(float(HP)/sh);
+       cx = (int) (float(cx)/sw);
+       cy = (int) (float(cy)/sh);
+       img = original;
+    }
+    is_gdi_printer = 1; // tell above function not to destroy data although this is little bit paranoya...
+    // We probably cant draw from display-compatible (printer-incompatible) cache;
+    // creating temporary image (without copying data) with clean cache...
+    Fl_RGB_Image xxx((const unsigned char *)(*(img->data())), img->w(), img->h(), img->d(), img->ld());
+    img = &xxx;
+    Fl_GDI_Graphics_Driver::draw(img, XP, YP, WP, HP, cx, cy);
+
+    is_gdi_printer = 0;
+    if(original)
+       SetWorldTransform(fl_gc, &old_tr); // setting back original transformation
+}
+
 #else
 void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) {
   int X, Y, W, H;
@@ -711,6 +754,7 @@
   m->label(_FL_IMAGE_LABEL, (const char*)this);
 }
 
+
 //
 // End of "$Id$".
 //
Index: src/Fl_Pixmap.cxx
===================================================================
--- src/Fl_Pixmap.cxx	(revision 10586)
+++ src/Fl_Pixmap.cxx	(working copy)
@@ -66,10 +66,10 @@
 }
 
 static int start(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy,
-		 int &X, int &Y, int &W, int &H)
+		 int &X, int &Y, int &W, int &H, void * id)
 {
   // ignore empty or bad pixmap data:
-  if (!pxm->data()) {
+  if (!pxm->data() && !id) {
     return 2;
   }
   if (WP == -1) {
@@ -95,7 +95,7 @@
 int Fl_Pixmap::prepare(int XP, int YP, int WP, int HP, int &cx, int &cy,
 			   int &X, int &Y, int &W, int &H) {
   if (w() < 0) measure();
-  int code = start(this, XP, YP, WP, HP, w(), h(), cx, cy, X, Y, W, H);
+  int code = start(this, XP, YP, WP, HP, w(), h(), cx, cy, X, Y, W, H, id_);
   if (code) {
     if (code == 2) draw_empty(XP, YP);
     return 1;
@@ -151,6 +151,7 @@
   } else {
     copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
   }
+  Fl_Pixmap::destroy_data(pxm);
 }
 
 #if FLTK_ABI_VERSION < 10301
@@ -159,6 +160,31 @@
 
 void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
   int X, Y, W, H;
+  Fl_Pixmap * original = (Fl_Pixmap *) Fl_Image::original();
+  XFORM old_tr;
+  if(original){
+    float sw = float(pxm->w())/float(original->w());
+    float sh = float(pxm->h())/float(original->h());
+    GetWorldTransform(fl_gc, &old_tr); // storing old transform
+    XFORM tr;
+    tr.eM11 = (FLOAT)sw;
+    tr.eM22 = (FLOAT)sh;
+    tr.eM12 = tr.eM21 = 0;
+    tr.eDx =  (FLOAT) XP;
+    tr.eDy =  (FLOAT) YP;
+    XP = 0;
+    YP = 0;
+    ModifyWorldTransform(fl_gc, &tr, MWT_LEFTMULTIPLY);
+    WP = int(float(WP)/sw);
+    HP = int(float(HP)/sh);
+    cx = (int) (float(cx)/sw);
+    cy = (int) (float(cy)/sh);
+    pxm = original;
+    int delete_cache = (pxm->id_)? 0 : 1; // save data if this is only data original, probably never drawn
+  }
+
+  Fl_Pixmap xxx(pxm->data());
+  pxm = &xxx;
   if (pxm->prepare(XP, YP, WP, HP, cx, cy, X, Y, W, H)) return;
   typedef BOOL (WINAPI* fl_transp_func)  (HDC,int,int,int,int,HDC,int,int,int,int,UINT);
   static HMODULE hMod = NULL;
@@ -179,6 +205,9 @@
   else {
     copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
   }
+  if(original)
+       SetWorldTransform(fl_gc, &old_tr);
+
 }
 
 #else // Xlib
@@ -203,6 +232,7 @@
     XSetClipOrigin(fl_display, fl_gc, 0, 0);
     fl_restore_clip();
   }
+  Fl_Pixmap::destroy_data(pxm);
 }
 
 #endif
Index: src/Fl_PostScript.cxx
===================================================================
--- src/Fl_PostScript.cxx	(revision 10586)
+++ src/Fl_PostScript.cxx	(working copy)
@@ -39,6 +39,8 @@
 
 /**
  @brief The constructor.
+ *
+ Default language level is 2
  */
 Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
 {
@@ -51,6 +53,23 @@
   bg_r = bg_g = bg_b = 255;
 }
 
+/**
+ @brief The constructor.
+ *
+ Default language level is 2
+ */
+Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(int level)
+{
+  close_cmd_ = 0;
+  //lang_level_ = 3;
+  lang_level_ = level;
+  mask = 0;
+  ps_filename_ = NULL;
+  scale_x = scale_y = 1.;
+  bg_r = bg_g = bg_b = 255;
+}
+
+
 /** \brief The destructor. */
 Fl_PostScript_Graphics_Driver::~Fl_PostScript_Graphics_Driver() {
   if(ps_filename_) free(ps_filename_);
@@ -58,6 +77,8 @@
 
 /**
  @brief The constructor.
+ *
+ Default PostScript language level is 2.
  */
 Fl_PostScript_File_Device::Fl_PostScript_File_Device(void)
 {
@@ -67,6 +88,14 @@
   Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver() );
 }
 
+Fl_PostScript_File_Device::Fl_PostScript_File_Device(int level)
+{
+#ifdef __APPLE__
+  gc = fl_gc; // the display context is used by fl_text_extents()
+#endif
+  Fl_Surface_Device::driver( new Fl_PostScript_Graphics_Driver(level) );
+}
+
 /**
  \brief Returns the PostScript driver of this drawing surface.
  */
Index: src/ps_image.cxx
===================================================================
--- src/ps_image.cxx	(revision 10586)
+++ src/ps_image.cxx	(working copy)
@@ -427,14 +427,29 @@
 
 
 void Fl_PostScript_Graphics_Driver::draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy){
+  Fl_Pixmap * original = (Fl_Pixmap *)(Fl_Image::original());
+  float scale_w = 1;
+  float scale_h = 1;
+
+  if(original){
+     scale_w = float(pxm->w())/float(original->w());
+     scale_h = float(pxm->h())/float(original->h());
+     pxm = original;
+  }
+
   const char * const * di =pxm->data();
   int w,h;
   if (!fl_measure_pixmap(di, w, h)) return;
   mask=0;
   fl_mask_bitmap=&mask;
-  mx = WP;
-  my = HP;
+  mx = pxm->w();
+  my = pxm->h();
   push_clip(XP, YP, WP, HP);
+    if(original){
+     clocale_printf("GS %d %d TR  %f %f SC\n", XP - cx, YP - cy, scale_w, scale_h);
+     fl_draw_pixmap(di, 0, 0, FL_BLACK );
+     fprintf(output,"\nGR\n");
+  }else
   fl_draw_pixmap(di,XP -cx, YP -cy, FL_BLACK );
   pop_clip();
   delete[] mask;
@@ -443,6 +458,17 @@
 }
 
 void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy){
+  Fl_RGB_Image * original = (Fl_RGB_Image *)(Fl_Image::original());
+  float scale_w = 1;
+  float scale_h = 1;
+  original = 0;
+
+  if(original){
+     scale_w = float(rgb->w())/float(original->w());
+     scale_h = float(rgb->h())/float(original->h());
+     rgb = original;
+  }
+
   const uchar  * di = rgb->array;
   int w = rgb->w();
   int h = rgb->h();
@@ -450,13 +476,41 @@
   if (lang_level_>2) //when not true, not making alphamask, mixing colors instead...
   if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting!
   push_clip(XP, YP, WP, HP);
-  draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld());
+
+  if(original){
+     clocale_printf("GS %d %d TR %f %f SC\n", XP - cx, YP - cy, scale_w, scale_h);
+     draw_image(di, 0, 0, w, h, rgb->d(), rgb->ld());
+     fprintf(output,"\nGR\n");
+  }else
+
+     draw_image(di, XP - cx, YP - cy, w, h, rgb->d(), rgb->ld());
   pop_clip();
   delete[]mask;
   mask=0;
 }
 
 void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy){
+  Fl_Bitmap * original = (Fl_Bitmap *)(Fl_Image::original());
+  float scale_w = 1;
+  float scale_h = 1;
+  int clip_x = XP;
+  int clip_y = YP;
+  int clip_w = WP;
+  int clip_h = HP;
+  int shift_x = 0;
+  int shift_y = 0;
+  if(original){
+     scale_w = float(bitmap->w())/float(original->w());
+     scale_h = float(bitmap->h())/float(original->h());
+     bitmap = original;
+     // For precision we draw all bits but translatted and clipped depending on WP, HP, cx, cy
+     shift_x = cx;
+     shift_y = cy;
+     cx = 0;
+     cy = 0;
+     WP = original->w();
+     HP = original->h();
+  }
   const uchar  * di = bitmap->array;
   int w,h;
   int LD=(bitmap->w()+7)/8;
@@ -478,7 +532,11 @@
   int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask
 
   int i,j;
-  push_clip(XP, YP, WP, HP);
+  push_clip(clip_x, clip_y, clip_w, clip_h);
+  if(original){
+    clocale_printf("GS %d %d TR %f %f SC\n", XP - cx, YP - cy, scale_w, scale_h);
+    XP = 0; YP = 0;
+  }
   fprintf(output , "%i %i %i %i %i %i MI", XP - si, YP + HP , WP , -HP , w , h);
 
   for (j=0; j<HP; j++){
@@ -490,6 +548,8 @@
     fprintf(output,"\n");
   }
   fprintf(output,">\n");
+  if(original)
+    fprintf(output,"\nGR\n");
   pop_clip();
 }
 
