diff --git a/picture.admin.inc b/picture.admin.inc
index e7f5cc9..59e6800 100644
--- a/picture.admin.inc
+++ b/picture.admin.inc
@@ -216,3 +216,132 @@ function picture_admin_settings($form, &$form_state) {
 
   return system_settings_form($form);
 }
+
+/**
+ * Choose which picture groups are available in the CKEditor image dialog.
+ */
+function picture_ckeditor_settings() {
+  $form = array();
+  $picture_groups = picture_mapping_load();
+  $ckeditor_groups = array();
+
+  // check if picture group mappings have been configured before proceeding.
+  if ($picture_groups) {
+    // create a settings form.
+    $form['description'] = array(
+      '#type' => 'item',
+      '#title' => t('Choose which picture groups will be available in the
+      CKEditor image dialog.'),
+    );
+
+    //retrieve pre-existing settings.
+    $ckeditor_groups = variable_get('picture_ckeditor_groups', array());
+
+    // loop through each picture group and place a checkbox and weight.
+    foreach ($picture_groups as $picture_group) {
+      $machine_name = $picture_group->machine_name;
+      $form[$machine_name] = array(
+        '#type' => 'fieldset',
+        '#title' => t('"@name" picture group', array('@name' => $machine_name)),
+      );
+      $form[$machine_name][$machine_name . '_enabled'] = array(
+        '#type' => 'checkbox',
+        '#default_value' => isset($ckeditor_groups[$machine_name]) ?
+          $ckeditor_groups[$machine_name]['enabled'] : 0,
+        '#title' => t('Include "@name" picture group in the CKEditor image
+        dialog', array('@name' => $machine_name)),
+      );
+      $form[$machine_name][$machine_name . '_weight'] = array(
+        '#type' => 'select',
+        '#title' => t('Weight'),
+        '#options' => array(
+          '1' => t('1'),
+          '2' => t('2'),
+          '3' => t('3'),
+          '4' => t('4'),
+          '5' => t('5'),
+          '6' => t('6'),
+          '7' => t('7'),
+          '8' => t('8'),
+          '9' => t('9'),
+          '10' => t('10'),
+        ),
+        '#default_value' => isset($ckeditor_groups[$machine_name]) ?
+          $ckeditor_groups[$machine_name]['weight'] : 1,
+        '#description' => t('Control the sort order of picture groups in the
+        CKEditor "size" drop-down. Higher weights sink to the bottom of the list.'),
+      );
+      $form[$machine_name][$machine_name . '_fallback'] = array(
+        '#type' => 'select',
+        '#title' => t('Fallback image style'),
+        '#options' => drupal_map_assoc(array_keys(image_styles())),
+        '#default_value' => isset($ckeditor_groups[$machine_name]) ?
+          $ckeditor_groups[$machine_name]['fallback'] : NULL,
+      );
+    }
+
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => 'Save',
+    );
+  }
+  return $form;
+}
+
+/**
+ * Validate handler for the picture_ckeditor_settings form.
+ * It checks that a fallback image style is selected for every
+ * picture group that has been enabled for the CKEditor image dialog.
+ */
+function picture_ckeditor_settings_validate($form, &$form_state) {
+  $picture_groups = picture_mapping_load();
+  $ckeditor_groups = array();
+  foreach ($picture_groups as $picture_group) {
+    $machine_name = $picture_group->machine_name;
+    if ($form_state['values'][$machine_name . '_enabled'] == 1) {
+      if (empty($form_state['values'][$machine_name . '_fallback'])) {
+        form_set_error($machine_name . '_fallback',
+          t('Please choose a fallback image style for this picture group'));
+      }
+    }
+  }
+}
+
+/**
+ * Submit handler for the picture_ckeditor_settings form. Place chosen picture
+ * groups into the variables table, and generate a custom plugin file for
+ * CKEditor.
+ */
+function picture_ckeditor_settings_submit($form, &$form_state) {
+  $picture_groups = picture_mapping_load();
+  $ckeditor_groups = array();
+
+  // Loop each picture group and record the settings.
+  foreach ($picture_groups as $picture_group) {
+    $machine_name = $picture_group->machine_name;
+    $ckeditor_groups[$machine_name]['enabled'] =
+      $form_state['values'][$machine_name . '_enabled'];
+    $ckeditor_groups[$machine_name]['weight'] =
+      $form_state['values'][$machine_name . '_weight'];
+    $ckeditor_groups[$machine_name]['fallback'] =
+      $form_state['values'][$machine_name . '_fallback'];
+  }
+
+  uasort($ckeditor_groups, 'picture_compare_weights');
+  variable_set('picture_ckeditor_groups', $ckeditor_groups);
+  drupal_set_message(t('Your settings have been saved'));
+
+  // Generate the custom CKEditor plugin file
+
+}
+
+/**
+  * Helper function to sort picture groups for the CKEditor image dialog
+  */
+
+function picture_compare_weights($a, $b) {
+  if ($a['weight'] == $b['weight']) {
+    return 0;
+  }
+  return ($a['weight'] < $b['weight']) ? -1 : 1;
+}
diff --git a/picture.info b/picture.info
index 59cc9da..75d4bbe 100644
--- a/picture.info
+++ b/picture.info
@@ -4,3 +4,4 @@ core = 7.x
 dependencies[] = breakpoints
 configure = admin/config/media/picture
 package = Picture
+stylesheets[all][] = picture_wysiwyg.css
diff --git a/picture.module b/picture.module
index 523b24c..fb6478c 100644
--- a/picture.module
+++ b/picture.module
@@ -90,6 +90,17 @@ function picture_menu() {
     }
   }
 
+  $items['admin/config/media/picture/ckeditor'] = array(
+    'title' => 'CKEditor',
+    'type' => MENU_LOCAL_TASK,
+    'description' => 'Choose picture groups to present in the CKEditor image dialog',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('picture_ckeditor_settings'),
+    'access arguments' => array('administer picture'),
+    'file' => 'picture.admin.inc',
+    'weight' => 0,
+  );
+
   return $items;
 }
 
