diff --git a/callwidget.cpp b/callwidget.cpp
index 21a6a3061a2826797270ac7eab90070344b8ba85..1edc850cee05fdb400171c2f1574eeeea1d1626e 100644
--- a/callwidget.cpp
+++ b/callwidget.cpp
@@ -1283,7 +1283,7 @@ CallWidget::CreateCopyPasteContextMenu()
         menu_->addAction(&action1);
         connect(&action1, SIGNAL(triggered()), this, SLOT(Copy()));
     }
-    if (mimeData->hasText()) {
+    if (mimeData->hasImage() || mimeData->hasUrls() || mimeData->hasText()) {
         menu_->addAction(&action2);
         connect(&action2, SIGNAL(triggered()), this, SLOT(Paste()));
     }
@@ -1294,12 +1294,36 @@ void
 CallWidget::Paste()
 {
     const QMimeData* mimeData = clipboard_->mimeData();
-    if (mimeData->hasHtml()) {
-        ui->messageView->setMessagesContent(mimeData->text());
-    } else if (mimeData->hasText()) {
-        ui->messageView->setMessagesContent(mimeData->text());
+
+    if (mimeData->hasImage()) {
+
+        //save temp data into base64 format
+        QPixmap pixmap = qvariant_cast<QPixmap>(mimeData->imageData());
+        QByteArray ba;
+        QBuffer bu(&ba);
+        bu.open(QIODevice::WriteOnly);
+        pixmap.save(&bu, "PNG");
+        auto str = QString::fromStdString(ba.toBase64().toStdString());
+
+        ui->messageView->setMessagesImageContent(str,0);
+    }
+    else if (mimeData->hasUrls()) {
+
+        QList<QUrl> urlList = mimeData->urls();
+        // extract the local paths of the files
+        for (int i = 0; i < urlList.size(); ++i) {
+            // Trim file:/// from url
+            QString filePath = urlList.at(i).toString().remove(0, 8);
+            QString fileType = QFileInfo(filePath).suffix();
+            if ( fileType == "png" || fileType == "jpg" || fileType == "jpeg" ||
+                 fileType == "gif" || fileType == "bmp") {
+                ui->messageView->setMessagesImageContent(filePath,1);
+            } else {
+                ui->messageView->setMessagesFileContent(filePath);
+            }
+        }
     } else {
-        ui->messageView->setMessagesContent(tr("Cannot display data"));
+        ui->messageView->setMessagesContent(mimeData->text());
     }
 }
 
diff --git a/messagewebview.cpp b/messagewebview.cpp
index 6fbdcd64769f0dcf6fa1c0fd663d3bc1d6966125..27fc7c57c207bbe51dc7c110f3a40b9fbdc947b2 100644
--- a/messagewebview.cpp
+++ b/messagewebview.cpp
@@ -21,10 +21,12 @@
 
 #include "messagewebview.h"
 
+#include <QCryptographicHash>
 #include <QDebug>
 #include <QDesktopServices>
 #include <QFileDialog>
 #include <QMenu>
+#include <QMessagebox>
 #include <QMimeData>
 #include <QMouseEvent>
 #include <QScrollBar>
@@ -183,9 +185,35 @@ bool MessageWebView::eventFilter(QObject *watched, QEvent *event)
     }
 }
 
-void MessageWebView::setMessagesContent(QString text)
+void MessageWebView::setMessagesContent(const QString& text)
 {
-    page()->runJavaScript(QStringLiteral("document.getElementById('message').value = '%1'").arg(text));
+    page()->runJavaScript(QStringLiteral("document.getElementById('message').value += '%1';").arg(text));
+}
+
+void
+MessageWebView::setMessagesImageContent(const QString &path, const short& type)
+{
+    if (type == 0) {
+        QString param = QString("addImage_base64('%1')").arg(path);
+        page()->runJavaScript(param);
+    } else if (type == 1) {
+        QString param = QString("addImage_path('%1')").arg(path);
+        page()->runJavaScript(param);
+    }
+}
+
+void
+MessageWebView::setMessagesFileContent(const QString &path)
+{
+    qint64 fileSize = QFileInfo(path).size();
+    QString fileName = QFileInfo(path).fileName();
+    //if file name is too large, trim it
+    if (fileName.length() > 15) {
+        fileName = fileName.remove(12, fileName.length() - 12) + "...";
+    }
+    QString param = QString("addFile_path('%1','%2','%3')")
+        .arg(path, fileName, Utils::humanFileSize(fileSize));
+    page()->runJavaScript(param);
 }
 
 void MessageWebView::copySelectedText(QClipboard* clipboard)
