Index: src/sas/sasgui/perspectives/file_converter/converter_panel.py
===================================================================
--- src/sas/sasgui/perspectives/file_converter/converter_panel.py	(revision 5451a785d13789c5b569c510919de49fd80648ef)
+++ src/sas/sasgui/perspectives/file_converter/converter_panel.py	(revision b7c21a7ddf745993873a2b28e2b3fe37d75cb427)
@@ -116,4 +116,34 @@
                     sasentry_attrs=entry_attrs)
 
+    def convert_to_red2d(self, filepath, x, y, frame_data):
+        """
+        Writes Data2D objects to Red2D .dat files. If more than one frame is
+        provided, the frame number will be appended to the filename of each
+        file written.
+
+        :param filepath: The filepath to write to
+        :param x: The x column of the data
+        :param y: The y column of the data
+        :param frame_data: A dictionary of the form frame_number: data, where
+        data is a 2D numpy array containing the intensity data
+        """
+        filename = os.path.split(filepath)[-1]
+        filepath = os.path.split(filepath)[0]
+        writer = Red2DWriter()
+
+        for i, frame in frame_data.iteritems():
+            # If more than 1 frame is being exported, append the frame
+            # number to the filename
+            if len(frame_data) > 1:
+                frame_filename = filename.split('.')
+                frame_filename[0] += str(i+1)
+                frame_filename = '.'.join(frame_filename)
+            else:
+                frame_filename = filename
+
+            data_i = frame.reshape((len(x),1))
+            data_info = Data2D(data=data_i, qx_data=x, qy_data=y)
+            writer.write(os.path.join(filepath, frame_filename), data_info)
+
     def extract_ascii_data(self, filename):
         """
@@ -169,4 +199,34 @@
 
         return qdata, iqdata
+
+    def extract_bsl_data(self, filename):
+        """
+        Extracts data from a 2D BSL file
+
+        :param filename: The header file to extract the data from
+        :return x_data: A 1D array containing all the x coordinates of the data
+        :return y_data: A 1D array containing all the y coordinates of the data
+        :return frame_data: A dictionary of the form frame_number: data, where
+        data is a 2D numpy array containing the intensity data
+        """
+        loader = BSLLoader(filename)
+        frames = [0]
+        if loader.n_frames > 1:
+            params = self.ask_frame_range(loader.n_frames)
+            frames = params['frames']
+        frame_data = {}
+
+        for frame in frames:
+            loader.frame = frame
+            frame_data[frame] = loader.load_data()
+
+        # TODO: Tidy this up
+        # Prepare axes values (arbitrary scale)
+        x_data = []
+        y_data = range(loader.n_pixels) * loader.n_rasters
+        for i in range(loader.n_rasters):
+            x_data += [i] * loader.n_pixels
+
+        return x_data, y_data, frame_data
 
     def ask_frame_range(self, n_frames):
@@ -231,40 +291,9 @@
                 qdata, iqdata = self.extract_otoko_data(self.q_input.GetPath())
             else: # self.data_type == 'bsl'
-                # TODO: Refactor this into an extract_bsl_data method
-                loader = BSLLoader(self.iq_input.GetPath())
-                frames = [0]
-                if loader.n_frames > 1:
-                    params = self.ask_frame_range(loader.n_frames)
-                    frames = params['frames']
-                data = {}
-
-                for frame in frames:
-                    loader.frame = frame
-                    data[frame] = loader.load_data()
-
-                # TODO: Tidy this up
-                # Prepare axes values (arbitrary scale)
-                data_x = []
-                data_y = range(loader.n_pixels) * loader.n_rasters
-                for i in range(loader.n_rasters):
-                    data_x += [i] * loader.n_pixels
+                x_data, y_data, frame_data = self.extract_bsl_data(
+                    self.iq_input.GetPath())
 
                 file_path = self.output.GetPath()
-                filename = os.path.split(file_path)[-1]
-                file_path = os.path.split(file_path)[0]
-                for i, frame in data.iteritems():
-                    # If more than 1 frame is being exported, append the frame
-                    # number to the filename
-                    if len(data) > 1:
-                        frame_filename = filename.split('.')
-                        frame_filename[0] += str(i+1)
-                        frame_filename = '.'.join(frame_filename)
-                    else:
-                        frame_filename = filename
-
-                    data_i = frame.reshape((loader.n_pixels*loader.n_rasters,1))
-                    data_info = Data2D(data=data_i, qx_data=data_x, qy_data=data_y)
-                    writer = Red2DWriter()
-                    writer.write(os.path.join(file_path, frame_filename), data_info)
+                self.convert_to_red2d(file_path, x_data, y_data, frame_data)
 
                 wx.PostEvent(self.parent.manager.parent,
@@ -363,5 +392,5 @@
     def show_detector_window(self, event):
         """
-        Show the window for inputting :class:`~sas.sascalc.dataloader.data_info.Detector~` metadata
+        Show the window for inputting Detector metadata
         """
         if self.meta_frames != []:
@@ -377,5 +406,5 @@
     def show_sample_window(self, event):
         """
-        Show the window for inputting :class:`~sas.sascalc.dataloader.data_info.Sample~` metadata
+        Show the window for inputting Sample metadata
         """
         if self.meta_frames != []:
@@ -391,5 +420,5 @@
     def show_source_window(self, event):
         """
-        Show the window for inputting :class:`~sas.sascalc.dataloader.data_info.Source~` metadata
+        Show the window for inputting Source metadata
         """
         if self.meta_frames != []:
