[haiku-commits] r39733 - haiku/trunk/src/add-ons/print/drivers/gutenprint

  • From: michael.w.pfeiffer@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 5 Dec 2010 12:13:07 +0100 (CET)

Author: laplace
Date: 2010-12-05 12:13:07 +0100 (Sun, 05 Dec 2010)
New Revision: 39733
Changeset: http://dev.haiku-os.org/changeset/39733

Added:
   haiku/trunk/src/add-ons/print/drivers/gutenprint/Rectangle.h
Modified:
   haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.cpp
   haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.h
Log:
* The bitmap bands from libprint are relative to the
  imageable area; made them absolute to the left, top
  of the page. The page contents should now be positioned
  correctly.
* Make sure the image to be printed on the page is
  inside the imageable area. This fixes the configuration
  error that the page is outside the imageable area.
TODO fix the implementation limitation that up to 1 Inch of the
total imageable page width and height cannot be used. There
is a comment in the source code that explains why that is.


Modified: haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.cpp
===================================================================
--- haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.cpp  2010-12-05 
00:48:56 UTC (rev 39732)
+++ haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.cpp  2010-12-05 
11:13:07 UTC (rev 39733)
@@ -10,6 +10,67 @@
 #include <Debug.h>
 
 
+// 72 DPI
+static const int32 kGutenprintUnit = 72;
+
+class CoordinateSystem
+{
+public:
+       CoordinateSystem()
+       :
+       fXDPI(0),
+       fYDPI(0)
+       {
+       }
+
+
+       void SetDPI(int32 x, int32 y) {
+               fXDPI = x;
+               fYDPI = y;
+       }
+
+
+       void ToGutenprint(int32 fromX, int32 fromY, int32& toX, int32& toY) {
+               toX = fromX * kGutenprintUnit / fXDPI;
+               toY = fromY * kGutenprintUnit / fYDPI;
+       }
+
+
+       void ToGutenprintCeiling(int32 fromX, int32 fromY, int32& toX, int32& 
toY) {
+               toX = (fromX * kGutenprintUnit + fXDPI - 1) / fXDPI;
+               toY = (fromY * kGutenprintUnit + fYDPI - 1) / fYDPI;
+       }
+
+
+       void FromGutenprint(int32 fromX, int32 fromY, int32& toX, int32& toY) {
+               toX = fromX * fXDPI / kGutenprintUnit;
+               toY = fromY * fYDPI / kGutenprintUnit;
+       }
+
+       void FromGutenprintCeiling(int32 fromX, int32 fromY, int32& toX, int32& 
toY) {
+               toX = (fromX * fXDPI + kGutenprintUnit - 1) / kGutenprintUnit;
+               toY = (fromY * fYDPI + kGutenprintUnit - 1) / kGutenprintUnit;
+       }
+
+       void SizeFromGutenprint(int32 fromWidth, int32 fromHeight,
+               int32& toWidth, int32& toHeight) {
+               toWidth = fromWidth * fXDPI / kGutenprintUnit;
+               toHeight = fromHeight * fYDPI / kGutenprintUnit;
+       }
+
+       void RoundUpToWholeInches(int32& width, int32& height) {
+               width = ((width + kGutenprintUnit - 1) / kGutenprintUnit)
+                       * kGutenprintUnit;
+               height = ((height + kGutenprintUnit - 1) / kGutenprintUnit)
+                       * kGutenprintUnit;
+       }
+
+private:
+       int32 fXDPI;
+       int32 fYDPI;
+};
+
+
 GPJob::GPJob()
        :
        fApplicationName(),
@@ -169,130 +230,150 @@
        fVariables = NULL;
 }
 