@@ -465,26 +493,89 @@ PrivateBridging::sendMessage(const QString& arg)
         LRCInstance::getCurrentConversationModel()->sendMessage(convUid, arg.toStdString());
     } catch (...) {
         qDebug() << "JS bridging - exception during sendMessage:" << arg;
+        return -1;
+    }
+    return 0;
+}
+
+Q_INVOKABLE int
+PrivateBridging::sendImage(const QString& arg)
+{
+    if (arg.startsWith("data:image/png;base64,")) {
+        //img tag contains base64 data, trim "data:image/png;base64," from data
+        QByteArray data = QByteArray::fromStdString(arg.toStdString().substr(22));
+        auto img_name_hash = QString::fromStdString(QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex().toStdString());
+        QString fileName = "\\img_" + img_name_hash + ".png";
+
+        QPixmap image_to_save;
+        if (!image_to_save.loadFromData(QByteArray::fromBase64(data))) {
+            qDebug().noquote() << "JS bridging - errors during loadFromData" << "\n";
+            return -1;
+        }
+
+        QString path = QString(Utils::WinGetEnv("TEMP"))  + fileName;
+        if (!image_to_save.save(path,"PNG")) {
+            qDebug().noquote() << "JS bridging - errors during QPixmap save" << "\n";
+            return -1;
+        }
+
+       try {
+            auto convUid = LRCInstance::getSelectedConvUid();
+            LRCInstance::getCurrentConversationModel()->sendFile(convUid, path.toStdString(), fileName.toStdString());
+        } catch (...) {
+            qDebug().noquote() << "JS bridging - exception during sendFile - base64 img" << "\n";
+            return -1;
+        }
+
+    } else {
+        //img tag contains file paths
+        QFileInfo fi(arg);
+        QString fileName = fi.fileName();
+        try {
+            auto convUid = LRCInstance::getSelectedConvUid();
+            LRCInstance::getCurrentConversationModel()->sendFile(convUid, arg.toStdString(), fileName.toStdString());
+        } catch (...) {
+            qDebug().noquote() << "JS bridging - exception during sendFile - image from path" << "\n";
+            return -1;
+        }
     }
     return 0;
 }
 
 Q_INVOKABLE int
-PrivateBridging::sendFile()
+PrivateBridging::sendFile(const QString&path)
 {
     qDebug() << "JS bridging - MessageWebView::sendFile";
-    QString filePath = QFileDialog::getOpenFileName((QWidget*)this->parent(), tr("Choose File"), "", tr("Files") + " (*)");
-    QFileInfo fi(filePath);
+    QFileInfo fi(path);
     QString fileName = fi.fileName();
     try {
         auto convUid = LRCInstance::getSelectedConvUid();
-        LRCInstance::getCurrentConversationModel()->sendFile(convUid, filePath.toStdString(), fileName.toStdString());
+        LRCInstance::getCurrentConversationModel()->sendFile(convUid, path.toStdString(), fileName.toStdString());
     } catch (...) {
         qDebug() << "JS bridging - exception during sendFile";
     }
     return 0;
 }
 
