Add in/out transformation for Binary

Rational

It happens that we want to apply some transformation at the input or output of a binary.
For example, we would like to implement an encryption on some Binary field of Tryton. We do not think it is common enough to be in the core. But encryption can be seen as just encrypt the input and decrypt the output.
Another example is to resize images. The user may enter an image too big and instead of resize it on server side (require to upload the big image), it could be done on client side. And instead of resize it could be convert into a different format or compress it etc.

Proposal

The idea is to add two optional attributes to the Binary definition: transform_in and transform_out. They will contain a list of transformations to apply sequentially like pipes (output of the previous is the input of the next). The transform_in is applied when the user set data and transform_out when the data are retrieved.
The transform function are defined on the client side with plugins and registered into a BinaryField class attribute which is a dictionary. The API of the transform function is to take the data as first argument. Extra argument can be passed if the item of the list is not a string but an iterable. In this case, the first item is the name of the function, the second is the *args and the third the **kwargs. The arguments are evaluated as PYSON statement using the record.

Example

On model:

format = fields.Selection([('jpg', "JPEG"), ('png', "PNG")], "Format")
data = fields.Binary(
    "Data",
    transform_in=['resize_80', ['convert', (Eval('format', 'jpg'),)]],
    transform_out=[['add_watermark, (), {'title': "Draft"}]],
    )

Client plugin:

from tryton.gui.window.view_form.model.fields import BinaryField

def convert(input, format='jpg'):
    ...

BinaryField.transforms['convert'] = convert

Implementation

2 Likes

Wow :smile: … A few days back I just had a chat on adding photo’s as attachments. But the newest smartphones and tablets are making photos with enormous file-sizes. So we talked about what we could do to resize the photos.
Are the transform function executed in the client? Or will the server execute the transform function? I can imagine that the server should do it. Because you then have to write the transform function once instead of twice (Python and Javascript)

They are executed on the client side.

It makes sense when you’re thinking about the use-case of binary fields containing sensible data that should be cryptographically transformed on the client-side (to prevent people on server side to access this data).

But yes indeed it requires to write twice the same functionality (we already do that for the client :wink:) which might or might not be a big problem.

That absolutely makes sense. I can even imagine a use case of adding a PDF and validate the data in the PDF (be sure it’s the right PDF, or even digitally sign it) before you can proceed. Also the use case of the images Cédric imagined also makes sense.
But it would be nice if the developer of a module can decide to do the transformation on the client-side or the server-side. Because the example of the PDF can also be done at the server-side which maybe makes more sense. Also when you use scripts to do things it can be easier to do it on the server-side.

But that is already possible using a Function field with setter or overriding create/write methods.

As usual, any constraint should always be enforced on server-side. The validation, you are talking about, can be done using the ModelStorage.validate method.
Here, this feature provides two additional features:

  • in case of data reduction (like resizing), it reduces the bandwidth usage.
  • in case of encryption, it obfuscates the data for the server side (better privacy).

Thanks, it’s now crystal clear to me what I can do on the server-side :smile: I already knew about Function fields and overriding, but didn’t think of the validate method. I just thought this feature would be another option to do things. But it’s now clear that the ‘to do things’ are at client side.

A post was split to a new topic: Is it possible to add zooming on image widget