You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@pdfbox.apache.org by John Hewson <jo...@jahewson.com> on 2014/12/27 14:16:29 UTC

Matrix Skew

Hi All,

I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
in PDFBox uses the following matrix:

| sx hy 0 |
| hx sy 0 |
| tx ty 1 |

In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.

The Concatenate operator class populates the Matrix as follows:
                                            PDFBox  PDF Spec
newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty

I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
(hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
constructor expects its elements but does not match the arrays used in the PDF spec.

Are we accidentally flipping skew-x and skew-y in the Concatenate operator?

-- John


Re: Matrix Skew

Posted by Tilman Hausherr <TH...@t-online.de>.
The best way to prove or falsify this theory would be to create a PDF 
that uses the "cm" operator, but has different values for hy and hx, and 
then render the image with PDFBox.

Or render PDF files and see what happens... I just changed that method, 
and get several differences in the Basiswissen-Vorschriften.pdf file, on 
page 1 (bottom left), page 6 (the two top right pictures). The file 
eci_altona-test-suite-v2_technical_H.pdf looks weird now. Same for 
example_013.pdf, which is about these things.

Tilman

Am 27.12.2014 um 14:16 schrieb John Hewson:
> Hi All,
>
> I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
> in PDFBox uses the following matrix:
>
> | sx hy 0 |
> | hx sy 0 |
> | tx ty 1 |
>
> In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
> the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.
>
> The Concatenate operator class populates the Matrix as follows:
>                                              PDFBox  PDF Spec
> newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
> newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
> newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
> newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
> newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
> newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty
>
> I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
> (hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
> constructor expects its elements but does not match the arrays used in the PDF spec.
>
> Are we accidentally flipping skew-x and skew-y in the Concatenate operator?
>
> -- John
>
>


Re: Matrix Skew

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
Hi John,

we're fine.

Maruan

Am 30.12.2014 um 00:30 schrieb John Hewson <jo...@jahewson.com>:

> Hi Maruan,
> 
>> On 28 Dec 2014, at 02:54, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
>> 
>> OK - I think the Matrix code is wrong in getting the shear values compared to the description in the PDF spec. 
>> 
>> eg. using a text matrix to produce an 'italic' text 
>> 
>> AffineTransform transform = AffineTransform.getShearInstance(0, 0.5);
>> contentStream.setTextMatrix(transform);
>> 
>> produces the same result as 
>> 
>> contentStream.setTextMatrix(1, 0, 0.5, 1, 0, 0);
>> 
>> 
>> Which is inline with the spec as c is the sy value.
>> 
> 
> Yes.
> 
>> Now getShearX, getShearY and create AffineTransform in Matrix are wrong IMHO as they have the extraction flipped between sx and sy.
> 
> That’s what was puzzling me. I think what we’re doing is fine based on AffineTransform’s definition of shear x/y, but that the terminology is simply different from PDF, i.e. an x-skew is described in terms of a y-factor, so it’s easy to see how the naming could be ambiguous.
> 
>> e.g. printing the values of
>> 
>> AffineTransform transform = AffineTransform.getShearInstance(0, 0.5);
> 
> Ok, so that’s hx = 0, hy = 0.5
> 
>> produces
>> 
>> AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]
>> 
>> where 
>> 
>> printing the values of
>> 
>> Matrix matrix = new Matrix();
>> matrix.setValue(1, 0, 0.5f);
> 
> Element (1,0) is hx, so you’re doing hx = 0.5, hy = 0, which is the opposite of your example above.
> 
>> produces
>> 
>> AffineTransform[[1.0, 0.5, 0.0], [0.0, 1.0, 0.0]]
>> 
>> which is wrong as it should produce AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]
> 
> Which would make sense for hx = 0.5 but what you wanted was:
> 
>    matrix.setValue(0, 1, 0.5f)
> 
> which produces the expected result:
> 
>    AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]
> 
> So I think we’re ok.
> 
> — John
> 
>> 
>> BR
>> 
>> Maruan
>> 
>> Am 27.12.2014 um 23:47 schrieb John Hewson <jo...@jahewson.com>:
>> 
>>> Yes, the pure matrix code seems to work fine. As do the examples which Tilman mentioned. I can’t find any issue with the code itself. However, we make use the following Matrix method:
>>> 
>>> public AffineTransform createAffineTransform()
>>> {
>>>  AffineTransform retval = new AffineTransform(
>>>      single[0], single[1],   // m00 m10 = scaleX shearY
>>>      single[3], single[4],   // m01 m11 = shearX scaleY
>>>      single[6], single[7] ); // m02 m12 = tx ty
>>>  return retval;
>>> }
>>> 
>>> Recall that single[] is the array:
>>> 
>>> | sx hy 0 |
>>> | hx sy 0 |
>>> | tx ty 1 |
>>> 
>>> Which is fine, except that shear-x and shear-y are flipped vs. the wording in the PDF spec, namely:
>>> 
>>> "Skew shall be specified by [1 tan a tan b 1 0 0], which skews the x axis by an angle a and the y axis by
>>> an angle b.”
>>> 
>>> But the AffineTransform constructor uses the following parameters:
>>> 
>>> "m00 - the X coordinate scaling element of the 3x3 matrix
>>> m10 - the Y coordinate shearing element of the 3x3 matrix
>>> m01 - the X coordinate shearing element of the 3x3 matrix
>>> m11 - the Y coordinate scaling element of the 3x3 matrix
>>> m02 - the X coordinate translation element of the 3x3 matrix
>>> m12 - the Y coordinate translation element of the 3x3 matrix"
>>> 
>>> At this point I’m left thinking that Java and PDF have chosen different meanings of “x” and “y” when talking about skew, indeed this appears to be the case, as the PDF spec defines the x-coordinate transform on p120 as:
>>> 
>>> x’ = a*x + c*y + e
>>> 
>>> while the AffineTransform documentation defines the same transform as:
>>> 
>>> x'  =  [ m00*x + m01*y + m02 ]
>>> 
>>> which might seem different until one realises that m00 = a, m01 = c, m02 = e. The only difference appears to be  the description that c "skews the y axis” in PDF and m01 is "the X coordinate shearing" in AffineTransform. It seems like PDF is weird in this regard?
>>> 
>>> -- John
>>> 
>>>> On 27 Dec 2014, at 16:51, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
>>>> 
>>>> Hi,
>>>> 
>>>> I tried the following with skew being [1 tan a tan b 1 0 0] according to the spec. 
>>>> 
>>>> Matrix matrix = new Matrix();
>>>> 
>>>> which gives me [1.0,0.0,0.0,1.0,0.0,0.0]
>>>> 
>>>> then
>>>> 
>>>> matrix.setValue(0, 1, 0.5f);
>>>> matrix.setValue(1, 0, 0.7f);
>>>> 
>>>> which shall set the tan a and tan b values
>>>> 
>>>> which gave me 
>>>> 
>>>> [1.0,0.5,0.7,1.0,0.0,0.0]
>>>> 
>>>> then
>>>> 
>>>> Matrix matrix2 = new Matrix()
>>>> 
>>>> again being [1.0,0.0,0.0,1.0,0.0,0.0]
>>>> 
>>>> then
>>>> 
>>>> matrix.concatenate(matrix2)
>>>> 
>>>> resulting in [1.0,0.5,0.7,1.0,0.0,0.0]
>>>> 
>>>> To me that indicates that the pure matrix class is fine for that case. What are the arguments to the Concatenate operator in your case? Could it be that reading the values is not OK?
>>>> 
>>>> BR
>>>> 
>>>> Maruan
>>>> 
>>>> Am 27.12.2014 um 14:16 schrieb John Hewson <jo...@jahewson.com>:
>>>> 
>>>>> Hi All,
>>>>> 
>>>>> I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
>>>>> in PDFBox uses the following matrix:
>>>>> 
>>>>> | sx hy 0 |
>>>>> | hx sy 0 |
>>>>> | tx ty 1 |
>>>>> 
>>>>> In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
>>>>> the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.
>>>>> 
>>>>> The Concatenate operator class populates the Matrix as follows:
>>>>>                                        PDFBox  PDF Spec
>>>>> newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
>>>>> newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
>>>>> newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
>>>>> newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
>>>>> newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
>>>>> newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty
>>>>> 
>>>>> I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
>>>>> (hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
>>>>> constructor expects its elements but does not match the arrays used in the PDF spec.
>>>>> 
>>>>> Are we accidentally flipping skew-x and skew-y in the Concatenate operator?
>>>>> 
>>>>> -- John
>>>>> 
>>>> 
>>> 
>> 
> 


Re: Matrix Skew

Posted by John Hewson <jo...@jahewson.com>.
Hi Maruan,

> On 28 Dec 2014, at 02:54, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
> 
> OK - I think the Matrix code is wrong in getting the shear values compared to the description in the PDF spec. 
> 
> eg. using a text matrix to produce an 'italic' text 
> 
> AffineTransform transform = AffineTransform.getShearInstance(0, 0.5);
> contentStream.setTextMatrix(transform);
> 
> produces the same result as 
> 
> contentStream.setTextMatrix(1, 0, 0.5, 1, 0, 0);
> 
> 
> Which is inline with the spec as c is the sy value.
> 

Yes.

> Now getShearX, getShearY and create AffineTransform in Matrix are wrong IMHO as they have the extraction flipped between sx and sy.

That’s what was puzzling me. I think what we’re doing is fine based on AffineTransform’s definition of shear x/y, but that the terminology is simply different from PDF, i.e. an x-skew is described in terms of a y-factor, so it’s easy to see how the naming could be ambiguous.

> e.g. printing the values of
> 
> AffineTransform transform = AffineTransform.getShearInstance(0, 0.5);

Ok, so that’s hx = 0, hy = 0.5

> produces
> 
> AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]
> 
> where 
> 
> printing the values of
> 
> Matrix matrix = new Matrix();
> matrix.setValue(1, 0, 0.5f);