+Q_INVOKABLE int
+PrivateBridging::selectFile()
+{
+    QString filePath = QFileDialog::getOpenFileName((QWidget*)this->parent(), tr("Choose File"), "", tr("Files") + " (*)");
+    if (filePath.length() == 0)
+        return 0;
+    QString fileType = QFileInfo(filePath).suffix();
+
+    if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) {
+        if (fileType == "png" || fileType == "jpg" || fileType == "jepg" || fileType == "gif" || fileType == "bmp") {
+            messageView->setMessagesImageContent(filePath,1);
+            return 0;
+        }
+        messageView->setMessagesFileContent(filePath);
+        return 0;
+    }
+    return -1;
+}
+
 Q_INVOKABLE int
 PrivateBridging::acceptInvitation()
 {
diff --git a/messagewebview.h b/messagewebview.h
index 262b911ca66eaa93106ba0ac6866cc2c04027916..919f0e2fb7949c4a955005f44a5c49f6784c6865 100644
--- a/messagewebview.h
+++ b/messagewebview.h
@@ -39,7 +39,9 @@ public:
     Q_INVOKABLE int acceptFile(const QString& arg);
     Q_INVOKABLE int refuseFile(const QString& arg);
     Q_INVOKABLE int sendMessage(const QString& arg);
-    Q_INVOKABLE int sendFile();
+    Q_INVOKABLE int sendImage(const QString& arg);
+    Q_INVOKABLE int sendFile(const QString& arg);
+    Q_INVOKABLE int selectFile();
     Q_INVOKABLE int log(const QString& arg);
     Q_INVOKABLE int acceptInvitation();
     Q_INVOKABLE int refuseInvitation();
@@ -78,8 +80,10 @@ public:
                        const std::string& contactUri = "",
                        const std::string& contactId = "");
     void setMessagesVisibility(bool visible);
-    void setMessagesContent(QString text);
+    void setMessagesContent(const QString& text);
     void copySelectedText(QClipboard* clipboard);
+    void setMessagesImageContent(const QString& path, const short &type);
+    void setMessagesFileContent(const QString& path);
     bool textSelected();
     void runJsText();
 
@@ -92,7 +96,6 @@ protected:
     void resizeEvent(QResizeEvent *event);
     bool eventFilter(QObject *watched, QEvent *event);
 
-
 signals:
     void conversationRemoved();
     void messagesCleared();
diff --git a/utils.cpp b/utils.cpp
index 2db4234d1ac3a7ea55e89167c880486620a2501a..dd1929b6a1b2429d2af28318dbead417dbef4933 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -779,3 +779,23 @@ Utils::swapQListWidgetItems(QListWidget* list, bool down)
     down ? list->insertItem(currIndex, temp) : list->insertItem(otherIndex, current);
     down ? list->insertItem(otherIndex, current) : list->insertItem(currIndex, temp);
 }
+
+QString
+Utils::humanFileSize(qint64 fileSize)
+{
+    float fileSizeF = static_cast<float>(fileSize);
+    float thresh = 1024;
+
+    if(abs(fileSizeF) < thresh) {
+        return QString::number(fileSizeF) + " B";
+    }
+    QString units[] = { "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
+    int unit_position = -1;
+    do {
+        fileSizeF /= thresh;
+        ++unit_position;
+    } while (abs(fileSizeF) >= thresh && unit_position < units->size() - 1);
+    //Round up to two decimal
+    fileSizeF = roundf(fileSizeF * 100) / 100;
+    return QString::number(fileSizeF) + " " + units[unit_position];
+}
diff --git a/utils.h b/utils.h
index e66aef8504d7da1094995650f253febd17f21698..eb5512716028f2e3c19e7ac798488e3976ff3b21 100644
--- a/utils.h
+++ b/utils.h
@@ -113,6 +113,9 @@ lrc::api::conversation::Info getConversationFromUid(const std::string & convUid,
 // misc helpers
 void swapQListWidgetItems(QListWidget* list, bool down = true);
 
+// Byte to human readable size
+QString humanFileSize(qint64 fileSize);
+
 template <typename Func1, typename Func2>
 void
 oneShotConnect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, Func1 signal, Func2 slot)
@@ -190,4 +193,4 @@ indexInVector(const std::vector<T>& vec, const T& item)
     }
     return std::distance(vec.begin(), it);
 }
