hummusRecipe icon indicating copy to clipboard operation
hummusRecipe copied to clipboard

Image opacity option not working

Open ytaborda17 opened this issue 4 years ago • 6 comments

I tried to use the opacity option with an image and is not working, if you open the file image in node_modules, you can see option.opacity declared but never used, but the documentation says you can use that property, in resume: it's not working

pdf.image(path + fileName, 361, 326, { width: 600, height: 450, keepAspectRatio: true, opacity: 10, align: 'center center' });

ytaborda17 avatar Mar 03 '20 15:03 ytaborda17

It seems to me the range for opacity is 0.0 - 1.0

chunyenHuang avatar Mar 03 '20 17:03 chunyenHuang

It doesn't matter the number you use in the option:

  • 0.8 / 0,8
  • 0.5 / 0,5
  • 1
  • 1505656565

It doesn't work, because the option is never used in the library, if you open the file /node_modules/hummus-recipe/lib/image.js you can se the option been declared, but is never used:

`/**

  • Place images to pdf

  • @name image

  • @function

  • @memberof Recipe

  • @param {string} imgSrc - The path for the image. [JPEG, PNG, TIFF]

  • @param {number} x - The coordinate x

  • @param {number} y - The coordinate y

  • @param {Object} [options] - The options

  • @param {number} [options.width] - The new width

  • @param {number} [options.height] - The new height

  • @param {number} [options.scale] - Scale the image from the original width and height.

  • @param {boolean} [options.keepAspectRatio=true] - Keep the aspect ratio.

  • @param {number} [options.opacity] - The opacity.

  • @param {string} [options.align] - 'center center'... */ exports.image = function image(imgSrc, x, y, options = {}) { const { width, height, offsetX, offsetY } = this._getImgOffset(imgSrc, options); const imgOptions = { transformation: { fit: 'always', // proportional: true, width, height } }; const { nx, ny } = this._calibrateCoordinate(x, y, offsetX, offsetY);

    const _options = this._getPathOptions(options, nx, ny); const gsId = _options.fillGsId;

    // See if this image has been seen already, so as to not duplicate it. let xObject = this.xObjects.find((element) => { return element.get('name') == imgSrc; });

    if (xObject) { _options.xObject = xObject; _options.ratio = [width / xObject.get('width'), height / xObject.get('height')]; }

    this._drawObject(this, nx, ny, width, height, _options, (ctx, xObject) => {

     // Only new images visit here
     xObject.set('type', 'image');
     xObject.set('name', imgSrc);
     xObject.set('width', width);
     xObject.set('height', height);
    
     this.xObjects.push(xObject);
    
     ctx
         .gs(xObject.getGsName(gsId))
         .drawImage(0, 0, imgSrc, imgOptions);
    

    });

    return this; };

exports._getImgOffset = function _getImgOffset(imgSrc = '', options = {}) { // set default to true options.keepAspectRatio = (options.keepAspectRatio == void 0) ? true : options.keepAspectRatio; const dimensions = this.writer.getImageDimensions(imgSrc); const ratio = dimensions.width / dimensions.height;

let width = dimensions.width;
let height = dimensions.height;
if (options.scale) {
    width = width * options.scale;
    height = height * options.scale;
} else
if (options.width && !options.height) {
    width = options.width;
    height = options.width / ratio;
} else
if (!options.width && options.height) {
    width = options.height * ratio;
    height = options.height;
} else
if (options.width && options.height) {
    if (!options.keepAspectRatio) {
        width = options.width;
        height = options.height;
    } else {
        // fit to the smaller
        if (options.width / ratio <= options.height) {
            width = options.width;
            height = options.width / ratio;
        } else {
            width = options.height * ratio;
            height = options.height;
        }
    }
}
let offsetX = 0;
let offsetY = -height;

if (options.align) {
    const alignments = options.align.split(' ');
    if (alignments[0]) {
        switch (alignments[0]) {
            case 'center':
                offsetX = -1 * width / 2;
                break;
            case 'right':
                offsetX = width / 2;
                break;
            default:
        }
    }
    if (alignments[1]) {
        switch (alignments[1]) {
            case 'center':
                offsetY = -1 * height / 2;
                break;
            case 'bottom':
                offsetY = height / 2;
                break;
            default:
        }
    }
}
return { width, height, offsetX, offsetY };

};`

ytaborda17 avatar Mar 04 '20 00:03 ytaborda17

It doesn't matter the number you use in the option:

@ytaborda17 Please don't be mad. It does not mean the opacity is not applied if you dont find it in the code. PDF operator does not have a field called opacity, instead it calls gs when writing context. https://github.com/chunyenHuang/hummusRecipe/blob/master/lib/image.js#L53.

I just run the following test and it seems to me the opacity works as expected. Please see the attached screen shot.

const path = require('path');
const HummusRecipe = require('../lib');

