diff --git a/common/plotters/DXF_plotter.cpp b/common/plotters/DXF_plotter.cpp
index 877a3526fc..96f5da8b07 100644
--- a/common/plotters/DXF_plotter.cpp
+++ b/common/plotters/DXF_plotter.cpp
@@ -861,145 +861,186 @@ void DXF_PLOTTER::Text( const VECTOR2I&             aPos,
     }
     else
     {
-        /* Emit text as a text entity. This loses formatting and shape but it's
-           more useful as a CAD object */
-        VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
-        SetColor( aColor );
-        wxString cname = getDXFColorName( m_currentColor );
-        VECTOR2D size_dev = userToDeviceSize( aSize );
-        int h_code = 0, v_code = 0;
-
-        switch( aH_justify )
-        {
-        case GR_TEXT_H_ALIGN_LEFT:   h_code = 0; break;
-        case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
-        case GR_TEXT_H_ALIGN_RIGHT:  h_code = 2; break;
-        }
-
-        switch( aV_justify )
-        {
-        case GR_TEXT_V_ALIGN_TOP:    v_code = 3; break;
-        case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
-        case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
-        }
-
-        // Position, size, rotation and alignment
-        // The two alignment point usages is somewhat idiot (see the DXF ref)
-        // Anyway since we don't use the fit/aligned options, they're the same
-        fprintf( m_outputFile,
-                 "  0\n"
-                 "TEXT\n"
-                 "  7\n"
-                 "%s\n"          // Text style
-                 "  8\n"
-                 "%s\n"          // Layer name
-                 "  10\n"
-                 "%g\n"          // First point X
-                 "  11\n"
-                 "%g\n"          // Second point X
-                 "  20\n"
-                 "%g\n"          // First point Y
-                 "  21\n"
-                 "%g\n"          // Second point Y
-                 "  40\n"
-                 "%g\n"          // Text height
-                 "  41\n"
-                 "%g\n"          // Width factor
-                 "  50\n"
-                 "%g\n"          // Rotation
-                 "  51\n"
-                 "%g\n"          // Oblique angle
-                 "  71\n"
-                 "%d\n"          // Mirror flags
-                 "  72\n"
-                 "%d\n"          // H alignment
-                 "  73\n"
-                 "%d\n",         // V alignment
-                 aBold ? (aItalic ? "KICADBI" : "KICADB") : (aItalic ? "KICADI" : "KICAD"),
-                 TO_UTF8( cname ),
-                 origin_dev.x, origin_dev.x,
-                 origin_dev.y, origin_dev.y,
-                 size_dev.y, fabs( size_dev.x / size_dev.y ),
-                 aOrient.AsDegrees(),
-                 aItalic ? DXF_OBLIQUE_ANGLE : 0,
-                 size_dev.x < 0 ? 2 : 0, // X mirror flag
-                 h_code, v_code );
-
-        /* There are two issue in emitting the text:
-           - Our overline character (~) must be converted to the appropriate
-           control sequence %%O or %%o
-           - Text encoding in DXF is more or less unspecified since depends on
-           the DXF declared version, the acad version reading it *and* some
-           system variables to be put in the header handled only by newer acads
-           Also before R15 unicode simply is not supported (you need to use
-           bigfonts which are a massive PITA). Common denominator solution:
-           use Latin1 (and however someone could choke on it, anyway). Sorry
-           for the extended latin people. If somewant want to try fixing this
-           recent version seems to use UTF-8 (and not UCS2 like the rest of
-           Windows)
-
-           XXX Actually there is a *third* issue: older DXF formats are limited
-           to 255 bytes records (it was later raised to 2048); since I'm lazy
-           and text so long is not probable I just don't implement this rule.
-           If someone is interested in fixing this, you have to emit the first
-           partial lines with group code 3 (max 250 bytes each) and then finish
-           with a group code 1 (less than 250 bytes). The DXF refs explains it
-           in no more details...
-         */
-
-        int braceNesting = 0;
-        int overbarDepth = -1;
-
-        fputs( "  1\n", m_outputFile );
-
-        for( unsigned int i = 0; i < aText.length(); i++ )
-        {
-            /* Here I do a bad thing: writing the output one byte at a time!
-               but today I'm lazy and I have no idea on how to coerce a Unicode
-               wxString to spit out latin1 encoded text ...
-
-               At least stdio is *supposed* to do output buffering, so there is
-               hope is not too slow */
-            wchar_t ch = aText[i];
-
-            if( ch > 255 )
-            {
-                // I can't encode this...
-                putc( '?', m_outputFile );
-            }
-            else
-            {
-                if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
-                {
-                    fputs( "%%o", m_outputFile );
-                    overbarDepth = braceNesting;
-
-                    // Skip the '{'
-                    i++;
-                    continue;
-                }
-                else if( aText[i] == '{' )
-                {
-                    braceNesting++;
-                }
-                else if( aText[i] == '}' )
-                {
-                    if( braceNesting > 0 )
-                        braceNesting--;
-
-                    if( braceNesting == overbarDepth )
-                    {
-                        fputs( "%%O", m_outputFile );
-                        overbarDepth = -1;
-                        continue;
-                    }
-                }
-
-                putc( ch, m_outputFile );
-            }
-        }
-
-        putc( '\n', m_outputFile );
+        TEXT_ATTRIBUTES attrs;
+        attrs.m_Halign = aH_justify;
+        attrs.m_Valign =aV_justify;
+        attrs.m_StrokeWidth = aWidth;
+        attrs.m_Angle = aOrient;
+        attrs.m_Italic = aItalic;
+        attrs.m_Bold = aBold;
+        attrs.m_Mirrored = aSize.x < 0;
+        attrs.m_Multiline = false;
+        plotOneLineOfText( aPos, aColor, aText, attrs );
     }
 }
 