-
-static int
-gcd(int a, int b)
-{
-       // Euclidean algorithm for greatest common divisor
-       while (b != 0) {
-               int t = b;
-               b = a % b;
-               a = t;
-       }
-       return a;
-}
-
-
-static int
-to72dpiFloor(int value, int fromUnit) {
-       // proper rounding is important in this formula
-       // do not "optimize"
-       const int toUnit = 72;
-       int g = gcd(toUnit, fromUnit);
-       int n = toUnit / g;
-       int m = fromUnit / g;
-       return (value / m) * n;
-}
-
-
-static int
-to72dpiCeiling(int value, int fromUnit) {
-       // proper rounding is important in this formula
-       // do not "optimize"
-       const int toUnit = 72;
-       int g = gcd(toUnit, fromUnit);
-       int n = toUnit / g;
-       int m = fromUnit / g;
-       return ((value + m - 1) / m) * n;
-}
-
-
-static int
-from72dpi(int value, int toUnit)
-{
-       const int fromUnit = 72;
-       return value * toUnit / fromUnit;
-}
-
-
 status_t
 GPJob::PrintPage(list<GPBand*>& bands) {
        if (fStatus != B_OK)
                return fStatus;
 
-       fPrintRect = GetPrintRectangle(bands);
        fBands = &bands;
        fCachedBand = NULL;
 
+       Rectangle<int> imageableArea;
+       stp_get_imageable_area(fVariables, &imageableArea.left,
+               &imageableArea.right, &imageableArea.bottom, 
&imageableArea.top);
+       fprintf(stderr, "GPJob imageable area left %d, top %d, right %d, "
+               "bottom %d\n",
+               imageableArea.left, imageableArea.top, imageableArea.right,
+               imageableArea.bottom);
+       fprintf(stderr, "GPJob width %d %s, height %d %s\n",
+               imageableArea.Width(),
+               imageableArea.Width() % 72 == 0 ? "whole inches" : "not whole 
inches",
+               imageableArea.Height(),
+               imageableArea.Height() % 72 == 0 ? "whole inches" : "not whole 
inches"
+               );
+
+       CoordinateSystem coordinateSystem;
+       coordinateSystem.SetDPI(fConfiguration->fXDPI, fConfiguration->fYDPI);
        {
-               int left;
-               int top;
-               int right;
-               int bottom;
-               stp_get_imageable_area(fVariables, &left, &right, &bottom, 
&top);
-               fprintf(stderr, "GPJob imageable area left %d, top %d, right 
%d, "
-                       "bottom %d\n",
-                       left, top, right, bottom);
+               // GPBand offset is relative to imageable area left, top
+               // but it has to be absolute to left, top of page
+               int32 offsetX;
+               int32 offsetY;
+               coordinateSystem.FromGutenprintCeiling(imageableArea.left,
+                       imageableArea.top, offsetX, offsetY);
 
+               BPoint offset(offsetX, offsetY);
+               list<GPBand*>::iterator it = fBands->begin();
+               for (; it != fBands->end(); it++) {
+                       (*it)->fWhere += offset;
+               }
        }
 
+       fPrintRect = GetPrintRectangle(bands);
+
        {
                int left = (int)fPrintRect.left;
                int top = (int)fPrintRect.top;
-               int width = fPrintRect.IntegerWidth() + 1;
-               int height = fPrintRect.IntegerHeight() + 1;
+               int width = fPrintRect.Width() + 1;
+               int height = fPrintRect.Height() + 1;
 
-               fprintf(stderr, "GPJob raw image dimensions left %d, top %d, 
width %d, height %d\n",
+               fprintf(stderr, "GPJob bitmap bands frame left %d, top %d, 
width %d, "
+                       "height %d\n",
                        left, top, width, height);
        }
 
-       int xDPI = fConfiguration->fXDPI;
-       int yDPI = fConfiguration->fYDPI;
+       // calculate the position and size of the image to be printed on the 
page
+       // unit: 1/72 Inches
+       // constraints: the image must be inside the imageable area
+       int32 left;
+       int32 top;
+       coordinateSystem.ToGutenprint(fPrintRect.left, fPrintRect.top, left, 
top);
+       if (left < imageableArea.left)
+               left = imageableArea.left;
+       if (top < imageableArea.top)
+               top = imageableArea.top;
 
-       // left, top of the image on the page in 1/72 Inches
-       int left = static_cast<int>(fPrintRect.left);
-       left = to72dpiFloor(left, xDPI);
-       int top = static_cast<int>(fPrintRect.top);
-       top = to72dpiFloor(top, yDPI);
+       int32 right;
+       int32 bottom;
+       coordinateSystem.ToGutenprintCeiling(fPrintRect.right, 
fPrintRect.bottom,
+               right, bottom);
+       if (right > imageableArea.right)
+               right = imageableArea.right;
+       if (bottom > imageableArea.bottom)
+               bottom = imageableArea.bottom;
 
-       // because of rounding in the previous step,
-       // now the image left, top has to be synchronized
-       fPrintRect.left = from72dpi(left, xDPI);
-       fPrintRect.top = from72dpi(top, yDPI);
+       fprintf(stderr, "GPJob image left %d, top %d, right %d, bottom %d\n",
+               (int)left, (int)top, (int)right, (int)bottom);
 
-       // width and height of the image on the page in 1/72 Inches
-       int width = fPrintRect.IntegerWidth() + 1;
-       width = to72dpiCeiling(width, xDPI);
-       int height = fPrintRect.IntegerHeight() + 1;
-       height = to72dpiCeiling(height, yDPI);
+       // make sure the width and height in pixels is a whole number
+       // by increasing the width and height in 1/72 Inches to a multiple of 72
+       //
+       // TODO the "whole number" condition has to be dropped; in the current
+       // implementation up to 1 Inch of the total width or height cannot be
+       // used; using the gcd of 72 and x or y DPI this could be reduced;
+       // for example if DPI is 600 to 1/3 Inch which is still not acceptable.
+       //
+       // the position might have to be changed in order to stay inside
+       // the imageable area; if it gets too large it is decreased by one Inch
+       int32 width = right - left;
+       int32 height = bottom - top;
+       coordinateSystem.RoundUpToWholeInches(width, height);
+       right = left + width;
+       bottom = top + height;
 
-       // synchronize image right and bottom too
-       fPrintRect.right = fPrintRect.left + from72dpi(width, xDPI);
-       fPrintRect.bottom = fPrintRect.top + from72dpi(height, yDPI);
+       // again make sure the image is inside the imageable area
+       if (right > imageableArea.right) {
+               right = imageableArea.right;
+               left = right - width;
+               if (left < imageableArea.left) {
+                       left = imageableArea.left;
+                       right = left + width - kGutenprintUnit;
+               }
+               width = right - left;
+       }
 
+       if (bottom > imageableArea.bottom) {
+               bottom = imageableArea.bottom;
+               top = bottom - height;
+               if (top < imageableArea.top) {
+                       top = imageableArea.top;
+                       bottom = top + height - kGutenprintUnit;
+               }
+               height = bottom - top;
+       }
+
+       // because of rounding and clipping in the previous step,
+       // now the image frame has to be synchronized
+       coordinateSystem.FromGutenprint(left, top, fPrintRect.left, 
fPrintRect.top);
+       int32 printRectWidth;
+       int32 printRectHeight;
+       coordinateSystem.SizeFromGutenprint(width, height, printRectWidth,
+               printRectHeight);
+       fPrintRect.right = fPrintRect.left + printRectWidth - 1;
+       fPrintRect.bottom = fPrintRect.top + printRectHeight - 1;
        {
-               int left = (int)fPrintRect.left;
-               int top = (int)fPrintRect.top;
-               int width = fPrintRect.IntegerWidth() + 1;
-               int height = fPrintRect.IntegerHeight() + 1;
+               int left = fPrintRect.left;
+               int top = fPrintRect.top;
+               int width = fPrintRect.Width() + 1;
+               int height = fPrintRect.Height() + 1;
 
-               fprintf(stderr, "GPJob image dimensions left %d, top %d, width 
%d, height %d\n",
+               fprintf(stderr, "GPJob image dimensions left %d, top %d, width 
%d, "
+                       "height %d\n",
                        left, top, width, height);
        }
 
-       fprintf(stderr, "GPJob image dimensions in 1/72 Inches:\n"
-               "left %d, top %d, width %d, height %d\n",
-               left, top, width, height);
+       fprintf(stderr, "GPJob image dimensions in 1/72 Inches: "
+               "left %d, top %d, right %d, bottom %d\n",
+               (int)left, (int)top, (int)right, (int)bottom);
 
-       stp_set_width(fVariables, width);
-       stp_set_height(fVariables, height);
+       stp_set_width(fVariables, right - left);
+       stp_set_height(fVariables, bottom - top);
        stp_set_left(fVariables, left);
        stp_set_top(fVariables, top);
 
        stp_merge_printvars(fVariables, stp_printer_get_defaults(fPrinter));
 
        if (!stp_verify(fVariables)) {
-               // TODO report error
                fprintf(stderr, "GPJob PrintPage: invalid variables\n");
                return B_ERROR;
        }
@@ -315,7 +396,7 @@
 }
 
 
-BRect
+RectInt32
 GPJob::GetPrintRectangle(list<GPBand*>& bands)
 {
        list<GPBand*>::iterator it = bands.begin();
@@ -349,14 +430,14 @@
 int
 GPJob::Width()
 {
-       return static_cast<int>(fPrintRect.IntegerWidth() + 1);
+       return fPrintRect.Width() + 1;
 }
 
 
 int
 GPJob::Height()
 {
-       return static_cast<int>(fPrintRect.IntegerHeight() + 1);
+       return fPrintRect.Height() + 1;
 }
 
 
@@ -367,8 +448,8 @@
                return STP_IMAGE_STATUS_ABORT;
 
        // row is relative to left, top of image
-       // convert it to absolute value
-       int line = static_cast<int>(fPrintRect.top) + row;
+       // convert it to absolute y coordinate value
+       int line = fPrintRect.top + row;
 
        FillWhite(data, size);
 
@@ -407,19 +488,30 @@
                band->fValidRect.top);
        int imageLeft = static_cast<int>(band->fValidRect.left);
 
-       const int sourceDelta = band->fBitmap.BytesPerRow();
+       const int sourceBytesPerRow = band->fBitmap.BytesPerRow();
        const int kSourceBytesPerPixel = 4; // BGRA
        const unsigned char* source =
                static_cast<unsigned char*>(band->fBitmap.Bits())
-               + imageTop * sourceDelta
+               + imageTop * sourceBytesPerRow
                + imageLeft * kSourceBytesPerPixel;
 
        int dataLeft = static_cast<int>(band->fWhere.x - fPrintRect.left);
+       int sourcePixelsToSkip = 0;
+       if (dataLeft < 0) {
+               sourcePixelsToSkip = -dataLeft;
+               dataLeft = 0;
+       }
+       int width = band->fValidRect.IntegerWidth() + 1 - sourcePixelsToSkip;
+       source += sourcePixelsToSkip * kSourceBytesPerPixel;
+       if (width <= 0)
+               return;
 
        const int kTargetBytesPerPixel = 3; // RGB
        unsigned char* target = &data[dataLeft * kTargetBytesPerPixel];
+       int maxWidth = size / kTargetBytesPerPixel - dataLeft;
+       if (width > maxWidth)
+               width = maxWidth;
 
-       const int width = band->fValidRect.IntegerWidth() + 1;
        ASSERT(0 <= imageTop && imageTop <= band->fValidRect.IntegerHeight());
        ASSERT((dataLeft + width) * kTargetBytesPerPixel <= size);
 

Modified: haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.h
===================================================================
--- haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.h    2010-12-05 
00:48:56 UTC (rev 39732)
+++ haiku/trunk/src/add-ons/print/drivers/gutenprint/GPJob.h    2010-12-05 
11:13:07 UTC (rev 39733)
@@ -17,6 +17,7 @@
 #include "GPBand.h"
 #include "GPJobConfiguration.h"
 #include "OutputStream.h"
+#include "Rectangle.h"
 
 
 class GPJob
@@ -37,11 +38,11 @@
        void            GetErrorMessage(BString& message);
 
 private:
-       BRect   GetPrintRectangle(list<GPBand*>& bands);
-       GPBand* FindBand(int line);
-       void    FillRow(GPBand* band, unsigned char* data, size_t size,
+       RectInt32       GetPrintRectangle(list<GPBand*>& bands);
+       GPBand*         FindBand(int line);
+       void            FillRow(GPBand* band, unsigned char* data, size_t size,
                int line);
-       void    FillWhite(unsigned char* data, size_t size);
+       void            FillWhite(unsigned char* data, size_t size);
 
        void                            Init();
        void                            Reset();
@@ -74,7 +75,7 @@
        stp_image_t                             fImage;
        stp_vars_t*                             fVariables;
        const stp_printer_t*    fPrinter;
-       BRect                                   fPrintRect;
+       RectInt32                               fPrintRect;
        list<GPBand*>*                  fBands;
        GPBand*                                 fCachedBand;
        status_t                                fStatus;

Added: haiku/trunk/src/add-ons/print/drivers/gutenprint/Rectangle.h
===================================================================
--- haiku/trunk/src/add-ons/print/drivers/gutenprint/Rectangle.h                
                (rev 0)
+++ haiku/trunk/src/add-ons/print/drivers/gutenprint/Rectangle.h        
2010-12-05 11:13:07 UTC (rev 39733)
@@ -0,0 +1,79 @@
+/*
+* Copyright 2010, Haiku. All rights reserved.
+* Distributed under the terms of the MIT License.
+*
+* Authors:
+*              Michael Pfeiffer
+*/
+#ifndef RECTANGLE_H
+#define RECTANGLE_H
+
+
+#include <SupportDefs.h>
+
+
+template<typename T>
+class Rectangle
+{
+public:
+       Rectangle()
+       :
+       left(0),
+       top(0),
+       right(0),
+       bottom(0)
+       {
+
+       }
+
+
+       Rectangle(const BRect& rect)
+       :
+       left(static_cast<T>(rect.left)),
+       top(static_cast<T>(rect.top)),
+       right(static_cast<T>(rect.right)),
+       bottom(static_cast<T>(rect.bottom))
+       {
+       }
+
+
+       Rectangle(T left, T top, T right, T bottom)
+       :
+       left(left),
+       top(top),
+       right(right),
+       bottom(bottom)
+       {
+       }
+
+
+       Rectangle<T>& operator=(const BRect& rect) {
+               left = static_cast<T>(rect.left);
+               top = static_cast<T>(rect.top);
+               right = static_cast<T>(rect.right);
+               bottom = static_cast<T>(rect.bottom);
+               return *this;
+       }
+
+
+       T Width() const {
+               return right - left;
+       }
+
+
+       T Height() const {
+               return bottom - top;
+       }
+
+
+       T left;
+       T top;
+       T right;
+       T bottom;
+};
+
+
+typedef Rectangle<int32> RectInt32;
+
+
+#endif


Other related posts:

  • » [haiku-commits] r39733 - haiku/trunk/src/add-ons/print/drivers/gutenprint - michael . w . pfeiffer