Element (1,0) is hx, so you’re doing hx = 0.5, hy = 0, which is the opposite of your example above.

> produces
> 
> AffineTransform[[1.0, 0.5, 0.0], [0.0, 1.0, 0.0]]
> 
> which is wrong as it should produce AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]

Which would make sense for hx = 0.5 but what you wanted was:

    matrix.setValue(0, 1, 0.5f)

which produces the expected result:

    AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]

So I think we’re ok.

— John

> 
> BR
> 
> Maruan
> 
> Am 27.12.2014 um 23:47 schrieb John Hewson <jo...@jahewson.com>:
> 
>> Yes, the pure matrix code seems to work fine. As do the examples which Tilman mentioned. I can’t find any issue with the code itself. However, we make use the following Matrix method:
>> 
>> public AffineTransform createAffineTransform()
>> {
>>   AffineTransform retval = new AffineTransform(
>>       single[0], single[1],   // m00 m10 = scaleX shearY
>>       single[3], single[4],   // m01 m11 = shearX scaleY
>>       single[6], single[7] ); // m02 m12 = tx ty
>>   return retval;
>> }
>> 
>> Recall that single[] is the array:
>> 
>> | sx hy 0 |
>> | hx sy 0 |
>> | tx ty 1 |
>> 
>> Which is fine, except that shear-x and shear-y are flipped vs. the wording in the PDF spec, namely:
>> 
>> "Skew shall be specified by [1 tan a tan b 1 0 0], which skews the x axis by an angle a and the y axis by
>> an angle b.”
>> 
>> But the AffineTransform constructor uses the following parameters:
>> 
>> "m00 - the X coordinate scaling element of the 3x3 matrix
>> m10 - the Y coordinate shearing element of the 3x3 matrix
>> m01 - the X coordinate shearing element of the 3x3 matrix
>> m11 - the Y coordinate scaling element of the 3x3 matrix
>> m02 - the X coordinate translation element of the 3x3 matrix
>> m12 - the Y coordinate translation element of the 3x3 matrix"
>> 
>> At this point I’m left thinking that Java and PDF have chosen different meanings of “x” and “y” when talking about skew, indeed this appears to be the case, as the PDF spec defines the x-coordinate transform on p120 as:
>> 
>> x’ = a*x + c*y + e
>> 
>> while the AffineTransform documentation defines the same transform as:
>> 
>> x'  =  [ m00*x + m01*y + m02 ]
>> 
>> which might seem different until one realises that m00 = a, m01 = c, m02 = e. The only difference appears to be  the description that c "skews the y axis” in PDF and m01 is "the X coordinate shearing" in AffineTransform. It seems like PDF is weird in this regard?
>> 
>> -- John
>> 
>>> On 27 Dec 2014, at 16:51, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
>>> 
>>> Hi,
>>> 
>>> I tried the following with skew being [1 tan a tan b 1 0 0] according to the spec. 
>>> 
>>> Matrix matrix = new Matrix();
>>> 
>>> which gives me [1.0,0.0,0.0,1.0,0.0,0.0]
>>> 
>>> then
>>> 
>>> matrix.setValue(0, 1, 0.5f);
>>> matrix.setValue(1, 0, 0.7f);
>>> 
>>> which shall set the tan a and tan b values
>>> 
>>> which gave me 
>>> 
>>> [1.0,0.5,0.7,1.0,0.0,0.0]
>>> 
>>> then
>>> 
>>> Matrix matrix2 = new Matrix()
>>> 
>>> again being [1.0,0.0,0.0,1.0,0.0,0.0]
>>> 
>>> then
>>> 
>>> matrix.concatenate(matrix2)
>>> 
>>> resulting in [1.0,0.5,0.7,1.0,0.0,0.0]
>>> 
>>> To me that indicates that the pure matrix class is fine for that case. What are the arguments to the Concatenate operator in your case? Could it be that reading the values is not OK?
>>> 
>>> BR
>>> 
>>> Maruan
>>> 
>>> Am 27.12.2014 um 14:16 schrieb John Hewson <jo...@jahewson.com>:
>>> 
>>>> Hi All,
>>>> 
>>>> I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
>>>> in PDFBox uses the following matrix:
>>>> 
>>>> | sx hy 0 |
>>>> | hx sy 0 |
>>>> | tx ty 1 |
>>>> 
>>>> In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
>>>> the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.
>>>> 
>>>> The Concatenate operator class populates the Matrix as follows:
>>>>                                         PDFBox  PDF Spec
>>>> newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
>>>> newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
>>>> newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
>>>> newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
>>>> newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
>>>> newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty
>>>> 
>>>> I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
>>>> (hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
>>>> constructor expects its elements but does not match the arrays used in the PDF spec.
>>>> 
>>>> Are we accidentally flipping skew-x and skew-y in the Concatenate operator?
>>>> 
>>>> -- John
>>>> 
>>> 
>> 
> 


Re: Matrix Skew

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
OK - I think the Matrix code is wrong in getting the shear values compared to the description in the PDF spec. 

eg. using a text matrix to produce an 'italic' text 

AffineTransform transform = AffineTransform.getShearInstance(0, 0.5);
contentStream.setTextMatrix(transform);

produces the same result as 

contentStream.setTextMatrix(1, 0, 0.5, 1, 0, 0);


Which is inline with the spec as c is the sy value.

Now getShearX, getShearY and createAffineTransform in Matrix are wrong IMHO as they have the extraction flipped between sx and sy.

e.g. printing the values of

AffineTransform transform = AffineTransform.getShearInstance(0, 0.5);

produces

AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]