-}
\ No newline at end of file
+}
diff --git a/web/chatview.css b/web/chatview.css
index 0052dd9c94f07670525118ea4fca0bdbf956f160..c02d1b2663bb771a6e57172b508a2eedab89ca3a 100644
--- a/web/chatview.css
+++ b/web/chatview.css
@@ -333,6 +333,143 @@ a:hover {
     pointer-events: none;
 }
 
+#file_image_send_container {
+    visibility: hidden;
+    position: fixed;
+    bottom: var(--messagebar-size);
+    z-index: 1;
+    display: flex;
+    justify-content: flex-start;
+    left: 0;
+    right: 0;
+    height: 8em;
+    /*border-top-left-radius: 25px;
+    border-top-right-radius: 25px;*/
+    border: 2px solid lightgray;
+    padding: 20px;
+    border-bottom: none;
+    background-color: #cfdbdd;
+    overflow-x: overlay;
+}
+
+    #file_image_send_container::-webkit-scrollbar{
+        height: 10px;
+    }
+
+    #file_image_send_container::after {
+        /*Create the margins with pseudo-elements*/
+        /*to solve overflow:scroll and The Right Padding Problem*/
+        content: ' ';
+        min-width: 20px;
+    }
+
+.img_wrapper {
+    position: relative;
+    max-width: 65px;
+    min-width: 65px;
+    max-height: 80px;
+    border: 3px solid rgba(255,255,255,0);
+    padding: 30px;
+    border-radius: 20px;
+    background-color: #cfdbdd;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin: 5px;
+}
+
+/* Make the image responsive */
+    .img_wrapper img {
+        height: 118px;
+        min-width: 131px;
+        object-fit: cover;
+        border-radius: 20px;
+    }
+
+/* Style the button and place it at the top right corner of the image */
+    .img_wrapper .btn {
+        position: absolute;
+        color: #fff;
+        border: 1px solid #AEAEAE;
+        border-radius: 40%;
+        background: rgba(96,95,97,0.5);
+        font-size: 10px;
+        font-weight: bold;
+        top: -5%;
+        right: -5%;
+    }
+
+        .img_wrapper .btn:hover {
+            background-color: lightgray;
+        }
+
+        .img_wrapper .btn:focus {
+            outline: none;
+            color: black;
+        }
+
+.file_wrapper {
+    position: relative;
+    max-width: 65px;
+    min-width: 65px;
+    max-height: 80px;
+    border: 3px solid rgba(255,255,255,0);
+    padding: 30px;
+    border-radius: 20px;
+    background-color: white;
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    margin: 5px;
+    font-family: sans-serif;
+}
+    /* Style the button and place it at the top right corner of the image */
+    .file_wrapper .btn {
+        position: absolute;
+        color: #fff;
+        border: 1px solid #AEAEAE;
+        border-radius: 40%;
+        background: rgba(96,95,97,0.5);
+        font-size: 10px;
+        font-weight: bold;
+        top: -5%;
+        right: -5%;
+    }
+
+        .file_wrapper .btn:hover {
+            background-color: lightgray;
+        }
+
+        .file_wrapper .btn:focus {
+            outline: none;
+            color: black;
+        }
+
+    .file_wrapper .svg-icon {
+        position: absolute;
+        max-width: 2em;
+        max-height: 25px;
+        margin-right: 2em;
+        top: 8%;
+        left: 1px;
+    }
+
+        .file_wrapper .svg-icon path,
+        .file_wrapper .svg-icon polygon,
+        .file_wrapper .svg-icon rect {
+            fill: #000000;
+        }
+
+        .file_wrapper .svg-icon circle {
+            stroke: #4691f6;
+            stroke-width: 1;
+        }
+    .file_wrapper .fileinfo {
+        position: absolute;
+        top: 30%;
+        left: 7%;
+    }
+
 #back_to_bottom_button {
     visibility: hidden;
     margin: auto;
diff --git a/web/chatview.html b/web/chatview.html
index 0333c61d998a13249ac6871314ae58620ff73552..5263398357381fce28ffbd8a02123b46dabf19d9 100644
--- a/web/chatview.html
+++ b/web/chatview.html
@@ -43,8 +43,9 @@
         <div id="back_to_bottom_button_container">
             <div id="back_to_bottom_button" onclick="back_to_bottom()">Jump to latest &#9660;</div>
         </div>
