diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index 3655a91a7..12947eca7 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -77,9 +77,16 @@ sub load {
     my ($file) = @_;
     
     my $ini = __PACKAGE__->read_ini($file);
+    return $class->load_ini_hash($ini->{_});
+}
+
+sub load_ini_hash {
+    my $class = shift;
+    my ($ini_hash) = @_;
+    
     my $config = $class->new;
-    foreach my $opt_key (keys %{$ini->{_}}) {
-        ($opt_key, my $value) = _handle_legacy($opt_key, $ini->{_}{$opt_key});
+    foreach my $opt_key (keys %$ini_hash) {
+        ($opt_key, my $value) = _handle_legacy($opt_key, $ini_hash->{$opt_key});
         next if !defined $opt_key;
         $config->set_deserialize($opt_key, $value);
     }
@@ -119,7 +126,7 @@ sub _handle_legacy {
     if ($opt_key eq 'gcode_flavor' && $value eq 'makerbot') {
         $value = 'makerware';
     }
-    if ($opt_key eq 'fill_density' && defined($value) && $value <= 1) {
+    if ($opt_key eq 'fill_density' && defined($value) && $value !~ /%/ && $value <= 1) {
         # fill_density was turned into a percent value
         $value *= 100;
         $value = "$value";  # force update of the PV value, workaround for bug https://rt.cpan.org/Ticket/Display.html?id=94110
@@ -161,16 +168,22 @@ sub set_ifndef {
     }
 }
 
-sub save {
-    my $self = shift;
-    my ($file) = @_;
+sub as_ini {
+    my ($self) = @_;
     
     my $ini = { _ => {} };
     foreach my $opt_key (sort @{$self->get_keys}) {
         next if $Options->{$opt_key}{shortcut};
         $ini->{_}{$opt_key} = $self->serialize($opt_key);
     }
-    __PACKAGE__->write_ini($file, $ini);
+    return $ini;
+}
+
+sub save {
+    my $self = shift;
+    my ($file) = @_;
+    
+    __PACKAGE__->write_ini($file, $self->as_ini);
 }
 
 sub setenv {
@@ -382,7 +395,8 @@ sub write_ini {
     binmode $fh, ':utf8';
     my $localtime = localtime;
     printf $fh "# generated by Slic3r $Slic3r::VERSION on %s\n", "$localtime";
-    foreach my $category (sort keys %$ini) {
+    # make sure the _ category is the first one written
+    foreach my $category (sort { ($a eq '_') ? -1 : ($a cmp $b) } keys %$ini) {
         printf $fh "\n[%s]\n", $category if $category ne '_';
         foreach my $key (sort keys %{$ini->{$category}}) {
             printf $fh "%s = %s\n", $key, $ini->{$category}{$key};
@@ -406,7 +420,7 @@ sub read_ini {
         next if /^\s+/;
         next if /^$/;
         next if /^\s*#/;
-        if (/^\[(\w+)\]$/) {
+        if (/^\[(.+?)\]$/) {
             $category = $1;
             next;
         }
diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm
index 4d152a4a7..448a26e5f 100644
--- a/lib/Slic3r/GUI.pm
+++ b/lib/Slic3r/GUI.pm
@@ -3,6 +3,7 @@ use strict;
 use warnings;
 use utf8;
 
+use File::Basename qw(basename);
 use FindBin;
 use Slic3r::GUI::AboutDialog;
 use Slic3r::GUI::ConfigWizard;
@@ -25,7 +26,9 @@ use Wx::Event qw(EVT_CLOSE EVT_MENU EVT_IDLE);
 use base 'Wx::App';
 
 use constant MI_LOAD_CONF     => &Wx::NewId;
+use constant MI_LOAD_CONFBUNDLE => &Wx::NewId;
 use constant MI_EXPORT_CONF   => &Wx::NewId;
+use constant MI_EXPORT_CONFBUNDLE => &Wx::NewId;
 use constant MI_QUICK_SLICE   => &Wx::NewId;
 use constant MI_REPEAT_QUICK  => &Wx::NewId;
 use constant MI_QUICK_SAVE_AS => &Wx::NewId;
@@ -117,6 +120,8 @@ sub OnInit {
     {
         $fileMenu->Append(MI_LOAD_CONF, "&Load Config…\tCtrl+L", 'Load exported configuration file');
         $fileMenu->Append(MI_EXPORT_CONF, "&Export Config…\tCtrl+E", 'Export current configuration to file');
+        $fileMenu->Append(MI_LOAD_CONFBUNDLE, "&Load Config Bundle…", 'Load presets from a bundle');
+        $fileMenu->Append(MI_EXPORT_CONFBUNDLE, "&Export Config Bundle…", 'Export all presets to file');
         $fileMenu->AppendSeparator();
         $fileMenu->Append(MI_QUICK_SLICE, "Q&uick Slice…\tCtrl+U", 'Slice file');
         $fileMenu->Append(MI_QUICK_SAVE_AS, "Quick Slice and Save &As…\tCtrl+Alt+U", 'Slice file and save as');
@@ -132,7 +137,9 @@ sub OnInit {
         $fileMenu->AppendSeparator();
         $fileMenu->Append(wxID_EXIT, "&Quit", 'Quit Slic3r');
         EVT_MENU($frame, MI_LOAD_CONF, sub { $self->{skeinpanel}->load_config_file });
+        EVT_MENU($frame, MI_LOAD_CONFBUNDLE, sub { $self->{skeinpanel}->load_configbundle });
         EVT_MENU($frame, MI_EXPORT_CONF, sub { $self->{skeinpanel}->export_config });
+        EVT_MENU($frame, MI_EXPORT_CONFBUNDLE, sub { $self->{skeinpanel}->export_configbundle });
         EVT_MENU($frame, MI_QUICK_SLICE, sub { $self->{skeinpanel}->quick_slice;
                                                $repeat->Enable(defined $Slic3r::GUI::SkeinPanel::last_input_file) });
         EVT_MENU($frame, MI_REPEAT_QUICK, sub { $self->{skeinpanel}->quick_slice(reslice => 1) });
@@ -309,6 +316,21 @@ sub save_settings {
     Slic3r::Config->write_ini("$datadir/slic3r.ini", $Settings);
 }
 
+sub presets {
+    my ($class, $section) = @_;
+    
+    my %presets = ();
+    opendir my $dh, "$Slic3r::GUI::datadir/$section" or die "Failed to read directory $Slic3r::GUI::datadir/$section (errno: $!)\n";
+    foreach my $file (grep /\.ini$/i, readdir $dh) {
+        my $name = basename($file);
+        $name =~ s/\.ini$//;
+        $presets{$name} = "$Slic3r::GUI::datadir/$section/$file";
+    }
+    closedir $dh;
+    
+    return %presets;
+}
+
 sub have_version_check {
     my $class = shift;
     
diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm
index 7db156393..11ff0dae4 100644
--- a/lib/Slic3r/GUI/SkeinPanel.pm
+++ b/lib/Slic3r/GUI/SkeinPanel.pm
@@ -284,6 +284,100 @@ sub load_config_file {
     }
 }
 
+sub export_configbundle {
+    my $self = shift;
+    
+    eval {
+        # validate current configuration in case it's dirty
+        $self->config->validate;
+    };
+    Slic3r::GUI::catch_error($self) and return;
+    
+    my $dir = $last_config ? dirname($last_config) : $Slic3r::GUI::Settings->{recent}{config_directory} || $Slic3r::GUI::Settings->{recent}{skein_directory} || '';
+    my $filename = "Slic3r_config_bundle.ini";
+    my $dlg = Wx::FileDialog->new($self, 'Save presets bundle as:', $dir, $filename, 
+        FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+    if ($dlg->ShowModal == wxID_OK) {
+        my $file = $dlg->GetPath;
+        $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
+        Slic3r::GUI->save_settings;
+        
+        # leave default category empty to prevent the bundle from being parsed as a normal config file
+        my $ini = { _ => {} };
+        $ini->{settings}{$_} = $Slic3r::GUI::Settings->{_}{$_} for qw(autocenter mode);
+        $ini->{presets} = $Slic3r::GUI::Settings->{presets};
+        if (-e "$Slic3r::GUI::datadir/simple.ini") {
+            my $config = Slic3r::Config->load("$Slic3r::GUI::datadir/simple.ini");
+            $ini->{simple} = $config->as_ini->{_};
+        }
+        
+        foreach my $section (qw(print filament printer)) {
+            my %presets = Slic3r::GUI->presets($section);
+            foreach my $preset_name (keys %presets) {
+                my $config = Slic3r::Config->load($presets{$preset_name});
+                $ini->{"$section:$preset_name"} = $config->as_ini->{_};
+            }
+        }
+        
+        Slic3r::Config->write_ini($file, $ini);
+    }
+    $dlg->Destroy;
+}
+
+sub load_configbundle {
+    my $self = shift;
+    
+    my $dir = $last_config ? dirname($last_config) : $Slic3r::GUI::Settings->{recent}{config_directory} || $Slic3r::GUI::Settings->{recent}{skein_directory} || '';
+    my $dlg = Wx::FileDialog->new($self, 'Select configuration to load:', $dir, "config.ini", 
+            FILE_WILDCARDS->{ini}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+    return unless $dlg->ShowModal == wxID_OK;
+    my ($file) = $dlg->GetPaths;
+    $dlg->Destroy;
+    
+    $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file);
+    Slic3r::GUI->save_settings;
+    
+    # load .ini file
+    my $ini = Slic3r::Config->read_ini($file);
+    
+    if ($ini->{settings}) {
+        $Slic3r::GUI::Settings->{_}{$_} = $ini->{settings}{$_} for keys %{$ini->{settings}};
+        Slic3r::GUI->save_settings;
+    }
+    if ($ini->{presets}) {
+        $Slic3r::GUI::Settings->{presets} = $ini->{presets};
+        Slic3r::GUI->save_settings;
+    }
+    if ($ini->{simple}) {
+        my $config = Slic3r::Config->load_ini_hash($ini->{simple});
+        $config->save("$Slic3r::GUI::datadir/simple.ini");
+        if ($self->{mode} eq 'simple') {
+            foreach my $tab (values %{$self->{options_tabs}}) {
+                $tab->load_config($config) for values %{$self->{options_tabs}};
+            }
+        }
+    }
+    my $imported = 0;
+    foreach my $ini_category (sort keys %$ini) {
+        next unless $ini_category =~ /^(print|filament|printer):(.+)$/;
+        my ($section, $preset_name) = ($1, $2);
+        my $config = Slic3r::Config->load_ini_hash($ini->{$ini_category});
+        $config->save(sprintf "$Slic3r::GUI::datadir/%s/%s.ini", $section, $preset_name);
+        $imported++;
+    }
+    if ($self->{mode} eq 'expert') {
+        foreach my $tab (values %{$self->{options_tabs}}) {
+            $tab->load_presets;
+        }
+    }
+    my $message = sprintf "%d presets successfully imported.", $imported;
+    if ($self->{mode} eq 'simple' && $Slic3r::GUI::Settings->{_}{mode} eq 'expert') {
+        Slic3r::GUI::show_info($self, "$message You need to restart Slic3r to make the changes effective.");
+    } else {
+        Slic3r::GUI::show_info($self, $message);
+    }
+}
+
 sub load_config {
     my $self = shift;
     my ($config) = @_;
diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm
index 493938979..f4e72ab65 100644
--- a/lib/Slic3r/GUI/Tab.pm
+++ b/lib/Slic3r/GUI/Tab.pm
@@ -345,16 +345,13 @@ sub load_presets {
         name    => '- default -',
     }];
     
-    opendir my $dh, "$Slic3r::GUI::datadir/" . $self->name or die "Failed to read directory $Slic3r::GUI::datadir/" . $self->name . " (errno: $!)\n";
-    foreach my $file (sort grep /\.ini$/i, readdir $dh) {
-        my $name = basename($file);
-        $name =~ s/\.ini$//;
+    my %presets = Slic3r::GUI->presets($self->name);
+    foreach my $preset_name (keys %presets) {
         push @{$self->{presets}}, {
-            file => "$Slic3r::GUI::datadir/" . $self->name . "/$file",
-            name => $name,
+            name => $preset_name,
+            file => $presets{$preset_name},
         };
     }
-    closedir $dh;
     
     $self->{presets_choice}->Clear;
     $self->{presets_choice}->Append($_->{name}) for @{$self->{presets}};