diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt
index 3c9afe863b..6586c5fefe 100644
--- a/gerbview/CMakeLists.txt
+++ b/gerbview/CMakeLists.txt
@@ -38,6 +38,7 @@ set( WIDGET_SRCS
 set( GERBVIEW_SRCS
     am_param.cpp
     am_primitive.cpp
+    aperture_macro.cpp
     gbr_layout.cpp
     gerber_file_image.cpp
     gerber_file_image_list.cpp
diff --git a/gerbview/am_param.cpp b/gerbview/am_param.cpp
index e424d0b1c1..5e1f9935b7 100644
--- a/gerbview/am_param.cpp
+++ b/gerbview/am_param.cpp
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1992-2017 Jean-Pierre Charras <jp.charras at wanadoo.fr>
  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
- * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -29,6 +29,7 @@
 
 #include <am_param.h>
 #include <am_primitive.h>
+#include <aperture_macro.h>
 #include <macros.h>
 
 extern int    ReadInt( char*& text, bool aSkipSeparator = true );
diff --git a/gerbview/am_primitive.cpp b/gerbview/am_primitive.cpp
index 8835f184e6..f7419dc2b8 100644
--- a/gerbview/am_primitive.cpp
+++ b/gerbview/am_primitive.cpp
@@ -1,5 +1,5 @@
 /**
- * @file aperture_macro.cpp
+ * @file am_primitive.cpp
  */
 
 /*
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1992-2017 Jean-Pierre Charras <jp.charras at wanadoo.fr>
  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -692,67 +692,3 @@ void AM_PRIMITIVE::ConvertShapeToPolygon( const GERBER_DRAW_ITEM* aParent,
         break;
     }
 }
-
-
-SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent,
-                                                       const VECTOR2I&         aShapePos )
-{
-    SHAPE_POLY_SET holeBuffer;
-
-    m_shape.RemoveAllContours();
-
-    for( AM_PRIMITIVE& prim_macro : m_PrimitivesList )
-    {
-        if( prim_macro.m_Primitive_id == AMP_COMMENT )
-            continue;
-
-        if( prim_macro.IsAMPrimitiveExposureOn( aParent ) )
-        {
-            prim_macro.ConvertBasicShapeToPolygon( aParent, m_shape, aShapePos );
-        }
-        else
-        {
-            prim_macro.ConvertBasicShapeToPolygon( aParent, holeBuffer, aShapePos );
-
-            if( holeBuffer.OutlineCount() )     // we have a new hole in shape: remove the hole
-            {
-                m_shape.BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
-                holeBuffer.RemoveAllContours();
-            }
-        }
-    }
-
-    // Merge and cleanup basic shape polygons
-    m_shape.Simplify( SHAPE_POLY_SET::PM_FAST );
-
-    // A hole can be is defined inside a polygon, or the polygons themselve can create
-    // a hole when merged, so we must fracture the polygon to be able to drawn it
-    // (i.e link holes by overlapping edges)
-    m_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
-
-    return &m_shape;
-}
-
-
-double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const
-{
-    // find parameter descr.
-    const AM_PARAM * param = nullptr;
-
-    for( unsigned ii = 0; ii < m_LocalParamStack.size(); ii ++ )
-    {
-        if( m_LocalParamStack[ii].GetIndex() == aParamId )
-        {
-            param = &m_LocalParamStack[ii];
-            break;
-        }
-    }
-
-    if ( param == nullptr )    // not found
-        return 0.0;
-
-    // Evaluate parameter
-    double value = param->GetValue( aDcode );
-
-    return value;
-}
diff --git a/gerbview/am_primitive.h b/gerbview/am_primitive.h
index e46cc79b7e..70bb867051 100644
--- a/gerbview/am_primitive.h
+++ b/gerbview/am_primitive.h
@@ -10,7 +10,7 @@
  *
  * Copyright (C) 1992-2010 Jean-Pierre Charras <jp.charras at wanadoo.fr>
  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
- * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -142,79 +142,4 @@ private:
 };
 
 
-/**
- * Support the "aperture macro" defined within standard RS274X.
- */
-class APERTURE_MACRO
-{
-public:
-    /**
-     * Usually, parameters are defined inside the aperture primitive using immediate mode or
-     * deferred mode.
-     *
-     * In deferred mode the value is defined in a DCODE that want to use the aperture macro.
-     * Some parameters are defined outside the aperture primitive and are local to the aperture
-     * macro.
-     *
-     * @return the value of a deferred parameter defined inside the aperture macro.
-     * @param aDcode is the D_CODE that uses this aperture macro and define deferred parameters.
-     * @param aParamId is the param id (defined by $3 or $5 ..) to evaluate.
-     */
-    double GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const;
-
-
-    /**
-     * Calculate the primitive shape for flashed items.
-     *
-     * When an item is flashed, this is the shape of the item.
-     *
-     * @param aParent is the parent #GERBER_DRAW_ITEM which is actually drawn.
-     * @return the shape of the item.
-     */
-    SHAPE_POLY_SET* GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent,
-                                           const VECTOR2I&         aShapePos );
-
-    /**
-     * The name of the aperture macro as defined like %AMVB_RECTANGLE* (name is VB_RECTANGLE)
-     */
-     wxString      m_AmName;
-
-    /**
-     * A sequence of AM_PRIMITIVEs
-     */
-    std::vector<AM_PRIMITIVE> m_PrimitivesList;
-
-    /*  A deferred parameter can be defined in aperture macro,
-     *  but outside aperture primitives. Example
-     *  %AMRECTHERM*
-     *  $4=$3/2*    parameter $4 is half value of parameter $3
-     * m_localparamStack handle a list of local deferred parameters
-     */
-    AM_PARAMS m_LocalParamStack;
-
-private:
-    SHAPE_POLY_SET m_shape;         ///< The shape of the item, calculated by GetApertureMacroShape
-};
-
-
-/**
- * Used by std:set<APERTURE_MACRO> instantiation which uses APERTURE_MACRO.name as its key.
- */
-struct APERTURE_MACRO_less_than
-{
-    // a "less than" test on two APERTURE_MACROs (.name wxStrings)
-    bool operator()( const APERTURE_MACRO& am1, const APERTURE_MACRO& am2 ) const
-    {
-        return am1.m_AmName.Cmp( am2.m_AmName ) < 0;  // case specific wxString compare
-    }
-};
-
-
-/**
- * A sorted collection of APERTURE_MACROS whose key is the name field in the APERTURE_MACRO.
- */
-typedef std::set<APERTURE_MACRO, APERTURE_MACRO_less_than> APERTURE_MACRO_SET;
-typedef std::pair<APERTURE_MACRO_SET::iterator, bool>      APERTURE_MACRO_SET_PAIR;
-
-
 #endif  // ifndef AM_PRIMITIVE_H
diff --git a/gerbview/aperture_macro.cpp b/gerbview/aperture_macro.cpp
new file mode 100644
index 0000000000..35df1e0de6
--- /dev/null
+++ b/gerbview/aperture_macro.cpp
@@ -0,0 +1,96 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2017 Jean-Pierre Charras <jp.charras at wanadoo.fr>
+ * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file aperture_macro.cpp
+ */
+
+
+#include <gerbview.h>
+#include <aperture_macro.h>
+
+
+SHAPE_POLY_SET* APERTURE_MACRO::GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent,
+                                                       const VECTOR2I&         aShapePos )
+{
+    SHAPE_POLY_SET holeBuffer;
+
+    m_shape.RemoveAllContours();
+
+    for( AM_PRIMITIVE& prim_macro : m_PrimitivesList )
+    {
+        if( prim_macro.m_Primitive_id == AMP_COMMENT )
+            continue;
+
+        if( prim_macro.IsAMPrimitiveExposureOn( aParent ) )
+        {
+            prim_macro.ConvertBasicShapeToPolygon( aParent, m_shape, aShapePos );
+        }
+        else
+        {
+            prim_macro.ConvertBasicShapeToPolygon( aParent, holeBuffer, aShapePos );
+
+            if( holeBuffer.OutlineCount() )     // we have a new hole in shape: remove the hole
+            {
+                m_shape.BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
+                holeBuffer.RemoveAllContours();
+            }
+        }
+    }
+
+    // Merge and cleanup basic shape polygons
+    m_shape.Simplify( SHAPE_POLY_SET::PM_FAST );
+
+    // A hole can be is defined inside a polygon, or the polygons themselve can create
+    // a hole when merged, so we must fracture the polygon to be able to drawn it
+    // (i.e link holes by overlapping edges)
+    m_shape.Fracture( SHAPE_POLY_SET::PM_FAST );
+
+    return &m_shape;
+}
+
+
+double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const
+{
+    // find parameter descr.
+    const AM_PARAM * param = nullptr;
+
+    for( unsigned ii = 0; ii < m_LocalParamStack.size(); ii ++ )
+    {
+        if( m_LocalParamStack[ii].GetIndex() == aParamId )
+        {
+            param = &m_LocalParamStack[ii];
+            break;
+        }
+    }
+
+    if ( param == nullptr )    // not found
+        return 0.0;
+
+    // Evaluate parameter
+    double value = param->GetValue( aDcode );
+
+    return value;
+}
diff --git a/gerbview/aperture_macro.h b/gerbview/aperture_macro.h
new file mode 100644
index 0000000000..69f46e4623
--- /dev/null
+++ b/gerbview/aperture_macro.h
@@ -0,0 +1,140 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2010 Jean-Pierre Charras <jp.charras at wanadoo.fr>
+ * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file aperture_macro.h
+ */
+
+#ifndef APERTURE_MACRO_H
+#define APERTURE_MACRO_H
+
+
+#include <vector>
+#include <set>
+
+#include <am_param.h>
+#include <am_primitive.h>
+
+class SHAPE_POLY_SET;
+
+/*
+ *  An aperture macro defines a complex shape and is a list of aperture primitives.
+ *  Each aperture primitive defines a simple shape (circle, rect, regular polygon...)
+ *  Inside a given aperture primitive, a fixed list of parameters defines info
+ *  about the shape: size, thickness, number of vertex ...
+ *
+ *  Each parameter can be an immediate value or a deferred value.
+ *  When value is deferred, it is defined when the aperture macro is instanced by
+ *  an ADD macro command
+ *  Note also a deferred parameter can be defined in aperture macro,
+ *  but outside aperture primitives. Example
+ *  %AMRECTHERM*
+ *  $4=$3/2*    parameter $4 is half value of parameter $3
+ *  21,1,$1-$3,$2-$3,0-$1/2-$4,0-$2/2-$4,0*
+ *  For the aperture primitive, parameters $1 to $3 will be defined in ADD command,
+ *  and $4 is defined inside the macro
+ *
+ *  Each basic shape can be a positive shape or a negative shape.
+ *  a negative shape is "local" to the whole shape.
+ *  It must be seen like a hole in the shape, and not like a standard negative object.
+ */
+
+
+/**
+ * Support the "aperture macro" defined within standard RS274X.
+ */
+class APERTURE_MACRO
+{
+public:
+    /**
+     * Usually, parameters are defined inside the aperture primitive using immediate mode or
+     * deferred mode.
+     *
+     * In deferred mode the value is defined in a DCODE that want to use the aperture macro.
+     * Some parameters are defined outside the aperture primitive and are local to the aperture
+     * macro.
+     *
+     * @return the value of a deferred parameter defined inside the aperture macro.
+     * @param aDcode is the D_CODE that uses this aperture macro and define deferred parameters.
+     * @param aParamId is the param id (defined by $3 or $5 ..) to evaluate.
+     */
+    double GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const;
+
+
+    /**
+     * Calculate the primitive shape for flashed items.
+     *
+     * When an item is flashed, this is the shape of the item.
+     *
+     * @param aParent is the parent #GERBER_DRAW_ITEM which is actually drawn.
+     * @return the shape of the item.
+     */
+    SHAPE_POLY_SET* GetApertureMacroShape( const GERBER_DRAW_ITEM* aParent,
+                                           const VECTOR2I&         aShapePos );
+
+    /**
+     * The name of the aperture macro as defined like %AMVB_RECTANGLE* (name is VB_RECTANGLE)
+     */
+     wxString      m_AmName;
+
+    /**
+     * A sequence of AM_PRIMITIVEs
+     */
+    std::vector<AM_PRIMITIVE> m_PrimitivesList;
+
+    /*  A deferred parameter can be defined in aperture macro,
+     *  but outside aperture primitives. Example
+     *  %AMRECTHERM*
+     *  $4=$3/2*    parameter $4 is half value of parameter $3
+     * m_localparamStack handle a list of local deferred parameters
+     */
+    AM_PARAMS m_LocalParamStack;
+
+private:
+    SHAPE_POLY_SET m_shape;         ///< The shape of the item, calculated by GetApertureMacroShape
+};
+
+
+/**
+ * Used by std:set<APERTURE_MACRO> instantiation which uses APERTURE_MACRO.name as its key.
+ */
+struct APERTURE_MACRO_less_than
+{
+    // a "less than" test on two APERTURE_MACROs (.name wxStrings)
+    bool operator()( const APERTURE_MACRO& am1, const APERTURE_MACRO& am2 ) const
+    {
+        return am1.m_AmName.Cmp( am2.m_AmName ) < 0;  // case specific wxString compare
+    }
+};
+
+
+/**
+ * A sorted collection of APERTURE_MACROS whose key is the name field in the APERTURE_MACRO.
+ */
+typedef std::set<APERTURE_MACRO, APERTURE_MACRO_less_than> APERTURE_MACRO_SET;
+typedef std::pair<APERTURE_MACRO_SET::iterator, bool>      APERTURE_MACRO_SET_PAIR;
+
+
+#endif  // ifndef APERTURE_MACRO_H
diff --git a/gerbview/dcode.cpp b/gerbview/dcode.cpp
index 5a7961881a..5c619fe2b3 100644
--- a/gerbview/dcode.cpp
+++ b/gerbview/dcode.cpp
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
  * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/gerbview/dcode.h b/gerbview/dcode.h