+
+void DXF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                    const wxString& aText,
+                    const TEXT_ATTRIBUTES& aAttributes,
+                    KIFONT::FONT* aFont,
+                    void* aData )
+{
+    TEXT_ATTRIBUTES attrs = aAttributes;
+    // Fix me: see how to use DXF text mode for multiline texts
+    if( attrs.m_Multiline && !aText.Contains( wxT( "\n" ) ) )
+        attrs.m_Multiline = false;  // the text has only one line.
+
+    bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
+
+    if( m_textAsLines || containsNonAsciiChars( aText ) || attrs.m_Multiline || processSuperSub )
+    {
+        // output text as graphics.
+        // Perhaps multiline texts could be handled as DXF text entity
+        // but I do not want spend time about that (JPC)
+        PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
+    }
+    else
+       plotOneLineOfText( aPos, aColor, aText, attrs );
+}
+
+void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                                    const wxString& aText,
+                                    const TEXT_ATTRIBUTES& aAttributes )
+{
+    /* Emit text as a text entity. This loses formatting and shape but it's
+       more useful as a CAD object */
+    VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
+    SetColor( aColor );
+    wxString cname = getDXFColorName( m_currentColor );
+    VECTOR2D size_dev = userToDeviceSize( aAttributes.m_Size );
+    int h_code = 0, v_code = 0;
+
+    switch( aAttributes.m_Halign )
+    {
+    case GR_TEXT_H_ALIGN_LEFT:   h_code = 0; break;
+    case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
+    case GR_TEXT_H_ALIGN_RIGHT:  h_code = 2; break;
+    }
+
+    switch( aAttributes.m_Valign )
+    {
+    case GR_TEXT_V_ALIGN_TOP:    v_code = 3; break;
+    case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
+    case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
+    }
+
+    // Position, size, rotation and alignment
+    // The two alignment point usages is somewhat idiot (see the DXF ref)
+    // Anyway since we don't use the fit/aligned options, they're the same
+    fprintf( m_outputFile,
+             "  0\n"
+             "TEXT\n"
+             "  7\n"
+             "%s\n"          // Text style
+             "  8\n"
+             "%s\n"          // Layer name
+             "  10\n"
+             "%g\n"          // First point X
+             "  11\n"
+             "%g\n"          // Second point X
+             "  20\n"
+             "%g\n"          // First point Y
+             "  21\n"
+             "%g\n"          // Second point Y
+             "  40\n"
+             "%g\n"          // Text height
+             "  41\n"
+             "%g\n"          // Width factor
+             "  50\n"
+             "%g\n"          // Rotation
+             "  51\n"
+             "%g\n"          // Oblique angle
+             "  71\n"
+             "%d\n"          // Mirror flags
+             "  72\n"
+             "%d\n"          // H alignment
+             "  73\n"
+             "%d\n",         // V alignment
+             aAttributes.m_Bold ?
+                (aAttributes.m_Italic ? "KICADBI" : "KICADB")
+                : (aAttributes.m_Italic ? "KICADI" : "KICAD"), TO_UTF8( cname ),
+             origin_dev.x, origin_dev.x,
+             origin_dev.y, origin_dev.y,
+             size_dev.y, fabs( size_dev.x / size_dev.y ),
+             aAttributes.m_Angle.AsDegrees(),
+             aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
+             aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
+             h_code, v_code );
+
+    /* There are two issue in emitting the text:
+       - Our overline character (~) must be converted to the appropriate
+       control sequence %%O or %%o
+       - Text encoding in DXF is more or less unspecified since depends on
+       the DXF declared version, the acad version reading it *and* some
+       system variables to be put in the header handled only by newer acads
+       Also before R15 unicode simply is not supported (you need to use
+       bigfonts which are a massive PITA). Common denominator solution:
+       use Latin1 (and however someone could choke on it, anyway). Sorry
+       for the extended latin people. If somewant want to try fixing this
+       recent version seems to use UTF-8 (and not UCS2 like the rest of
+       Windows)
+
+       XXX Actually there is a *third* issue: older DXF formats are limited
+       to 255 bytes records (it was later raised to 2048); since I'm lazy
+       and text so long is not probable I just don't implement this rule.
+       If someone is interested in fixing this, you have to emit the first
+       partial lines with group code 3 (max 250 bytes each) and then finish
+       with a group code 1 (less than 250 bytes). The DXF refs explains it
+       in no more details...
+     */
+
+    int braceNesting = 0;
+    int overbarDepth = -1;
+
+    fputs( "  1\n", m_outputFile );
+
+    for( unsigned int i = 0; i < aText.length(); i++ )
+    {
+        /* Here I do a bad thing: writing the output one byte at a time!
+           but today I'm lazy and I have no idea on how to coerce a Unicode
+           wxString to spit out latin1 encoded text ...
+
+           At least stdio is *supposed* to do output buffering, so there is
+           hope is not too slow */
+        wchar_t ch = aText[i];
+
+        if( ch > 255 )
+        {
+            // I can't encode this...
+            putc( '?', m_outputFile );
+        }
+        else
+        {
+            if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
+            {
+                fputs( "%%o", m_outputFile );
+                overbarDepth = braceNesting;
+
+                // Skip the '{'
+                i++;
+                continue;
+            }
+            else if( aText[i] == '{' )
+            {
+                braceNesting++;
+            }
+            else if( aText[i] == '}' )
+            {
+                if( braceNesting > 0 )
+                    braceNesting--;
+
+                if( braceNesting == overbarDepth )
+                {
+                    fputs( "%%O", m_outputFile );
+                    overbarDepth = -1;
+                    continue;
+                }
+            }
+
+            putc( ch, m_outputFile );
+        }
+    }
+
+    putc( '\n', m_outputFile );
+}
diff --git a/common/plotters/GERBER_plotter.cpp b/common/plotters/GERBER_plotter.cpp
index e0cd72803d..4ec85e3a57 100644
--- a/common/plotters/GERBER_plotter.cpp
+++ b/common/plotters/GERBER_plotter.cpp
@@ -2004,6 +2004,20 @@ void GERBER_PLOTTER::Text( const VECTOR2I&             aPos,
 }
 
 