+        <div id="file_image_send_container"></div>
         <div id="sendMessage">
-            <div class="nav-button action-button" onclick="sendFile()" title="Send File">
+            <div class="nav-button action-button" onclick="selectFile()" title="Send File">
                 <svg class="svgicon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
                     <path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z" />
                     <path d="M0 0h24v24H0z" fill="none" />
diff --git a/web/chatview.js b/web/chatview.js
index 0ccd0cd49d95e935cf8d842952fa9fe566ee3879..f923e214829d041d1c10af4d552ba9459217a621 100644
--- a/web/chatview.js
+++ b/web/chatview.js
@@ -32,6 +32,8 @@ const inviteImage       = document.getElementById("invite_image")
 const invitationText    = document.getElementById("text")
 var   messages          = document.getElementById("messages")
 var   backToBottomBtn   = document.getElementById("back_to_bottom_button")
+var   sendContainer     = document.getElementById("file_image_send_container")
+
 
 /* States: allows us to avoid re-doing something if it isn't meaningful */
 var displayLinksEnabled = true
@@ -273,11 +275,31 @@ function formatDate(date) {
  */
 function sendMessage()
 {
+    //send image in sendContainer
+    var data_to_send = sendContainer.innerHTML;
+    var imgSrcExtract = new RegExp('<img src="(.*?)">', 'g');
+    var fileSrcExtract = new RegExp('<div class="file_wrapper" data-path="(.*?)">', 'g');
+
+    var img_src;
+    while ((img_src = imgSrcExtract.exec(data_to_send)) !== null ) {
+        window.jsbridge.sendImage(img_src[1]);
+    }
+
+    var file_src;
+    while ((file_src = fileSrcExtract.exec(data_to_send)) !== null) {
+        window.jsbridge.sendFile(file_src[1]);
+    }
+
+    sendContainer.innerHTML = "";
+    sendContainer.style.visibility = "hidden";
+    reduce_send_container();
+
     var message = messageBarInput.value
     if (message.length > 0) {
         messageBarInput.value = ""
         window.jsbridge.sendMessage(message)
     }
+
 }
 
 /* exported acceptInvitation */
@@ -293,12 +315,6 @@ function blockConversation() {
     window.jsbridge.blockConversation()
 }
 
-/* exported sendFile */
-function sendFile()
-{
-    window.jsbridge.sendFile();
-}
-
 /**
  * Convert text to HTML.
  */
@@ -1633,3 +1649,109 @@ function isTextSelected() {
         return true;
     return false;
 }
+
+/* exported selectFile - sselect files from Qt */
+function selectFile() {
+
+    window.jsbridge.selectFile();
+    //js or qt
+}
+
+/**
+ * add file (local file) to message area
+ */
+function addFile_path(path, name, size) {
+    var html = '<div class="file_wrapper" data-path=' + path + '>' +
+        '<svg class="svg-icon" viewBox="0 0 20 20">' +
+        '<path fill = "none" d = "M17.222,5.041l-4.443-4.414c-0.152-0.151-0.356-0.235-0.571-0.235h-8.86c-0.444,0-0.807,0.361-0.807,0.808v17.602c0,0.448,0.363,0.808,0.807,0.808h13.303c0.448,0,0.808-0.36,0.808-0.808V5.615C17.459,5.399,17.373,5.192,17.222,5.041zM15.843,17.993H4.157V2.007h7.72l3.966,3.942V17.993z" ></path>' +
+        '<path fill="none" d="M5.112,7.3c0,0.446,0.363,0.808,0.808,0.808h8.077c0.445,0,0.808-0.361,0.808-0.808c0-0.447-0.363-0.808-0.808-0.808H5.92C5.475,6.492,5.112,6.853,5.112,7.3z"></path>' +
+        '<path fill="none" d="M5.92,5.331h4.342c0.445,0,0.808-0.361,0.808-0.808c0-0.446-0.363-0.808-0.808-0.808H5.92c-0.444,0-0.808,0.361-0.808,0.808C5.112,4.97,5.475,5.331,5.92,5.331z"></path>' +
+        '<path fill="none" d="M13.997,9.218H5.92c-0.444,0-0.808,0.361-0.808,0.808c0,0.446,0.363,0.808,0.808,0.808h8.077c0.445,0,0.808-0.361,0.808-0.808C14.805,9.58,14.442,9.218,13.997,9.218z"></path>' +
+        '<path fill="none" d="M13.997,11.944H5.92c-0.444,0-0.808,0.361-0.808,0.808c0,0.446,0.363,0.808,0.808,0.808h8.077c0.445,0,0.808-0.361,0.808-0.808C14.805,12.306,14.442,11.944,13.997,11.944z"></path>' +
+        '<path fill="none" d="M13.997,14.67H5.92c-0.444,0-0.808,0.361-0.808,0.808c0,0.447,0.363,0.808,0.808,0.808h8.077c0.445,0,0.808-0.361,0.808-0.808C14.805,15.032,14.442,14.67,13.997,14.67z"></path>' +
+        '</svg >' +
+        '<div class="fileinfo">' +
+        '<p>' + name + '</p>' +
+        '<p>' + size + '</p>' +
+        '</div >' +
+        '<button class="btn" onclick="remove(this)">X</button>' +
+        '</div >';
+    // At first, visiblity can empty
+    if (sendContainer.style.visibility.length == 0 || sendContainer.style.visibility == "hidden") {
+        grow_send_container();
+        sendContainer.style.visibility = "visible";
+    }
+    //add html here since display is set to flex, image will change accordingly
+    sendContainer.innerHTML += html;
+}
+
+/**
+ * add image (base64 array) to message area
+ */
+function addImage_base64(base64) {
+
+    var html =  '<div class="img_wrapper">' +
+                '<img src="data:image/png;base64,' + base64 + '"/>' +
+                '<button class="btn" onclick="remove(this)">X</button>' +
+                '</div >';
+    // At first, visiblity can empty
+    if (sendContainer.style.visibility.length == 0 || sendContainer.style.visibility == "hidden") {
+        grow_send_container();
+        sendContainer.style.visibility = "visible";
+    }
+    //add html here since display is set to flex, image will change accordingly
+    sendContainer.innerHTML += html;
+}
+
+/**
+ * add image (image path) to message area
+ */
+function addImage_path(path) {
+
+
+    var html = '<div class="img_wrapper">' +
+               '<img src="' + path + '"/>' +
+               '<button class="btn" onclick="remove(this)">X</button>' +
+               '</div >';
+    // At first, visiblity can empty
+    if (sendContainer.style.visibility.length == 0 || sendContainer.style.visibility == "hidden") {
+        grow_send_container();
+        sendContainer.style.visibility = "visible";
+    }
+    //add html here since display is set to flex, image will change accordingly
+    sendContainer.innerHTML += html;
+}
+
+/**
+ * This function adjusts the body paddings so that that the file_image_send_container doesn't
+ * overlap messages when it grows.
+ */
+/* exported grow_send_container */
+function grow_send_container() {
+    exec_keeping_scroll_position(function () {
+        var msgbar_size = window.getComputedStyle(document.body).getPropertyValue("--messagebar-size");
+        document.body.style.paddingBottom = (parseInt(msgbar_size) + 158).toString() + "px";
+        //6em
+    }, [])
+}
+
+/**
+ * This function adjusts the body paddings so that that the file_image_send_container will hide
+ * and recover padding bottom
+ */
+/* exported grow_send_container */
+function reduce_send_container() {
+    exec_keeping_scroll_position(function () {
+        document.body.style.paddingBottom = (parseInt(document.body.style.paddingBottom) - 158).toString() + "px";
+        //6em
+    }, [])
+}
+
+// Remove current cancel button division  and hide the sendContainer
+function remove(e) {
+    e.parentNode.parentNode.removeChild(e.parentNode);
+    if (sendContainer.innerHTML.length == 0) {
+        reduce_send_container();
+        sendContainer.style.visibility = "hidden";
+    }
+}