diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
index 016b8d9e98c8d7a83c1ede405b736cd431eb03d5..8b0a0588ca3ac0c1ef69192954e034edd75a8290 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
@@ -132,6 +132,8 @@ public final class FastRGridExternalLookup {
                 return LCircle.create();
             case "L_points":
                 return LPoints.create();
+            case "L_raster":
+                return LRaster.create();
 
             // Bounds primitive:
             case "L_rectBounds":
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java
index 48e5ca2d58fcd3da897908e0acc74003041ee96d..adba03004cfa945ccba56231ed7b4f4140995caa 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GPar.java
@@ -18,7 +18,6 @@ import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDataAtMod;
 import java.util.Arrays;
 import java.util.function.Function;
 
-import com.oracle.truffle.r.library.fastrGrid.GridState.GridPalette;
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext;
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContextDefaults;
 import com.oracle.truffle.r.library.fastrGrid.device.GridColor;
@@ -26,7 +25,6 @@ import com.oracle.truffle.r.library.fastrGrid.device.GridDevice;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -267,21 +265,7 @@ public final class GPar {
 
         private GridColor getGridColor(int listIndex) {
             Object value = data[listIndex];
-            GridColor color = getPaletteColor(value);
-            if (color != null) {
-                return color;
-            }
-
-            String strValue = null;
-            if (value instanceof String) {
-                strValue = (String) value;
-            } else if (value instanceof RAbstractStringVector && ((RAbstractStringVector) value).getLength() > 0) {
-                strValue = ((RAbstractStringVector) value).getDataAt(index % ((RAbstractStringVector) value).getLength());
-            } else {
-                return GridColor.TRANSPARENT;
-            }
-
-            color = GridColorUtils.gridColorFromString(strValue);
+            GridColor color = GridColorUtils.getColor(value, index);
             double alpha = asDouble(data[GP_ALPHA], index);
             if (alpha != 1.) {
                 int newAlpha = Math.min(255, (int) (alpha * ((color.getAlpha() / 255.0) * 255)));
@@ -291,44 +275,6 @@ public final class GPar {
             }
         }
 
-        private GridColor getPaletteColor(Object colorIdIn) {
-            Object colorId = colorIdIn;
-            if (colorId instanceof RAbstractVector) {
-                RAbstractVector vec = (RAbstractVector) colorId;
-                colorId = vec.getDataAtAsObject(index % vec.getLength());
-            }
-            int paletteIdx = RRuntime.INT_NA;
-            if (colorId instanceof Integer) {
-                paletteIdx = (int) colorId;
-            } else if (colorId instanceof Double && !RRuntime.isNA((Double) colorId)) {
-                paletteIdx = (int) (double) colorId;
-            } else if (colorId instanceof String && !RRuntime.isNA((String) colorId)) {
-                paletteIdx = paletteIdxFromString((String) colorId);
-            } else if (colorId instanceof Byte && !RRuntime.isNA((byte) colorId)) {
-                paletteIdx = (int) (byte) colorId;
-            }
-            if (RRuntime.isNA(paletteIdx)) {
-                return null;
-            }
-            if (paletteIdx < 0) {
-                throw RError.error(RError.NO_CALLER, Message.GENERIC, Utils.stringFormat("numerical color values must be >= 0, found %d", paletteIdx));
-            }
-            if (paletteIdx == 0) {
-                return GridColor.TRANSPARENT;
-            }
-            GridPalette palette = GridContext.getContext().getGridState().getPalette();
-            GridColor result = palette.colors[(paletteIdx - 1) % palette.colors.length];
-            return result; // one based index
-        }
-
-        private int paletteIdxFromString(String colorId) {
-            try {
-                return Integer.parseInt(colorId, 10);
-            } catch (NumberFormatException ex) {
-                return RRuntime.INT_NA;
-            }
-        }
-
         private static final byte[] DASHED_LINE = new byte[]{4, 4};
         private static final byte[] DOTTED_LINE = new byte[]{1, 3};
         private static final byte[] DOTDASH_LINE = new byte[]{1, 3, 4, 3};
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java
index 1ec25bf728686609acfa0232c2515f4f09818363..c751e57f43cddaab2e1f1f8cf82918e246fffff6 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java
@@ -18,6 +18,10 @@ import com.oracle.truffle.r.library.fastrGrid.GridState.GridPalette;
 import com.oracle.truffle.r.library.fastrGrid.device.GridColor;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public final class GridColorUtils {
 
@@ -27,6 +31,28 @@ public final class GridColorUtils {
         // only static members
     }
 
+    /**
+     * Converts given object into {@link GridColor}. The object may be a vector, in which case the
+     * index modulo its size is used to select element of that vector.
+     */
+    public static GridColor getColor(Object value, int index) {
+        GridColor color = GridColorUtils.getPaletteColor(value, index);
+        if (color != null) {
+            return color;
+        }
+
+        String strValue = null;
+        if (value instanceof String) {
+            strValue = (String) value;
+        } else if (value instanceof RAbstractStringVector && ((RAbstractStringVector) value).getLength() > 0) {
+            strValue = ((RAbstractStringVector) value).getDataAt(index % ((RAbstractStringVector) value).getLength());
+        } else {
+            return GridColor.TRANSPARENT;
+        }
+
+        return gridColorFromString(strValue);
+    }
+
     public static GridPalette getDefaultPalette() {
         if (defaultPalette == null) {
             // Note: default palette copied from GNU R
@@ -105,6 +131,44 @@ public final class GridColorUtils {
         return isNormalized ? synonym : synonym.replace(" ", "").toLowerCase(Locale.ROOT);
     }
 
+    private static GridColor getPaletteColor(Object colorIdIn, int index) {
+        Object colorId = colorIdIn;
+        if (colorId instanceof RAbstractVector) {
+            RAbstractVector vec = (RAbstractVector) colorId;
+            colorId = vec.getDataAtAsObject(index % vec.getLength());
+        }
+        int paletteIdx = RRuntime.INT_NA;
+        if (colorId instanceof Integer) {
+            paletteIdx = (int) colorId;
+        } else if (colorId instanceof Double && !RRuntime.isNA((Double) colorId)) {
+            paletteIdx = (int) (double) colorId;
+        } else if (colorId instanceof String && !RRuntime.isNA((String) colorId)) {
+            paletteIdx = paletteIdxFromString((String) colorId);
+        } else if (colorId instanceof Byte && !RRuntime.isNA((byte) colorId)) {
+            paletteIdx = (int) (byte) colorId;
+        }
+        if (RRuntime.isNA(paletteIdx)) {
+            return null;
+        }
+        if (paletteIdx < 0) {
+            throw RError.error(RError.NO_CALLER, Message.GENERIC, Utils.stringFormat("numerical color values must be >= 0, found %d", paletteIdx));
+        }
+        if (paletteIdx == 0) {
+            return GridColor.TRANSPARENT;
+        }
+        GridPalette palette = GridContext.getContext().getGridState().getPalette();
+        GridColor result = palette.colors[(paletteIdx - 1) % palette.colors.length];
+        return result; // one based index
+    }
+
+    private static int paletteIdxFromString(String colorId) {
+        try {
+            return Integer.parseInt(colorId, 10);
+        } catch (NumberFormatException ex) {
+            return RRuntime.INT_NA;
+        }
+    }
+
     private static final class NamesHolder {
         private static final HashMap<String, Object> NAMES = new HashMap<>(700);
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRaster.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRaster.java
new file mode 100644
index 0000000000000000000000000000000000000000..6741f4f107555b6fb103548a500f3f2b15bbba80
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRaster.java
@@ -0,0 +1,127 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 2001-3 Paul Murrell
+ * Copyright (c) 1998-2013, The R Core Team
+ * Copyright (c) 2017, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.fastrGrid;
+
+import static com.oracle.truffle.r.library.fastrGrid.GridUtils.getDataAtMod;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext;
+import com.oracle.truffle.r.library.fastrGrid.device.GridDevice;
+import com.oracle.truffle.r.library.fastrGrid.device.GridDevice.ImageInterpolation;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+
+/**
+ * Draws a raster image at specified position. The image may be matrix of integers, in which case it
+ * is used directly, or matrix of any valid color representation, e.g. strings with color codes.
+ */
+public abstract class LRaster extends RExternalBuiltinNode.Arg8 {
+    private static final String NATIVE_RASTER_CLASS = "nativeRaster";
+
+    static {
+        Casts casts = new Casts(LRaster.class);
+        casts.arg(0).mustBe(abstractVectorValue());
+        casts.arg(1).mustBe(abstractVectorValue());
+        casts.arg(2).mustBe(abstractVectorValue());
+        casts.arg(3).mustBe(abstractVectorValue());
+        casts.arg(4).mustBe(abstractVectorValue());
+        casts.arg(5).mustBe(numericValue()).asDoubleVector();
+        casts.arg(6).mustBe(numericValue()).asDoubleVector();
+        casts.arg(7).mustBe(logicalValue()).asLogicalVector();
+    }
+
+    public static LRaster create() {
+        return LRasterNodeGen.create();
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object doRaster(RAbstractVector raster, RAbstractVector xVec, RAbstractVector yVec, RAbstractVector widthVec, RAbstractVector heightVec, RAbstractDoubleVector hjust, RAbstractDoubleVector vjust,
+                    RAbstractLogicalVector interpolate) {
+        GridContext ctx = GridContext.getContext();
+        GridDevice dev = ctx.getCurrentDevice();
+
+        RList currentVP = ctx.getGridState().getViewPort();
+        GPar gpar = GPar.create(ctx.getGridState().getGpar());
+        ViewPortTransform vpTransform = ViewPortTransform.get(currentVP, dev);
+        ViewPortContext vpContext = ViewPortContext.fromViewPort(currentVP);
+        UnitConversionContext conversionCtx = new UnitConversionContext(vpTransform.size, vpContext, dev, gpar);
+
+        if (vpTransform.rotationAngle != 0) {
+            throw RInternalError.unimplemented("L_raster with view-port rotation.");
+        }
+
+        int[] pixels;
+        if (raster instanceof RAbstractIntVector && isNativeRaster(raster)) {
+            pixels = ((RAbstractIntVector) raster).materialize().getDataWithoutCopying();
+        } else {
+            int rasterLen = raster.getLength();
+            pixels = new int[rasterLen];
+            for (int i = 0; i < rasterLen; i++) {
+                pixels[i] = GridColorUtils.getColor(raster, i).getRawValue();
+            }
+        }
+
+        Object dimsObj = raster.getAttr(RRuntime.DIM_ATTR_KEY);
+        if (!(dimsObj instanceof RAbstractIntVector)) {
+            throw RInternalError.shouldNotReachHere("Dims attribute should always be integer vector.");
+        }
+        RAbstractIntVector dims = (RAbstractIntVector) dimsObj;
+        if (dims.getLength() != 2) {
+            throw error(Message.GENERIC, "L_raster dims attribute is not of size 2");
+        }
+
+        int length = GridUtils.maxLength(xVec, yVec, widthVec, heightVec);
+        for (int i = 0; i < length; i++) {
+            Size size = Size.fromUnits(widthVec, heightVec, i, conversionCtx);
+            Point origLoc = Point.fromUnits(xVec, yVec, i, conversionCtx);
+            Point transLoc = TransformMatrix.transLocation(origLoc, vpTransform.transform);
+            Point loc = transLoc.justify(size, getDataAtMod(hjust, i), getDataAtMod(vjust, i));
+            ImageInterpolation interpolation = getInterpolation(interpolate, i);
+            dev.drawRaster(loc.x, loc.y, size.getWidth(), size.getHeight(), pixels, dims.getDataAt(1), interpolation);
+        }
+        return RNull.instance;
+    }
+
+    private static ImageInterpolation getInterpolation(RAbstractLogicalVector interpolation, int idx) {
+        if (RRuntime.fromLogical(interpolation.getDataAt(idx % interpolation.getLength()))) {
+            return ImageInterpolation.LINEAR_INTERPOLATION;
+        }
+        return ImageInterpolation.NEAREST_NEIGHBOR;
+    }
+
+    private static boolean isNativeRaster(RAbstractVector vec) {
+        RStringVector clazz = vec.getClassAttr();
+        if (clazz == null) {
+            return false;
+        }
+        for (int i = 0; i < clazz.getLength(); i++) {
+            if (clazz.getDataAt(i).equals(NATIVE_RASTER_CLASS)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java
index 0515ded9b5bf94c49d13a8092c7063d0fbaee6bf..87ed10b88a6d2d714f9d08448f05f3b08b49c558 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridDevice.java
@@ -30,6 +30,20 @@ public interface GridDevice {
     int DEFAULT_WIDTH = 720;
     int DEFAULT_HEIGHT = 720;
 
+    /**
+     * Raster image resizing methods.
+     */
+    enum ImageInterpolation {
+        /**
+         * The device should use linear interpolation if available.
+         */
+        LINEAR_INTERPOLATION,
+        /**
+         * The device should use the nearest neighbor interpolation if available.
+         */
+        NEAREST_NEIGHBOR,
+    }
+
     void openNewPage();
 
     /**
@@ -80,6 +94,13 @@ public interface GridDevice {
 
     void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius);
 
+    /**
+     * Draws a raster image at specified position. The pixels array shall be treated as by row
+     * matrix, the values are values compatible with the internal {@link GridColor} representation,
+     * e.g. what {@link GridColor#getRawValue()} would return.
+     */
+    void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation);
+
     /**
      * Prints a string with left bottom corner at given position rotated by given angle anti clock
      * wise, the centre of the rotation should be the bottom left corer.
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
index baad5ebe4167fd56f54527f64d3d811909de6fff..aae079d9c3b5c618871f186c48d6a812b7658d1e 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
@@ -30,6 +30,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.text.DecimalFormat;
+import java.util.Base64;
 import java.util.Collections;
 
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridFontStyle;
@@ -108,6 +109,13 @@ public class SVGDevice implements GridDevice {
         append("<circle vector-effect='non-scaling-stroke' cx='%.3f' cy='%.3f' r='%.3f'/>", centerX, transY(centerY), radius);
     }
 
+    @Override
+    public void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation) {
+        byte[] bitmap = Bitmap.create(pixels, pixelsColumnsCount);
+        String base64 = Base64.getEncoder().encodeToString(bitmap);
+        append("<image x='%.3f' y='%.3f' width='%.3f' height='%.3f' preserveAspectRatio='none' xlink:href='data:image/bmp;base64,%s'/>", leftX, transY(bottomY + height), width, height, base64);
+    }
+
     @Override
     public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) {
         appendStyle(ctx);
@@ -270,4 +278,60 @@ public class SVGDevice implements GridDevice {
     private static double toDegrees(double rotationAnticlockWise) {
         return (180. / Math.PI) * -rotationAnticlockWise;
     }
+
+    private static final class Bitmap {
+        private static final int FILE_HEADER_SIZE = 14;
+        private static final int IMAGE_HEADER_SIZE = 40;
+        private static final int BITS_PER_PIXEL = 24;
+        private static final int COMPRESSION_TYPE = 0;
+
+        static byte[] create(int[] pixels, int width) {
+            int height = pixels.length / width;
+            int widthInBytes = width * 3;
+            int widthPadding = widthInBytes % 2;
+            widthInBytes += widthPadding;
+
+            int len = FILE_HEADER_SIZE + IMAGE_HEADER_SIZE + height * widthInBytes;
+            byte[] result = new byte[len];
+
+            // file header
+            result[0] = 0x42; // B
+            result[1] = 0x4d; // M
+            int offset = putInt(result, 2, len);
+            offset += 4;    // unused 4B must be zero
+            offset = putInt(result, offset, FILE_HEADER_SIZE + IMAGE_HEADER_SIZE);  // data offset
+
+            // image header
+            offset = putInt(result, offset, IMAGE_HEADER_SIZE);
+            offset = putInt(result, offset, width);
+            offset = putInt(result, offset, height);
+            result[offset++] = 1;   // fixed value
+            result[offset++] = 0;   // fixed value
+            result[offset++] = BITS_PER_PIXEL;
+            result[offset++] = 0;   // bits per pixel is 2B value
+            offset = putInt(result, offset, COMPRESSION_TYPE);
+            // followed by 5 unimportant values (each 4B) that we leave 0
+            offset += 4 * 5;
+
+            // image data
+            for (int row = height - 1; row >= 0; row--) {
+                for (int col = 0; col < width; col++) {
+                    GridColor color = GridColor.fromRawValue(pixels[row * width + col]);
+                    result[offset++] = (byte) (color.getBlue() & 0xff);
+                    result[offset++] = (byte) (color.getGreen() & 0xff);
+                    result[offset++] = (byte) (color.getRed() & 0xff);
+                }
+                offset += widthPadding;
+            }
+            return result;
+        }
+
+        private static int putInt(byte[] data, int offset, int value) {
+            data[offset] = (byte) (value & 0xff);
+            data[offset + 1] = (byte) (value >>> 8 & 0xff);
+            data[offset + 2] = (byte) (value >>> 16 & 0xff);
+            data[offset + 3] = (byte) (value >>> 24 & 0xff);
+            return offset + 4;
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedJFrameDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedJFrameDevice.java
index 607b0ad8b033aca74cbdcc07b9d807e45b5cee5a..84375d755d26c89aa6f7172e2b459655cc7b9d34 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedJFrameDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/BufferedJFrameDevice.java
@@ -146,6 +146,12 @@ public final class BufferedJFrameDevice implements GridDevice, ImageSaver {
         drawActions.add(() -> inner.drawCircle(ctx, centerX, centerY, radius));
     }
 
+    @Override
+    public void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation) {
+        inner.drawRaster(leftX, bottomY, width, height, pixels, pixelsColumnsCount, interpolation);
+        drawActions.add(() -> inner.drawRaster(leftX, bottomY, width, height, pixels, pixelsColumnsCount, interpolation));
+    }
+
     @Override
     public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) {
         inner.drawString(ctx, leftX, bottomY, rotationAnticlockWise, text);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java
index e29477b675150abd208d970cd15bbcc2323942cb..1e10c2cd88c4a48208f13e8650c98ac99a57452c 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java
@@ -30,13 +30,17 @@ import java.awt.Color;
 import java.awt.Font;
 import java.awt.FontMetrics;
 import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
 import java.awt.Paint;
 import java.awt.RenderingHints;
 import java.awt.Shape;
+import java.awt.Toolkit;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.image.MemoryImageSource;
 
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext;
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridFontStyle;
@@ -59,7 +63,7 @@ public class Graphics2DDevice implements GridDevice {
     // may wish to apply his/her own transformations to the graphics object and we should not
     // interfere with these. In cases we do use transformation, we make sure to set back the
     // original one after we're done.
-    static final double AWT_POINTS_IN_INCH = 72.;
+    static final double AWT_POINTS_IN_INCH = GraphicsEnvironment.isHeadless() ? 72. : Toolkit.getDefaultToolkit().getScreenResolution();
 
     private static BasicStroke blankStroke;
 
@@ -131,6 +135,13 @@ public class Graphics2DDevice implements GridDevice {
         drawShape(ctx, new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2d, radius * 2d));
     }
 
+    @Override
+    public void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation) {
+        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, fromInterpolation(interpolation));
+        Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(pixelsColumnsCount, pixels.length / pixelsColumnsCount, pixels, 0, pixelsColumnsCount));
+        graphics.drawImage(image, transX(leftX), transY(bottomY + height), transDim(width), transDim(height), null);
+    }
+
     @Override
     public void drawString(DrawingContext ctx, double leftXIn, double bottomYIn, double rotationAnticlockWise, String text) {
         setContextAndFont(ctx);
@@ -337,4 +348,11 @@ public class Graphics2DDevice implements GridDevice {
                 throw RInternalError.shouldNotReachHere("unexpected value of GridLineJoin enum");
         }
     }
+
+    private static Object fromInterpolation(ImageInterpolation interpolation) {
+        if (interpolation == ImageInterpolation.NEAREST_NEIGHBOR) {
+            return RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+        }
+        return RenderingHints.VALUE_INTERPOLATION_BILINEAR;
+    }
 }
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index e3f4d743c28a5656ba333229852f99d02ba89cdc..201313142399f2b7a80f536e1ee26adacbc6bf98 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -745,6 +745,7 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/p
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/deriv/Deriv.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/deriv/DerivVisitor.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRect.java,gnu_r_murrel_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRaster.java,gnu_r_murrel_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LPretty.java,gnu_r_murrel_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LRectBounds.java,gnu_r_murrel_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/LCircleBounds.java,gnu_r_murrel_core.copyright