+void GERBER_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                    const wxString& aText,
+                    const TEXT_ATTRIBUTES& aAttributes,
+                    KIFONT::FONT* aFont,
+                    void* aData )
+{
+    GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
+
+    if( gbr_metadata )
+        formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
+
+    PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
+}
+
 void GERBER_PLOTTER::SetLayerPolarity( bool aPositive )
 {
     if( aPositive )
diff --git a/common/plotters/PDF_plotter.cpp b/common/plotters/PDF_plotter.cpp
index fa38b83354..f41e64cfcc 100644
--- a/common/plotters/PDF_plotter.cpp
+++ b/common/plotters/PDF_plotter.cpp
@@ -1376,7 +1376,9 @@ void PDF_PLOTTER::Text( const VECTOR2I&             aPos,
     double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
     double wideningFactor, heightFactor;
 
-    computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify,
+    VECTOR2I t_size( std::abs( aSize.x ), std::abs( aSize.y ) );
+
+    computeTextParameters( aPos, aText, aOrient, t_size, m_plotMirror, aH_justify,
                            aV_justify, aWidth, aItalic, aBold, &wideningFactor, &ctm_a,
                            &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
 
@@ -1389,7 +1391,7 @@ void PDF_PLOTTER::Text( const VECTOR2I&             aPos,
     if( !aFont )
         aFont = KIFONT::FONT::GetFont();
 
-    VECTOR2I full_box( aFont->StringBoundaryLimits( aText, aSize, aWidth, aBold, aItalic ) );
+    VECTOR2I full_box( aFont->StringBoundaryLimits( aText, t_size, aWidth, aBold, aItalic ) );
     VECTOR2I box_x( full_box.x, 0 );
     VECTOR2I box_y( 0, full_box.y );
 
@@ -1410,13 +1412,13 @@ void PDF_PLOTTER::Text( const VECTOR2I&             aPos,
     {
         wxString word = str_tok.GetNextToken();
 
-        computeTextParameters( pos, word, aOrient, aSize, m_plotMirror, GR_TEXT_H_ALIGN_LEFT,
+        computeTextParameters( pos, word, aOrient, t_size, m_plotMirror, GR_TEXT_H_ALIGN_LEFT,
                                GR_TEXT_V_ALIGN_BOTTOM, aWidth, aItalic, aBold, &wideningFactor, &ctm_a,
                                &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
 
         // Extract the changed width and rotate by the orientation to get the offset for the
         // next word
-        VECTOR2I bbox( aFont->StringBoundaryLimits( word, aSize, aWidth, aBold, aItalic ).x, 0 );
+        VECTOR2I bbox( aFont->StringBoundaryLimits( word, t_size, aWidth, aBold, aItalic ).x, 0 );
         RotatePoint( bbox, aOrient );
         pos += bbox;
 
@@ -1444,6 +1446,30 @@ void PDF_PLOTTER::Text( const VECTOR2I&             aPos,
 }
 
 
+void PDF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                    const wxString& aText,
+                    const TEXT_ATTRIBUTES& aAttributes,
+                    KIFONT::FONT* aFont,
+                    void* aData )
+{
+    VECTOR2I size = aAttributes.m_Size;
+
+    // PDF files do not like 0 sized texts which create broken files.
+    if( size.x == 0 || size.y == 0 )
+        return;
+
+    if( aAttributes.m_Mirrored )
+        size.x = -size.x;
+
+    PDF_PLOTTER::Text( aPos, aColor, aText, aAttributes.m_Angle, size,
+                       aAttributes.m_Halign, aAttributes.m_Valign,
+                       aAttributes.m_StrokeWidth,
+                       aAttributes.m_Italic, aAttributes.m_Bold,
+                       aAttributes.m_Multiline,
+                       aFont, aData );
+}
+
+
 void PDF_PLOTTER::HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL )
 {
     m_hyperlinksInPage.push_back( std::make_pair( aBox, aDestinationURL ) );
diff --git a/common/plotters/PS_plotter.cpp b/common/plotters/PS_plotter.cpp
index 1078e0e530..0a4fa8a38b 100644
--- a/common/plotters/PS_plotter.cpp
+++ b/common/plotters/PS_plotter.cpp
@@ -967,6 +967,28 @@ void PS_PLOTTER::Text( const VECTOR2I&             aPos,
 }
 
 
+void PS_PLOTTER::PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData )
+{
+    SetCurrentLineWidth( aAttributes.m_StrokeWidth );
+    SetColor( aColor );
+
+    // Draw the hidden postscript text (if requested)
+    if( m_textMode == PLOT_TEXT_MODE::PHANTOM )
+    {
+        std::string ps_test = encodeStringForPlotter( aText );
+        VECTOR2D pos_dev = userToDeviceCoordinates( aPos );
+        fprintf( m_outputFile, "%s %g %g phantomshow\n", ps_test.c_str(), pos_dev.x, pos_dev.y );
+    }
+
+    PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
+}
+
+
 /**
  * Character widths for Helvetica
  */
diff --git a/common/plotters/SVG_plotter.cpp b/common/plotters/SVG_plotter.cpp
index 40ceaa677b..b1b67e86ca 100644
--- a/common/plotters/SVG_plotter.cpp
+++ b/common/plotters/SVG_plotter.cpp
@@ -853,3 +853,23 @@ void SVG_PLOTTER::Text( const VECTOR2I&             aPos,
 
     fputs( "</g>", m_outputFile );
 }
+
+
+void SVG_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                    const wxString& aText,
+                    const TEXT_ATTRIBUTES& aAttributes,
+                    KIFONT::FONT* aFont,
+                    void* aData )
+{
+    VECTOR2I size = aAttributes.m_Size;
+
+    if( aAttributes.m_Mirrored )
+        size.x = -size.x;
+
+    SVG_PLOTTER::Text( aPos, aColor, aText, aAttributes.m_Angle, size,
+                       aAttributes.m_Halign, aAttributes.m_Valign,
+                       aAttributes.m_StrokeWidth,
+                       aAttributes.m_Italic, aAttributes.m_Bold,
+                       aAttributes.m_Multiline,
+                       aFont, aData );
+}
diff --git a/common/plotters/plotter.cpp b/common/plotters/plotter.cpp
index 8f734fe076..52e577a177 100644
--- a/common/plotters/plotter.cpp
+++ b/common/plotters/plotter.cpp
@@ -694,23 +694,6 @@ void PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int a
 }
 
 
-/**
- * Same as GRText, but plot graphic text instead of draw it.
- *
- * @param aPos is the text position (according to aH_justify, aV_justify).
- * @param aColor is the text color.
- * @param aText is the text to draw.
- * @param aOrient is the angle.
- * @param aSize is the text size (size.x or size.y can be < 0 for mirrored texts).
- * @param aH_justify is the horizontal justification (Left, center, right).
- * @param aV_justify is the vertical justification (bottom, center, top).
- * @param aPenWidth is the line width (if = 0, use plot default line width).
- * @param aItalic is the true to simulate an italic font.
- * @param aBold use true to use a bold font Useful only with default width value (aPenWidth = 0).
- * @param aMultilineAllowed use true to plot text as multiline, otherwise single line.
- * @param aData is a parameter used by some plotters in SetCurrentLineWidth(),
- *              not directly used here.
- */
 void PLOTTER::Text( const VECTOR2I&             aPos,
                     const COLOR4D&              aColor,
                     const wxString&             aText,
@@ -771,3 +754,45 @@ void PLOTTER::Text( const VECTOR2I&             aPos,
 
     aFont->Draw( &callback_gal, aText, aPos, attributes );
 }
+
+void PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                    const wxString& aText,
+                    const TEXT_ATTRIBUTES& aAttributes,
+                    KIFONT::FONT* aFont,
+                    void* aData )
+{
+    KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
+
+    TEXT_ATTRIBUTES attributes = aAttributes;
+    int penWidth = attributes.m_StrokeWidth;
+
+    SetColor( aColor );
+    SetCurrentLineWidth( penWidth, aData );
+
+    if( penWidth == 0 && attributes.m_Bold ) // Use default values if aPenWidth == 0
+        penWidth = GetPenSizeForBold( std::min( attributes.m_Size.x, attributes.m_Size.y ) );
+
+    if( penWidth < 0 )
+        penWidth = -penWidth;
+
+    attributes.m_StrokeWidth = penWidth;
+
+    CALLBACK_GAL callback_gal( empty_opts,
+            // Stroke callback
+            [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
+            {
+                MoveTo( aPt1 );
+                LineTo( aPt2 );
+                PenFinish();
+            },
+            // Polygon callback
+            [&]( const SHAPE_LINE_CHAIN& aPoly )
+            {
+                PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
+            } );
+
+    if( !aFont )
+        aFont = KIFONT::FONT::GetFont();
+
+    aFont->Draw( &callback_gal, aText, aPos, attributes );
+}
diff --git a/eeschema/lib_field.cpp b/eeschema/lib_field.cpp
index 2152164bed..995a401d88 100644
--- a/eeschema/lib_field.cpp
+++ b/eeschema/lib_field.cpp
@@ -383,8 +383,14 @@ void LIB_FIELD::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOffs
     if( !font )
         font = KIFONT::FONT::GetFont( renderSettings->GetDefaultFont(), IsBold(), IsItalic() );
 
-    aPlotter->Text( textpos, color, GetShownText(), orient, GetTextSize(), hjustify, vjustify,
-                    penWidth, IsItalic(), IsBold(), false, font );
+    TEXT_ATTRIBUTES attrs = GetAttributes();
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Halign = hjustify;
+    attrs.m_Valign = vjustify;
+    attrs.m_Angle = orient;
+    attrs.m_Multiline = false;
+
+    aPlotter->PlotText( textpos, color, GetShownText(), attrs, font );
 }
 
 
diff --git a/eeschema/lib_pin.cpp b/eeschema/lib_pin.cpp
index 28626e287d..253c79ddda 100644
--- a/eeschema/lib_pin.cpp
+++ b/eeschema/lib_pin.cpp
@@ -812,8 +812,15 @@ void LIB_PIN::PlotPinTexts( PLOTTER *aPlotter, const VECTOR2I &aPinPos, int aPin
                  int size, GR_TEXT_H_ALIGN_T hJustify, GR_TEXT_V_ALIGN_T vJustify, int penWidth )
 
             {
-                aPlotter->Text( VECTOR2I( px, py ), color, text, angle, VECTOR2I( size, size ),
-                                hJustify, vJustify, penWidth, false, false, false, font );
+                TEXT_ATTRIBUTES attrs;
+                attrs.m_StrokeWidth = std::min( penWidth, size / 5 );  // Keep text readable
+                attrs.m_Angle = angle;
+                attrs.m_Size = VECTOR2I( size, size );
+                attrs.m_Halign = hJustify;
+                attrs.m_Valign = vJustify;
+                attrs.m_Multiline = false;
+
+                aPlotter->PlotText( VECTOR2I( px, py ), color, text, attrs, font );
             };
 
     /* Draw the text inside, but the pin numbers outside. */
diff --git a/eeschema/lib_text.cpp b/eeschema/lib_text.cpp
index af023cb0dc..507e36b243 100644
--- a/eeschema/lib_text.cpp
+++ b/eeschema/lib_text.cpp
@@ -326,9 +326,10 @@ void LIB_TEXT::Plot( PLOTTER* plotter, bool aBackground, const VECTOR2I& offset,
     if( !font )
         font = KIFONT::FONT::GetFont( settings->GetDefaultFont(), IsBold(), IsItalic() );
 
-    plotter->Text( pos, color, GetText(), t1 ? ANGLE_HORIZONTAL : ANGLE_VERTICAL, GetTextSize(),
-                   GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(), IsBold(),
-                   true, font );
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Angle = t1 ? ANGLE_HORIZONTAL : ANGLE_VERTICAL;
+
+    plotter->PlotText( pos, color, GetText(), attrs, font );
 }
 
 
diff --git a/eeschema/lib_textbox.cpp b/eeschema/lib_textbox.cpp
index 6d84504c47..386a50c30d 100644
--- a/eeschema/lib_textbox.cpp
+++ b/eeschema/lib_textbox.cpp
@@ -466,11 +466,13 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOf
 
     text.GetLinePositions( positions, (int) strings_list.Count() );
 
+    TEXT_ATTRIBUTES attrs = GetAttributes();
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Multiline = false;
+
     for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
     {
-        aPlotter->Text( positions[ii], color, strings_list.Item( ii ), text.GetTextAngle(),
-                        text.GetTextSize(), text.GetHorizJustify(), text.GetVertJustify(),
-                        penWidth, text.IsItalic(), text.IsBold(), false, font );
+        aPlotter->PlotText( positions[ii], color, strings_list.Item( ii ), attrs, font );
     }
 }
 
diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp
index 07fb444d61..a99139b362 100644
--- a/eeschema/sch_field.cpp
+++ b/eeschema/sch_field.cpp
@@ -958,6 +958,9 @@ void SCH_FIELD::Plot( PLOTTER* aPlotter, bool aBackground ) const
 
     penWidth = std::max( penWidth, settings->GetMinPenWidth() );
 
+    // clamp the pen width to be sure the text is readable
+    penWidth = std::min( penWidth, std::min( GetTextSize().x, GetTextSize().y ) / 4 );
+
     if( !IsVisible() )
         return;
 
@@ -1011,8 +1014,14 @@ void SCH_FIELD::Plot( PLOTTER* aPlotter, bool aBackground ) const
     if( !font )
         font = KIFONT::FONT::GetFont( settings->GetDefaultFont(), IsBold(), IsItalic() );
 
-    aPlotter->Text( textpos, color, GetShownText(), orient, GetTextSize(),  hjustify, vjustify,
-                    penWidth, IsItalic(), IsBold(), false, font );
+    TEXT_ATTRIBUTES attrs = GetAttributes();
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Halign = hjustify;
+    attrs.m_Valign = vjustify;
+    attrs.m_Angle = orient;
+    attrs.m_Multiline = false;
+
+    aPlotter->PlotText( textpos, color, GetShownText(), attrs, font );
 
     if( IsHypertext() )
     {
diff --git a/eeschema/sch_label.cpp b/eeschema/sch_label.cpp
index ca424bb9e6..c9b0aecfc8 100644
--- a/eeschema/sch_label.cpp
+++ b/eeschema/sch_label.cpp
@@ -967,15 +967,17 @@ void SCH_LABEL_BASE::Plot( PLOTTER* aPlotter, bool aBackground ) const
     VECTOR2I textpos = GetTextPos() + GetSchematicTextOffset( aPlotter->RenderSettings() );
     CreateGraphicShape( aPlotter->RenderSettings(), s_poly, GetTextPos() );
 
+    TEXT_ATTRIBUTES attrs = GetAttributes();
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Multiline = false;
+
     if( aBackground )
     {
         // No filled shapes (yet)
     }
     else
     {
-        aPlotter->Text( textpos, color, GetShownText(), GetTextAngle(), GetTextSize(),
-                        GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(), IsBold(),
-                        false, font );
+        aPlotter->PlotText( textpos, color, GetShownText(), attrs, font );
 
         if( s_poly.size() )
             aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
diff --git a/eeschema/sch_text.cpp b/eeschema/sch_text.cpp
index 1b6be4e712..ffa67f9493 100644
--- a/eeschema/sch_text.cpp
+++ b/eeschema/sch_text.cpp
@@ -462,12 +462,15 @@ void SCH_TEXT::Plot( PLOTTER* aPlotter, bool aBackground ) const
 
     GetLinePositions( positions, (int) strings_list.Count() );
 
+    TEXT_ATTRIBUTES attrs = GetAttributes();
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Multiline = false;
+
     for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
     {
         VECTOR2I  textpos = positions[ii] + text_offset;
         wxString& txt = strings_list.Item( ii );
-        aPlotter->Text( textpos, color, txt, GetTextAngle(), GetTextSize(), GetHorizJustify(),
-                        GetVertJustify(), penWidth, IsItalic(), IsBold(), false, font );
+        aPlotter->PlotText( textpos, color, txt, attrs, font );
     }
 
     if( HasHyperlink() )
diff --git a/eeschema/sch_textbox.cpp b/eeschema/sch_textbox.cpp
index 8800b5ca7e..558ee3e926 100644
--- a/eeschema/sch_textbox.cpp
+++ b/eeschema/sch_textbox.cpp
@@ -410,11 +410,13 @@ void SCH_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground ) const
 
     GetLinePositions( positions, (int) strings_list.Count() );
 
+    TEXT_ATTRIBUTES attrs = GetAttributes();
+    attrs.m_StrokeWidth = penWidth;
+    attrs.m_Multiline = false;
+
     for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
     {
-        aPlotter->Text( positions[ii], color, strings_list.Item( ii ), GetTextAngle(),
-                        GetTextSize(), GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(),
-                        IsBold(), false, font );
+        aPlotter->PlotText( positions[ii], color, strings_list.Item( ii ), attrs, font );
     }
 
     if( HasHyperlink() )
diff --git a/include/plotters/plotter.h b/include/plotters/plotter.h
index 1beac0ed02..308b598547 100644
--- a/include/plotters/plotter.h
+++ b/include/plotters/plotter.h
@@ -409,8 +409,22 @@ public:
     /**
      * Draw text with the plotter.
      *
-     * For convenience it accept the color to use for specific plotters (GERBER) aData is used
-     * to pass extra parameters.
+     * For convenience it accept the color to use for specific plotters
+     * aData is used to pass extra parameters (GERBER).
+     *
+     * @param aPos is the text position (according to aH_justify, aV_justify).
+     * @param aColor is the text color.
+     * @param aText is the text to draw.
+     * @param aOrient is the angle.
+     * @param aSize is the text size (size.x or size.y can be < 0 for mirrored texts).
+     * @param aH_justify is the horizontal justification (Left, center, right).
+     * @param aV_justify is the vertical justification (bottom, center, top).
+     * @param aPenWidth is the line width (if = 0, use plot default line width).
+     * @param aItalic is the true to simulate an italic font.
+     * @param aBold use true to use a bold font Useful only with default width value (aPenWidth = 0).
+     * @param aMultilineAllowed use true to plot text as multiline, otherwise single line.
+     * @param aData is a parameter used by some plotters in SetCurrentLineWidth(),
+     *              not directly used here.
      */
     virtual void Text( const VECTOR2I&             aPos,
                        const COLOR4D&              aColor,
@@ -426,6 +440,12 @@ public:
                        KIFONT::FONT*               aFont,
                        void*                       aData = nullptr );
 
+    virtual void PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData = nullptr );
     /**
      * Create a clickable hyperlink with a rectangular click area
      *
diff --git a/include/plotters/plotter_dxf.h b/include/plotters/plotter_dxf.h
index 90aa09585a..fe75764889 100644
--- a/include/plotters/plotter_dxf.h
+++ b/include/plotters/plotter_dxf.h
@@ -166,7 +166,12 @@ public:
                        KIFONT::FONT*          aFont = nullptr,
                        void*                  aData = nullptr ) override;
 
-
+    virtual void PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData = nullptr ) override;
     /**
      * Set the units to use for plotting the DXF file.
      *
@@ -210,6 +215,10 @@ protected:
                       const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill,
                       int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
 
+    void plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
+                            const wxString& aText,
+                            const TEXT_ATTRIBUTES& aAttributes );
+
     bool           m_textAsLines;
     COLOR4D        m_currentColor;
     PLOT_DASH_TYPE m_currentLineType;
diff --git a/include/plotters/plotter_gerber.h b/include/plotters/plotter_gerber.h
index 90d5a01da4..d60c78c7ca 100644
--- a/include/plotters/plotter_gerber.h
+++ b/include/plotters/plotter_gerber.h
@@ -124,6 +124,14 @@ public:
                        KIFONT::FONT*               aFont = nullptr,
                        void*                       aData = nullptr ) override;
 
+
+    virtual void PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData = nullptr ) override;
+
     /**
      * Filled circular flashes are stored as apertures
      */
diff --git a/include/plotters/plotters_pslike.h b/include/plotters/plotters_pslike.h
index 6628ddd03b..5d8639cba2 100644
--- a/include/plotters/plotters_pslike.h
+++ b/include/plotters/plotters_pslike.h
@@ -231,6 +231,14 @@ public:
                        KIFONT::FONT*               aFont = nullptr,
                        void*                       aData = nullptr ) override;
 
+    virtual void PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData = nullptr ) override;
+
+
 protected:
     virtual void emitSetRGBColor( double r, double g, double b, double a ) override;
 };