@@ -579,7 +590,7 @@ function theme_picture_formatter_colorbox($variables) {
       'fragment' => $id,
       'html' => TRUE,
     );
-    
+
     // Do not load picture automatically.
     $colorbox = str_replace('span data-picture=""', 'span data-picture-lazy="lazy"', $colorbox);
     $output = l($output, current_path(), $options) . $colorbox;
@@ -687,6 +698,12 @@ function theme_picture($variables) {
         $attributes['data-' . $key] = $variables[$key];
       }
     }
+    // Add attributes that are already prefixed by 'data-'
+    foreach (array('data-picture-group', 'data-picture-align') as $key) {
+      if (isset($variables[$key])) {
+        $attributes[$key] = $variables[$key];
+      }
+    }
     $output[] = '<span data-picture=""' . drupal_attributes($attributes) . '>';
 
     // Add source tags to the output.
@@ -935,3 +952,147 @@ function picture_file_formatter_picture_settings($form, &$form_state, $settings)
 
   return $element;
 }
+
+/**
+ * Implements hook_filter_info()
+ */
+function picture_filter_info() {
+  $filters = array();
+  $filters['picture'] = array(
+    'title' => t('Make images responsive with the picture module'),
+    'description' => t('Replace img tags with markup that contains media width
+    breakpoints. The appropriate image file size will be chosen.'),
+    'process callback' => '_picture_filter_process',
+    'tips callback' => '_picture_filter_tips',
+    //@TODO remove following cache line when development is finished.
+    'cache' => FALSE,
+    );
+
+  return $filters;
+}
+
+/**
+ * Process callback for inline image filter
+ */
+function _picture_filter_process($text, $filter) {
+  // Find all img tags with a data-picture-group.
+  preg_match_all('/<img.*?data-picture-group=".*?>/i', $text, $images);
+
+  if (!empty($images[0])) {
+    foreach ($images[0] as $image) {
+      // create the render array expected by theme_picture_formatter
+      $image_render_array = _picture_filter_prepare_image($image);
+
+      // get the responsive markup for this image
+      $new_markup = theme('picture_formatter', $image_render_array);
+
+      //replace the original img tag with the responsive markup
+      $text = str_replace($image, $new_markup, $text);
+    }
+  }
+  return $text;
+}
+
+/**
+ * Prepare a Render Array for theme_picture_formatter(...)
+ * similar to picture_field_formatter_picture_view(...)
+ * with modifications for inline images
+ *
+ * @param $image
+ *   an img tag
+ */
+function _picture_filter_prepare_image($image) {
+  // Parse the tag as xml.
+  $xml = simplexml_load_string('<image>' . html_entity_decode($image, ENT_QUOTES, "utf-8") . '</image>');
+  if (isset($xml->img[0]) && is_object($xml->img[0])) {
+    $attributes = array();
+    foreach ($xml->img[0]->attributes() as $a => $b) {
+      $attributes[$a] = (string)$b;
+    }
+  }
+
+  $image_render_array = array();
+  $breakpoint_styles = array();
+  $fallback_image_style = '';
+  $group_name = $attributes['data-picture-group'];
+  $mappings = picture_mapping_load($group_name);
+
+  if ($mappings) {
+    foreach ($mappings->mapping as $breakpoint_name => $multipliers) {
+      if (!empty($multipliers)) {
+        foreach ($multipliers as $multiplier => $image_style) {
+          if (!empty($image_style)) {
+            if (empty($fallback_image_style)) {
+              $fallback_image_style = $image_style;
+            }
+            if (!isset($breakpoint_styles[$breakpoint_name])) {
+              $breakpoint_styles[$breakpoint_name] = array();
+            }
+            $breakpoint_styles[$breakpoint_name][$multiplier] = $image_style;
+          }
+        }
+      }
+    }
+  }
+
+  // figure out the schema for the file since theme_picture expects
+  // a file uri, not the root relative path
+  // @TODO Please review this:
+  // I'm not sure how to get a 'uri' with a 'schema' (public or private...)
+  // knowing just the drupal root relative file path.
+  // This currently will work only with public files.
+  $file_root_relative = $attributes['src'];
+  $public_path = variable_get('file_public_path', conf_path() . '/files');
+  $uri = 'public://' . str_replace($public_path, '', $file_root_relative);
+  $uri = file_stream_wrapper_uri_normalize($uri);
+  $image_info = image_get_info($uri);
+  $picture_groups = variable_get('picture_ckeditor_groups', array());
+  $image_render_array = array(
+    '#theme' => 'picture_formatter',
+    '#attached' => array('library' => array(
+      array('picture', 'matchmedia'),
+      array('picture', 'picturefill'),
+      array('picture', 'picture.ajax'),
+    )),
+    '#item' => array(
+      'style_name' => $picture_groups[$attributes['data-picture-group']]
+        ['fallback'],
+      'uri' => $uri,
+      'width' => $image_info['width'],
+      'height' => $image_info['height'],
+      'data-picture-group' => $attributes['data-picture-group'],
+      'data-picture-align' => $attributes['data-picture-align'],
+      'alt' => $attributes['alt'],
+      'title' => $attributes['title'],
+      'filemime' => $image_info['mime_type'],
+    ),
+    '#image_style' => $picture_groups[$attributes['data-picture-group']]['fallback'],
+    '#breakpoints' => $breakpoint_styles,
+    '#path' => '',
+  );
+
+  return $image_render_array;
+
+}
+/**
+ * Implements picture filter tips callback.
+ */
+function _picture_filter_tips($filter, $format, $long = FALSE) {
+  return t('Images will be responsive, with a file size appropriate for the browser width. This functions only for local public files.');
+}
+
+/**
+ * Implements hook_page_alter()
+ *
+ * Add the image processing javascript to every page. This allows these scripts
+ * to get included in aggregation, which is probably good since there will be
+ * pictures needing this javascript on most pages. The library does not get
+ * added twice, even if it's attached to multiple fields that are also being
+ * displayed with responsive images. Maybe this should check that the
+ * page is not an admin theme page?
+ */
+function picture_page_alter(&$page) {
+  drupal_add_library('picture', 'matchmedia', TRUE);
+  drupal_add_library('picture', 'picturefill', TRUE);
+  drupal_add_library('picture', 'picture.ajax', TRUE);
+}