describe('Modify', () => {
    const taskATP = 'Add transparent png';
    it(taskATP, (done) => {
        const src = path.join(__dirname, 'materials/test.pdf');
        const output = path.join(__dirname, `output/${taskATP}.pdf`);
        const wikiPng = path.join(__dirname, 'materials/wiki.png');

        const recipe = new HummusRecipe(src, output);
        recipe
            .editPage(1)
            .image(wikiPng, 'center', 'center', {
                width: 300,
                height: 300,
                align: 'center center',
                opacity: 0.5,
            })
            .endPage()
            .endPDF(done);
    });
});
Screen Shot 2020-03-03 at 6 58 58 PM

If you still can not make it work, please post your code so I can take a look for you.

chunyenHuang avatar Mar 04 '20 03:03 chunyenHuang

Ok, still not working, thanks any way, as you said, here is the code:

async function newPdf(data) {
  const order = Object.keys(data.cotizar.companias).sort();

  // client files + folder
  const fileName = data.quoteId + '.pdf';
  const folderName = data.nid + data.nid_dv;

  // pdf
  const origPath = PDF_PATH + 'base.pdf';
  const destPath = PDF_PATH + '/' + folderName + '/' + fileName;

  // logos
  const p = require('path')
  let logos = {
      path: p.join(__dirname, '../../shared/logos/'),
      files: {
          partner: data.user.partner.name
      }
  };

  common.createFolder(PDF_PATH + '/', folderName);

  return await new Promise((resolve, reject) => {
      const pdfDoc = new HummusRecipe(origPath, destPath);
      resolve(pdfDoc);
  }).then((page1header) => { // page1header
      page1header.editPage(1);
      if (data.user.partner.logo.indexOf('http') !== -1) {
          page1header.image(logos.path + logos.files.partner, 700, 32, {
              width: 100,
              height: 30,
              keepAspectRatio: true,
              align: 'center center'
          });
          // water mark
          page1header.image(logos.path + logos.files.partner, 361, 326, { // center: 371, 306,
              width: 600,
              height: 450,
              keepAspectRatio: true,
              opacity: 0.3,
              align: 'center center'
          });
      }
      page1header.text(data.form.date, 119, 40, { color: '#000000', size: 7 })
          .text('No: ' + data.quoteId, 665, 550, { color: '#000000', size: 7, bold: true })
          .text(data.form.name.toUpperCase(), 145, 63, { color: '#000000', size: 7 })
          .text(`${data.form.badge} ${data.form.cold}`, 370, 61, { color: '#000000', size: 7 })
          .text(common.currency(data.form.value, 0), 626, 83, { color: '#000000', size: 9, align: 'center', bold: true })

      return page1header;
  }).then((page2) => { // pag 2
      let x = 60;
      let y = 170;
      order.forEach(item => {
          if (item) {
            // ... print image and text an stuff
            // ... everything ok here
          }
      });
      page2.endPage().endPDF();
      return page2;
  }).then(() => { //Upload and save
      return {
          destPath: destPath,
          awsPath: 'path/' + folderName + '/' + fileName,
          quoteId: data.quoteId
      };
  }).catch(err => {
      throw new ErrorHandler(500, '--> Code not working U suck!', err);
  });

}

So, what I'm I doing wrong? Beacuse, with or without an opacity option, the image is printed but in full color.

I'm using Node 12.16.1, and before you say it, a downgrade is not a solution.

ytaborda17 avatar Mar 07 '20 02:03 ytaborda17

Oh I see the where the issue is.

          page1header.image(logos.path + logos.files.partner, 700, 32, {
              width: 100,
              height: 30,
              keepAspectRatio: true,
              align: 'center center'
          });
          // water mark
          page1header.image(logos.path + logos.files.partner, 361, 326, { // center: 371, 306,
              width: 600,
              height: 450,
              keepAspectRatio: true,
              opacity: 0.3,
              align: 'center center'
          });

You called .image twice with different opacity setups. It is a bug that the xObject is cached so the opacity is locked to the first image.

I can reproduce this bug with the following codes

const path = require('path');
const HummusRecipe = require('../lib');

describe('Modify', () => {
    const taskATP = 'Add transparent png';
    it(taskATP, (done) => {
        const src = path.join(__dirname, 'materials/test.pdf');
        const output = path.join(__dirname, `output/${taskATP}.pdf`);
        const wikiPng = path.join(__dirname, 'materials/wiki.png');

        const recipe = new HummusRecipe(src, output);
        recipe
            .editPage(1)
            .image(wikiPng, 'center', 50, {
                width: 300,
                height: 300,
                align: 'center center',
                opacity: 0.8,
            })
            .image(wikiPng, 'center', 'center', {
                width: 300,
                height: 300,
                align: 'center center',
                opacity: 0.1,
            })
            .endPage()
            .endPDF(done);
    });
});

chunyenHuang avatar Mar 07 '20 05:03 chunyenHuang

Screen Shot 2020-03-06 at 9 45 24 PM The new version should fix this issue for you.

chunyenHuang avatar Mar 07 '20 05:03 chunyenHuang