@@ -353,6 +361,13 @@ public:
                        KIFONT::FONT*               aFont = nullptr,
                        void*                       aData = nullptr ) override;
 
+    virtual void PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData = nullptr ) override;
+
     void HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL ) override;
 
     void HyperlinkMenu( const BOX2I& aBox, const std::vector<wxString>& aDestURLs ) override;
@@ -600,6 +615,14 @@ public:
                        KIFONT::FONT*               aFont = nullptr,
                        void*                       aData = nullptr ) override;
 
+
+    virtual void PlotText( const VECTOR2I&          aPos,
+                           const COLOR4D&           aColor,
+                           const wxString&          aText,
+                           const TEXT_ATTRIBUTES&   aAttributes,
+                           KIFONT::FONT*            aFont,
+                           void*                    aData = nullptr ) override;
+
 protected:
     virtual void Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
                       const EDA_ANGLE& aEndAngle, int aRadius,
diff --git a/pcbnew/exporters/gen_drill_report_files.cpp b/pcbnew/exporters/gen_drill_report_files.cpp
index 1c80e5d26b..2bb2fedfa5 100644
--- a/pcbnew/exporters/gen_drill_report_files.cpp
+++ b/pcbnew/exporters/gen_drill_report_files.cpp
@@ -266,10 +266,16 @@ bool GENDRILL_WRITER_BASE::genDrillMapFile( const wxString& aFullFileName, PLOT_
 
     // Plot title  "Info"
     wxString Text = wxT( "Drill Map:" );
-    plotter->Text( VECTOR2I( plotX, plotY ), COLOR4D::UNSPECIFIED, Text, ANGLE_HORIZONTAL,
-                   VECTOR2I( KiROUND( charSize * charScale ), KiROUND( charSize * charScale ) ),
-                   GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_CENTER, TextWidth, false, false,
-                   false, nullptr /* stroke font */ );
+
+    TEXT_ATTRIBUTES attrs;
+    attrs.m_StrokeWidth = TextWidth;
+    attrs.m_Angle = ANGLE_HORIZONTAL;
+    attrs.m_Size = VECTOR2I( KiROUND( charSize * charScale ), KiROUND( charSize * charScale ) );
+    attrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
+    attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
+    attrs.m_Multiline = false;
+
+    plotter->PlotText( VECTOR2I( plotX, plotY ), COLOR4D::UNSPECIFIED, Text, attrs, nullptr /* stroke font */ );
 
     // For some formats (PS, PDF SVG) we plot the drill size list on more than one column
     // because the list must be contained inside the printed page
@@ -328,10 +334,7 @@ bool GENDRILL_WRITER_BASE::genDrillMapFile( const wxString& aFullFileName, PLOT_
         if( tool.m_Hole_NotPlated )
             msg += wxT( " (not plated)" );
 
-        plotter->Text( VECTOR2I( plotX, y ), COLOR4D::UNSPECIFIED, msg, ANGLE_HORIZONTAL,
-                       VECTOR2I( KiROUND( charSize * charScale ), KiROUND( charSize * charScale ) ),
-                       GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_CENTER, TextWidth, false, false,
-                       false, nullptr /* stroke font */ );
+        plotter->PlotText( VECTOR2I( plotX, y ), COLOR4D::UNSPECIFIED, msg, attrs, nullptr /* stroke font */ );
 
         intervalle = KiROUND( ( ( charSize * charScale ) + TextWidth ) * 1.2 );
 
diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp
index 5aa24662d3..285e08f441 100644
--- a/pcbnew/plot_brditems_plotter.cpp
+++ b/pcbnew/plot_brditems_plotter.cpp
@@ -402,8 +402,7 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4
     m_plotter->SetColor( color );
 
     // calculate some text parameters :
-    TEXT_ATTRIBUTES attrs = aText->GetAttributes();
-    VECTOR2I      size = aText->GetTextSize();
+    //VECTOR2I      size = aText->GetTextSize();
     VECTOR2I      pos = aText->GetTextPos();
     int           thickness = aText->GetEffectiveTextPenWidth();
     KIFONT::FONT* font = aText->GetFont();
@@ -416,14 +415,15 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4
                                       aText->IsBold(), aText->IsItalic() );
     }
 