index a03c0efdfb..c75c137a1a 100644
--- a/gerbview/dcode.h
+++ b/gerbview/dcode.h
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1992-2010 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
- * Copyright (C) 1992-2021 KiCad Developers, see change_log.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/gerbview/gerber_file_image.cpp b/gerbview/gerber_file_image.cpp
index 43acd2970f..4e70465159 100644
--- a/gerbview/gerber_file_image.cpp
+++ b/gerbview/gerber_file_image.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 1992-2019 Jean-Pierre Charras  jp.charras at wanadoo.fr
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
diff --git a/gerbview/gerber_file_image.h b/gerbview/gerber_file_image.h
index e01d4448a4..4fc7e90f54 100644
--- a/gerbview/gerber_file_image.h
+++ b/gerbview/gerber_file_image.h
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2010-2019 Jean-Pierre Charras  jp.charras at wanadoo.fr
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -31,12 +31,9 @@
 #include <dcode.h>
 #include <gerber_draw_item.h>
 #include <am_primitive.h>
+#include <aperture_macro.h>
 #include <gbr_netlist_metadata.h>
 
-// An useful macro used when reading gerber files;
-#define IsNumber( x ) ( ( ( (x) >= '0' ) && ( (x) <='9' ) )   \
-                       || ( (x) == '-' ) || ( (x) == '+' )  || ( (x) == '.' ) )
-
 typedef std::vector<GERBER_DRAW_ITEM*> GERBER_DRAW_ITEMS;
 
 class GERBVIEW_FRAME;
diff --git a/gerbview/rs274_read_XY_and_IJ_coordinates.cpp b/gerbview/rs274_read_XY_and_IJ_coordinates.cpp
index fc4894b73d..952b005611 100644
--- a/gerbview/rs274_read_XY_and_IJ_coordinates.cpp
+++ b/gerbview/rs274_read_XY_and_IJ_coordinates.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2010-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
- * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -68,6 +68,14 @@ int scaletoIU( double aCoord, bool isMetric )
 }
 
 
+// An useful function used when reading gerber files
+static bool IsNumber( char x )
+{
+    return ( ( x >= '0' ) && ( x <='9' ) )
+           || ( x == '-' ) || ( x == '+' )  || ( x == '.' );
+}
+
+
 VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& aText, bool aExcellonMode )
 {
     VECTOR2I pos( 0, 0 );