# Create a dynamic membership card on APEX

In this post, I will demonstrate how to dynamically embed data into images and download them. For this demo, I will be creating a membership card by adding the membership details to a pre-defined template.

First, let's add the membership template image to the static application files. I will use a file I created using canva.com  

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1681291566527/42a7e4ba-c3a3-4edd-9a3c-a56ea543c4e5.png align="center")

  
Open your APEX application and go to **Shared Components**.

1. Click on **Static Application Files**.
    
2. Click the **Create** button and upload the image file.
    
3. We are going to need later the file reference. (e.g. #APP\_FILES#membership\_canvas.png)
    

To store the data, I created a table named "membership\_card", which includes the following details:  

```sql
create sequence membership_card_seq;

create table membership_card (
    id                             number default on null membership_card_seq.NEXTVAL 
                                   constraint membership_card_id_pk primary key,
    name                           varchar2(255),
    membership_number              number,
    image                          blob
)
;    
```

We are now able to create an APEX page that generates the card. The page will include a select list item (P2\_NAME) that allows us to choose the data from the membership by using the following query as the source.  

```sql
select name,
       id
from membership_card
order by 1 
```

To display the image, we require a standard region where we can add the following code to load the image that was previously added to the shared components. But we don't need to show it, so we will add style="display:none".  

```xml
<img id="img_membership_card" style="display:none" src="#APP_FILES#membership_canvas.png" crossorigin="anonymous"/>
<canvas id="canvas" />
```

The next step is to create an AJAX callback process for retrieving the membership data.

```sql
DECLARE
  ln_error_code NUMBER;
  lv_error_msg  VARCHAR2(4000);
BEGIN
  FOR i IN 1..apex_application.g_f01.count
  LOOP
    FOR x IN
    (
           SELECT mb.name,
                  to_char(mb.expiration_date,'fmDay, fmDD fmMonth, YYYY') as expiration_date ,
                  substr(membership_number,1,4)||' '||substr(membership_number,5,4)||' '||substr(membership_number,9,4)||' '||substr(membership_number,13,4)  as membership_number, 
                  apex_web_service.blob2clobbase64(p_blob => mb.image_file) as img
           FROM   membership_card mb
           WHERE  mb.id = apex_application.g_f01(i))
    LOOP
      apex_json.open_object;
      apex_json.Open_array('output');
      apex_json.open_object;
      apex_json.WRITE('membershipNumber',x.membership_number);
      apex_json.WRITE('expirationDate',x.expiration_date);
      apex_json.WRITE('name',x.name);
      apex_json.WRITE('image',x.img);
      apex_json.close_object;
      apex_json.close_array;
      apex_json.close_object;
    END LOOP;
  END LOOP;
EXCEPTION
WHEN OTHERS THEN
  apex_json.open_object;
  apex_json.Open_array('output');
  apex_json.open_object;
  apex_json.WRITE('lv_error_code', 0);
  apex_json.WRITE('lv_error_msg', SQLERRM);
  apex_json.close_object;
  apex_json.close_array;
  apex_json.close_object;
END;
```

Note that we are utilizing the apex\_web\_service.blob2clobbase64 function to convert the member picture blob into clob base64 format, which enables us to easily use it within the JavaScript code.  
  
Now let's create the JavaScript code that will retrieve the data, embed it into the template image, and generate a new image.  
  

```javascript
function generateCard(id) {
    /* get the template image size and create a canvas */
    var canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d");
    canvas.width = $("#img_membership_card").width();
    canvas.crossOrigin = "Anonymous";
    canvas.height = $("#img_membership_card").height();

    /* load the membership data calling the AJAX process */

    apex.server.process(
        "LOAD_DATA",
        {
            f01: id,
            pageItems: "#P2_NAME"
        },
        {
            success: function (pData) {
                let membershipNumber,
                    name,
                    expirationDate,
                    image,
                    img = new Image();
                img.onload = function () {
                    ctx.drawImage(this, 450, 20, 102, 100);
                };

                /* get the membership data returned by the AJAX   callback process */
                image = pData.output[0].image;
                membershipNumber = pData.output[0].membershipNumber;
                name = pData.output[0].name;
                expirationDate = pData.output[0].expirationDate;

                /* print the data onto the canvas */

                img.src = "data:image/png;base64," + image;

                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.drawImage($("#img_membership_card").get(0), 0, 0);

                ctx.font = "18pt monospace";
                ctx.fillStyle = "#ffffff";
                ctx.fillText(membershipNumber, 40, 200);

                ctx.font = "12pt Arial";
                ctx.fillStyle = "#000000";
                ctx.fillText(name, 120, 245);
                ctx.fillText(expirationDate, 120, 280);
            },
        }
    );
}
/* function to download the image */

function downloadCard() {
    var link = document.createElement("a");
    link.download = "membership_card.jpg";
    link.href = document.getElementById("canvas").toDataURL();
    link.click();
}
```

Now, we simply need to create a dynamic action fired by the select list to invoke the JavaScript mentioned above.

1. Right-click on the P2\_NAME item and select Create Dynamic Action. That should look as follows  
    Name: Print Membership Card
    
    Event: Change
    
    Selection Type: Item
    
    Item(s): P2\_NAME  
    
2. Create an Execute Javascript Code action and add the code below
    

```javascript
generateCard(apex.item("P2_NAME").getValue());
```

We can now run the page. When we select a value from the select list, the template image is populated with the membership data generating a new image.  

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1681296939430/bf0bec2a-0eb0-49ea-9df7-a9fc986812b7.png align="center")

To download the membership card, we can create a button with the action "Redirect to URL" and add the following code as the target.  

```javascript
javascript:downloadCard();
```