-    if( aText->IsMirrored() )
-        size.x = -size.x;  // Text is mirrored
-
     // Non bold texts thickness is clamped at 1/6 char size by the low level draw function.
     // but in Pcbnew we do not manage bold texts and thickness up to 1/4 char size
     // (like bold text) and we manage the thickness.
     // So we set bold flag to true
-    bool allow_bold = true;
+    TEXT_ATTRIBUTES attrs = aText->GetAttributes();
+    attrs.m_StrokeWidth = thickness;
+    attrs.m_Angle = aText->GetDrawRotation();
+    attrs.m_Bold = true;
+    attrs.m_Multiline = false;
 
     GBR_METADATA gbr_metadata;
 
@@ -434,6 +434,8 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4
     const FOOTPRINT* parent = static_cast<const FOOTPRINT*> ( aText->GetParent() );
     gbr_metadata.SetCmpReference( parent->GetReference() );
 
+    m_plotter->SetCurrentLineWidth( thickness );
+
     if( aText->IsKnockout() )
     {
         KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
@@ -462,12 +464,7 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4
             m_plotter->PlotPoly( finalPoly.Outline( ii ), FILL_T::FILLED_SHAPE, 0, &gbr_metadata );
     }
     else
-    {
-        m_plotter->SetCurrentLineWidth( thickness );
-        m_plotter->Text( pos, aColor, aText->GetShownText(), aText->GetDrawRotation(), size,
-                         aText->GetHorizJustify(), aText->GetVertJustify(), thickness,
-                         aText->IsItalic(), allow_bold, false, font, &gbr_metadata );
-    }
+        m_plotter->PlotText( pos, aColor, aText->GetShownText(), attrs, font, &gbr_metadata );
 }
 
 
