/// <summary>
        /// Draws the currently available user information
        /// (ID, tracking status) on the Image. If recording, this method
        /// also writes the user joints to the log-datastructure.
        /// </summary>
        private void drawAndLogUserInformation()
        {
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                int[] users = this.userGenerator.GetUsers();
                if (recording)
                {
                    movementData.Add(movementData.Keys.Count,
                                     new Dictionary <int, JointDictionary>());
                }

                foreach (int user in users)
                {
                    if (shouldPrintID)
                    {
                        Point3D com = this.userGenerator.GetCoM(user);
                        com = depthGenerator.ConvertRealWorldToProjective(com);

                        string label = "";
                        if (!this.shouldPrintState)
                        {
                            label += user;
                        }
                        else if (skeletonCapability.IsTracking(user))
                        {
                            label += user + " - Tracking";
                        }
                        else if (skeletonCapability.IsCalibrating(user))
                        {
                            label += user + " - Calibrating...";
                        }
                        else
                        {
                            label += user + " - Looking for pose";
                        }

                        using (Brush brush = new SolidBrush(ANTICOLORS[user % NCOLORS]))
                        {
                            g.DrawString(label, font_label,
                                         brush,
                                         com.X - TextRenderer.MeasureText(label, font_label).Width / 2,
                                         com.Y);
                        }
                    }
                    if ((shouldDrawSkeleton || recording) &&
                        skeletonCapability.IsTracking(user))
                    {
                        GetJoints(skeletonCapability, user, joints);
                        if (recording)
                        {
                            JointDictionary threeDPositions = new JointDictionary(true);
                            GetJoints3D(skeletonCapability, user, threeDPositions);
                            movementData[movementData.Keys.Count - 1].
                            Add(user, threeDPositions);
                        }

                        if (shouldDrawSkeleton)
                        {
                            DrawSkeleton(g, ANTICOLORS[user % NCOLORS], joints, 0.5f);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// The export logic.
        /// </summary>
        /// <param name="parameter">An object[] with the real parameters.
        /// Have a look at <see cref="ExportFrames"/> for a usage
        /// example.</param>
        private void doExport(object parameter)
        {
            object[] parameters = parameter as object[];
            if (parameters == null)
            {
                return;
            }

            // Export directory
            DirectoryInfo exportDir = parameters[10] as DirectoryInfo;

            if (exportDir == null)
            {
                return;
            }

            // Frame list
            List <int> frames = parameters[0] as List <int>;

            if (frames == null || frames.Count == 0)
            {
                return;
            }
            frames.Sort();

            // User list
            List <int> userIDs = parameters[1] as List <int>;

            if (userIDs == null)
            {
                return;
            }

            // Ignore List
            List <int> formerIgnoreList = new List <int>(UsersToIgnore);

            UsersToIgnore.Clear();
            List <int> occuringUsers = GetUserStatistics(frames).Keys.ToList <int>();

            foreach (int user in occuringUsers)
            {
                if (!userIDs.Contains(user))
                {
                    UsersToIgnore.Add(user);
                }
            }

            // The rest of parameters
            bool AnnotationsIn2D         = (bool)parameters[2];
            bool AnnotationsIn3D         = (bool)parameters[3];
            bool ExportRelativePathNames = (bool)parameters[4];
            bool ImageOrDepth            = (bool)parameters[5];
            bool DrawBackground          = (bool)parameters[6];
            bool DrawSkeleton            = (bool)parameters[7];
            bool DrawHighlights          = (bool)parameters[8];
            bool DrawLabels = (bool)parameters[9];

            // Number format
            int max = frames[frames.Count - 1];
            int characters;

            if (max == 0)
            {
                characters = 1;
            }
            else
            {
                characters = (int)Math.Ceiling(Math.Log10(max));
            }
            String exportFormatString = "d" + characters;

            // The export xml files.
            ImageDictionary exportedIndex2D = new ImageDictionary(false);

            exportedIndex2D.XmlExportFrameFileList = new Dictionary <int, string>();
            exportedIndex2D.XmlOmitPoints          = (userIDs.Count == 0);

            ImageDictionary exportedIndex3D = new ImageDictionary(true);

            exportedIndex3D.XmlExportFrameFileList = new Dictionary <int, string>();
            exportedIndex3D.XmlOmitPoints          = (userIDs.Count == 0);

            String filename;
            String export_filename_suffix = "";

            lock (RUN_CONTROL_LOCK)
            {
                try
                {
                    StopPlayback();

                    lock (EXPORT_LOCK)
                    {
                        // Configure for export
                        DrawSkeletonMesh         = DrawSkeleton;
                        DrawSensorData           = true;
                        this.ImageOrDepth        = ImageOrDepth;
                        this.DrawBackground      = DrawBackground;
                        this.DrawUserHighlight   = DrawHighlights;
                        this.DrawUserInformation = DrawLabels;

                        if (DrawSkeleton)
                        {
                            export_filename_suffix += "s";
                        }
                        if (!DrawSensorData)
                        {
                            export_filename_suffix += "a";
                        }
                        if (!ImageOrDepth)
                        {
                            export_filename_suffix += "d";
                        }
                        if (!DrawBackground)
                        {
                            export_filename_suffix += "b";
                        }
                        if (DrawUserHighlight)
                        {
                            export_filename_suffix += "h";
                        }
                        if (DrawUserInformation)
                        {
                            export_filename_suffix += "l";
                        }

                        if (export_filename_suffix.Length > 0)
                        {
                            export_filename_suffix = "-" + export_filename_suffix;
                        }

                        for (int frameIndex = 0; frameIndex < frames.Count; frameIndex++)
                        {
                            SeekFrame(frames[frameIndex]);
                            RequestUpdate(false);
                            String relative_filename = frames[frameIndex].ToString(exportFormatString) +
                                                       export_filename_suffix + ".png";
                            filename = Path.Combine(exportDir.FullName,
                                                    relative_filename);


                            lock (ImageLock)
                            {
                                bitmap.Save(filename, ImageFormat.Png);
                            }

                            // Get the user positions in this frame
                            Dictionary <int, JointDictionary> frame_positions2D =
                                new Dictionary <int, JointDictionary>();
                            Dictionary <int, JointDictionary> frame_positions3D =
                                new Dictionary <int, JointDictionary>();
                            if (UserLocationInformation.ContainsKey(frames[frameIndex]))
                            {
                                foreach (int user in UserLocationInformation[frames[frameIndex]].Keys)
                                {
                                    if (userIDs.Contains(user))
                                    {
                                        frame_positions3D.Add(user, new JointDictionary(
                                                                  UserLocationInformation[frames[frameIndex]][user]));
                                        frame_positions2D.Add(user, new JointDictionary(
                                                                  Convert3Dto2D(UserLocationInformation[frames[frameIndex]][user], depthGenerator)));
                                    }
                                }
                            }
                            exportedIndex2D.Add(frames[frameIndex], frame_positions2D);
                            if (!ExportRelativePathNames)
                            {
                                exportedIndex2D.XmlExportFrameFileList.Add(
                                    frames[frameIndex], filename);
                            }
                            else
                            {
                                exportedIndex2D.XmlExportFrameFileList.Add(
                                    frames[frameIndex], relative_filename);
                            }
                            exportedIndex3D.Add(frames[frameIndex], frame_positions3D);
                            if (!ExportRelativePathNames)
                            {
                                exportedIndex3D.XmlExportFrameFileList.Add(
                                    frames[frameIndex], filename);
                            }
                            else
                            {
                                exportedIndex3D.XmlExportFrameFileList.Add(
                                    frames[frameIndex], relative_filename);
                            }


                            onExportMadeProgress(
                                (float)(frameIndex + 1) / (float)frames.Count * 100, frameIndex + 1, frames.Count);
                            if (export_cancelled)
                            {
                                return;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    onExportFailed(e.Message);
                    return;
                }

                // Reset ignore list
                UsersToIgnore.Clear();
                UsersToIgnore.AddRange(formerIgnoreList);

                if (!AnnotationsIn2D)
                {
                    exportedIndex2D = null;
                }
                if (!AnnotationsIn3D)
                {
                    exportedIndex3D = null;
                }
            }

            // Report success.
            Thread reporter = new Thread(onExportFinished);

            reporter.Start(new object[] { this, exportDir, frames, userIDs,
                                          exportedIndex2D, exportedIndex3D, ExportRelativePathNames,
                                          export_filename_suffix });
        }