galkahana / HummusJS

Node.js module for high performance creation, modification and parsing of PDF files and streams
http://www.pdfhummus.com
Other
1.15k stars 170 forks source link

How to rotate and resize all pages ? #206

Closed GautierT closed 7 years ago

GautierT commented 7 years ago

Hi, Following the issue #192 i'm now trying to rotate the page.

I'm doing the resize like this :

const resizeWriter = hummus.createWriter(file_path_tmp)
const resizeReader = hummus.createReader(file_path)

const resize_page_count = resizeReader.getPagesCount()

  for (let i = 0; i < resize_page_count; i++) {
    debug('Page : ', i)
    const page = resizeWriter.createPage(0, 0, 595, 842)

    const pageContent = resizeWriter.startPageContentContext(page)

    const margin = 0
    const ratio = 0.9
    pageContent
      .q()
      .drawImage(margin, margin, file_path_to_a_270_degree_PDF, {
        index: i,
        transformation: [ratio, 0, 0, ratio, 0, 0]
      })
      .Q()

    resizeWriter.writePage(page)
  }

  resizeWriter.end()

What should be the parameter object of transformation to rotate from 270° to 0°.

I don't really understand the number that have to be put in the array of transformation. Is it the same that for .cm() ? If yes what is the parameter for .cm() ? I can't find the answer in the documentation.

Thanks @galkahana

GautierT commented 7 years ago

I currently have a PDF too large and rotated at 270°. I want to resize it to fit in A4 format and rotate it to 0°. Thanks for the help.

galkahana commented 7 years ago

transformation matrixes are all the same around hummus, and are the same as their PDF counterparts. A transformation matrix is a 6 numbers array that can be described like this: [a, b, c, d, tx, ty]

where: X' = ax + cy + tx Y' = bx + dy + ty

you can read about it in the pdf reference manual, section 4.2.3

As for the problem at hand.

you are looking to scale and rotate the page. shouldn't be too hard. you need to get the rotation matrix, and then the scale matrix, and multiply them.

A rotation matrix for angle a' is [cos(a'), -sin(a'),sin(a'), cos(a),0,0], where a' is represented in radians (for example, 270 degrees, is 270/180 =1.5). You would normally won't just like to rotate, but also offset the element, cause the rotation happens around the bottom left of the element.

scaling - you already know.

to get the end results, here's what you should do:

  1. say your scale is "ratio", then you figured the matrix - [ratio, 0, 0 ,ratio, 0 ,0]
  2. the page is rotated at 270, you want to rotate it to 0. well, that's a 90 degrees rotation. matrix is then [0, -1, 1, 0, 0, 0]
  3. rotating the page in 90 degrees, will cause the graphics to move to the next quadrant, you want to offset it back in the x axis, according to the original page height scaled by ration, so this is a translation matrix that should be [1, 0, 0,1, ratio*org_height, 0] (you may want to experiment with this a bit, to see that you get what's going on and that i'm actually right). you wanna do that prior to rotating (try to imagine this).

so, scale, then translate, then rotate: [ratio,0,0,ratio,0,0] [1,0,0,1,org_heightratio,0] [0, -1, 1,0, 0, 0] = [0, -ratio, ratio, 0, 0, -ratioorg_height]

(hope i got the order right)

galkahana commented 7 years ago

Felt like i shouldn't just throw this at you without testing. so i tested...and i got some mistakes here.

to rotate in 90 degree the correct matrix is [0,1,-1,0,0,0] (i got confused how matrixes are represented in PDF. they use left side multiplication instead of right size, which causes the matrixes to be transposed to what im used to, so its actually [cos(a'), sin(a'), -sin(a'), cos(a),0,0]). second, it's ok to do the translation after the rotation, as long as you understand what you need to do. in this case, rotating in 90 degree, will require that after that we translate the y axis in minus of the height, cause basically we want the top left corner to be the resting on the 0,0 with the width and height going in the positive directions. so it's [1,0,0,1,0,-height].

so it's, scale, rotate, then translate. this can be done in two ways:

  1. using 3 calls to cm (they accumulate)
  2. using one call to cm (or using the form matrix, as you did). in this case the end results matrix is [0, ratio, -ratio, 0, ratio*org_height,0]

i created some samples for this in the attached code, using rectangle with text. you should replace the code drawing the rectangle with the call to drawImage to get the same effect. transformationUtils.zip

GautierT commented 7 years ago

Wahou! Thanks a lot. I will look and test that on Monday.

On sam. 7 oct. 2017 13:41 gal kahana notifications@github.com wrote:

Felt like i shouldn't just throw this at you without testing. so i tested...and i got some mistakes here.

to rotate in 90 degree the correct matrix is [0,1,-1,0,0,0] (i got confused how matrixes are represented in PDF. they use left side multiplication instead of right size, which causes the matrixes to be transposed to what im used to, so its actually [cos(a'), sin(a'), -sin(a'), cos(a),0,0]). second, it's ok to do the translation after the rotation, as long as you understand what you need to do. in this case, rotating in 90 degree, will require that after that we translate the y axis in minus of the height, cause basically we want the top left corner to be the resting on the 0,0 with the width and height going in the positive directions. so it's [1,0,0,1,0,-height].

so it's, scale, rotate, then translate. this can be done in two ways:

  1. using 3 calls to cm (they accumulate)
  2. using one call to cm (or using the form matrix, as you did). in this case the end results matrix is [0, ratio, -ratio, 0, ratio*org_height,0]

i created some samples for this in the attached code, using rectangle with text. you should replace the code drawing the rectangle with the call to drawImage to get the same effect. transformationUtils.zip https://github.com/galkahana/HummusJS/files/1364599/transformationUtils.zip

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/galkahana/HummusJS/issues/206#issuecomment-334932485, or mute the thread https://github.com/notifications/unsubscribe-auth/AFzrtfoyu0g7Miz0sdvGz-o5Myv1dyCwks5sp3GTgaJpZM4PwXZJ .

chunyenHuang commented 7 years ago

I have some example here about rotating page. https://github.com/chunyenHuang/hummusRecipe/blob/master/lib/page.js#L95

    switch (rotate) {
        case 90:
            context.cm(0, 1, -1, 0, height, 0);
            break;
        case 270:
            context.cm(0, -1, 1, 0, 0, width);
            break;
        case 180:
            context.cm(-1, 0, 0, -1, width, height);
            break;
        default:
    }
GautierT commented 7 years ago

Thanks a lot @galkahana and @chunyenHuang . It's working great. And i have now a better understanding of PDF manipulation.