@@ -840,7 +837,6 @@ void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer,
     }
 
     wxString        shownText( aText->GetShownText() );
-    TEXT_ATTRIBUTES attrs = aText->GetAttributes();
 
     if( shownText.IsEmpty() )
         return;
@@ -856,13 +852,16 @@ void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer,
     COLOR4D color = getColor( aLayer );
     m_plotter->SetColor( color );
 
-    VECTOR2I size = aText->GetTextSize();
+    //VECTOR2I size = aText->GetTextSize();
     VECTOR2I pos = aText->GetTextPos();
 
+    TEXT_ATTRIBUTES attrs = aText->GetAttributes();
     attrs.m_StrokeWidth = aText->GetEffectiveTextPenWidth();
+    attrs.m_Angle = aText->GetDrawRotation();
+    attrs.m_Multiline = false;
 
-    if( aText->IsMirrored() )
-        size.x = -size.x;
+    //if( aText->IsMirrored() )
+    //    size.x = -size.x;
 
     m_plotter->SetCurrentLineWidth( attrs.m_StrokeWidth );
 
@@ -905,16 +904,12 @@ void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer,
         for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
         {
             wxString& txt =  strings_list.Item( ii );
-            m_plotter->Text( positions[ii], color, txt, aText->GetDrawRotation(), size,
-                             attrs.m_Halign, attrs.m_Valign, attrs.m_StrokeWidth, attrs.m_Italic,
-                             attrs.m_Bold, false, font, &gbr_metadata );
+            m_plotter->PlotText( positions[ii], color, txt, attrs, font, &gbr_metadata );
         }
     }
     else
     {
-        m_plotter->Text( pos, color, shownText, aText->GetDrawRotation(), size, attrs.m_Halign,
-                         attrs.m_Valign, attrs.m_StrokeWidth, attrs.m_Italic, attrs.m_Bold, false,
-                         font, &gbr_metadata );
+        m_plotter->PlotText( pos, color, shownText, attrs, font, &gbr_metadata );
     }
 }