where 

printing the values of

Matrix matrix = new Matrix();
matrix.setValue(1, 0, 0.5f);

produces

AffineTransform[[1.0, 0.5, 0.0], [0.0, 1.0, 0.0]]

which is wrong as it should produce AffineTransform[[1.0, 0.0, 0.0], [0.5, 1.0, 0.0]]


BR

Maruan

Am 27.12.2014 um 23:47 schrieb John Hewson <jo...@jahewson.com>:

> Yes, the pure matrix code seems to work fine. As do the examples which Tilman mentioned. I can’t find any issue with the code itself. However, we make use the following Matrix method:
> 
> public AffineTransform createAffineTransform()
> {
>    AffineTransform retval = new AffineTransform(
>        single[0], single[1],   // m00 m10 = scaleX shearY
>        single[3], single[4],   // m01 m11 = shearX scaleY
>        single[6], single[7] ); // m02 m12 = tx ty
>    return retval;
> }
> 
> Recall that single[] is the array:
> 
> | sx hy 0 |
> | hx sy 0 |
> | tx ty 1 |
> 
> Which is fine, except that shear-x and shear-y are flipped vs. the wording in the PDF spec, namely:
> 
> "Skew shall be specified by [1 tan a tan b 1 0 0], which skews the x axis by an angle a and the y axis by
> an angle b.”
> 
> But the AffineTransform constructor uses the following parameters:
> 
> "m00 - the X coordinate scaling element of the 3x3 matrix
> m10 - the Y coordinate shearing element of the 3x3 matrix
> m01 - the X coordinate shearing element of the 3x3 matrix
> m11 - the Y coordinate scaling element of the 3x3 matrix
> m02 - the X coordinate translation element of the 3x3 matrix
> m12 - the Y coordinate translation element of the 3x3 matrix"
> 
> At this point I’m left thinking that Java and PDF have chosen different meanings of “x” and “y” when talking about skew, indeed this appears to be the case, as the PDF spec defines the x-coordinate transform on p120 as:
> 
> x’ = a*x + c*y + e
> 
> while the AffineTransform documentation defines the same transform as:
> 
> x'  =  [ m00*x + m01*y + m02 ]
> 
> which might seem different until one realises that m00 = a, m01 = c, m02 = e. The only difference appears to be  the description that c "skews the y axis” in PDF and m01 is "the X coordinate shearing" in AffineTransform. It seems like PDF is weird in this regard?
> 
> -- John
> 
>> On 27 Dec 2014, at 16:51, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
>> 
>> Hi,
>> 
>> I tried the following with skew being [1 tan a tan b 1 0 0] according to the spec. 
>> 
>> Matrix matrix = new Matrix();
>> 
>> which gives me [1.0,0.0,0.0,1.0,0.0,0.0]
>> 
>> then
>> 
>> matrix.setValue(0, 1, 0.5f);
>> matrix.setValue(1, 0, 0.7f);
>> 
>> which shall set the tan a and tan b values
>> 
>> which gave me 
>> 
>> [1.0,0.5,0.7,1.0,0.0,0.0]
>> 
>> then
>> 
>> Matrix matrix2 = new Matrix()
>> 
>> again being [1.0,0.0,0.0,1.0,0.0,0.0]
>> 
>> then
>> 
>> matrix.concatenate(matrix2)
>> 
>> resulting in [1.0,0.5,0.7,1.0,0.0,0.0]
>> 
>> To me that indicates that the pure matrix class is fine for that case. What are the arguments to the Concatenate operator in your case? Could it be that reading the values is not OK?
>> 
>> BR
>> 
>> Maruan
>> 
>> Am 27.12.2014 um 14:16 schrieb John Hewson <jo...@jahewson.com>:
>> 
>>> Hi All,
>>> 
>>> I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
>>> in PDFBox uses the following matrix:
>>> 
>>> | sx hy 0 |
>>> | hx sy 0 |
>>> | tx ty 1 |
>>> 
>>> In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
>>> the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.
>>> 
>>> The Concatenate operator class populates the Matrix as follows:
>>>                                          PDFBox  PDF Spec
>>> newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
>>> newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
>>> newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
>>> newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
>>> newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
>>> newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty
>>> 
>>> I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
>>> (hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
>>> constructor expects its elements but does not match the arrays used in the PDF spec.
>>> 
>>> Are we accidentally flipping skew-x and skew-y in the Concatenate operator?
>>> 
>>> -- John
>>> 
>> 
> 


Re: Matrix Skew

Posted by John Hewson <jo...@jahewson.com>.
Yes, the pure matrix code seems to work fine. As do the examples which Tilman mentioned. I can’t find any issue with the code itself. However, we make use the following Matrix method:

public AffineTransform createAffineTransform()
{
    AffineTransform retval = new AffineTransform(
        single[0], single[1],   // m00 m10 = scaleX shearY
        single[3], single[4],   // m01 m11 = shearX scaleY
        single[6], single[7] ); // m02 m12 = tx ty
    return retval;
}

Recall that single[] is the array:

| sx hy 0 |
| hx sy 0 |
| tx ty 1 |

Which is fine, except that shear-x and shear-y are flipped vs. the wording in the PDF spec, namely:

"Skew shall be specified by [1 tan a tan b 1 0 0], which skews the x axis by an angle a and the y axis by
an angle b.”

But the AffineTransform constructor uses the following parameters:

"m00 - the X coordinate scaling element of the 3x3 matrix
 m10 - the Y coordinate shearing element of the 3x3 matrix
 m01 - the X coordinate shearing element of the 3x3 matrix
 m11 - the Y coordinate scaling element of the 3x3 matrix
 m02 - the X coordinate translation element of the 3x3 matrix
 m12 - the Y coordinate translation element of the 3x3 matrix"

At this point I’m left thinking that Java and PDF have chosen different meanings of “x” and “y” when talking about skew, indeed this appears to be the case, as the PDF spec defines the x-coordinate transform on p120 as:

x’ = a*x + c*y + e

while the AffineTransform documentation defines the same transform as:

x'  =  [ m00*x + m01*y + m02 ]

which might seem different until one realises that m00 = a, m01 = c, m02 = e. The only difference appears to be  the description that c "skews the y axis” in PDF and m01 is "the X coordinate shearing" in AffineTransform. It seems like PDF is weird in this regard?

-- John

> On 27 Dec 2014, at 16:51, Maruan Sahyoun <sa...@fileaffairs.de> wrote:
> 
> Hi,
> 
> I tried the following with skew being [1 tan a tan b 1 0 0] according to the spec. 
> 
> Matrix matrix = new Matrix();
> 
> which gives me [1.0,0.0,0.0,1.0,0.0,0.0]
> 
> then
> 
> matrix.setValue(0, 1, 0.5f);
> matrix.setValue(1, 0, 0.7f);
> 
> which shall set the tan a and tan b values
> 
> which gave me 
> 
> [1.0,0.5,0.7,1.0,0.0,0.0]
> 
> then
> 
> Matrix matrix2 = new Matrix()
> 
> again being [1.0,0.0,0.0,1.0,0.0,0.0]
> 
> then
> 
> matrix.concatenate(matrix2)
> 
> resulting in [1.0,0.5,0.7,1.0,0.0,0.0]
> 
> To me that indicates that the pure matrix class is fine for that case. What are the arguments to the Concatenate operator in your case? Could it be that reading the values is not OK?
> 
> BR
> 
> Maruan
> 
> Am 27.12.2014 um 14:16 schrieb John Hewson <jo...@jahewson.com>:
> 
>> Hi All,
>> 
>> I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
>> in PDFBox uses the following matrix:
>> 
>> | sx hy 0 |
>> | hx sy 0 |
>> | tx ty 1 |
>> 
>> In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
>> the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.
>> 
>> The Concatenate operator class populates the Matrix as follows:
>>                                           PDFBox  PDF Spec
>> newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
>> newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
>> newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
>> newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
>> newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
>> newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty
>> 
>> I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
>> (hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
>> constructor expects its elements but does not match the arrays used in the PDF spec.
>> 
>> Are we accidentally flipping skew-x and skew-y in the Concatenate operator?
>> 
>> -- John
>> 
> 


Re: Matrix Skew

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
Hi,

I tried the following with skew being [1 tan a tan b 1 0 0] according to the spec. 

Matrix matrix = new Matrix();

which gives me [1.0,0.0,0.0,1.0,0.0,0.0]

then

matrix.setValue(0, 1, 0.5f);
matrix.setValue(1, 0, 0.7f);

which shall set the tan a and tan b values

which gave me 

[1.0,0.5,0.7,1.0,0.0,0.0]

then

Matrix matrix2 = new Matrix()

again being [1.0,0.0,0.0,1.0,0.0,0.0]

then

matrix.concatenate(matrix2)

resulting in [1.0,0.5,0.7,1.0,0.0,0.0]

To me that indicates that the pure matrix class is fine for that case. What are the arguments to the Concatenate operator in your case? Could it be that reading the values is not OK?

BR

Maruan

Am 27.12.2014 um 14:16 schrieb John Hewson <jo...@jahewson.com>:

> Hi All,
> 
> I’ve been looking at the Matrix class and trying to understand if it has some problems. The Matrix class
> in PDFBox uses the following matrix:
> 
> | sx hy 0 |
> | hx sy 0 |
> | tx ty 1 |
> 
> In a PDF file this matrix is represented as the 6-element array [a, b, c, d, e, f] where the meaning of
> the values comes from p118 and is [sx, hx, hy, sy, tx, ty]. Note that h is used to mean shear/skew.
> 
> The Concatenate operator class populates the Matrix as follows:
>                                            PDFBox  PDF Spec
> newMatrix.setValue(0, 0, a.floatValue());   sx      a = sx
> newMatrix.setValue(0, 1, b.floatValue());   hy      c = hx <- Flipped?
> newMatrix.setValue(1, 0, c.floatValue());   hx      b = hy <- Flipped?
> newMatrix.setValue(1, 1, d.floatValue());   sy      d = sy
> newMatrix.setValue(2, 0, e.floatValue());   tx      e = tx
> newMatrix.setValue(2, 1, f.floatValue());   ty      f = ty
> 
> I’ve annotated what PDFBox does on the left, compared to the PDF spec, the x and y skew elements
> (hx and hy) are flipped in PDFBox. This flip matches the order in which AWT’s AffineTransform’s
> constructor expects its elements but does not match the arrays used in the PDF spec.
> 
> Are we accidentally flipping skew-x and skew-y in the Concatenate operator?
> 
> -- John
>