Esempio n. 1
0
        /// <summary>
        /// Generate one or more GIF image files, and output references to them.
        /// </summary>
        /// <param name="offset">Visualization set file offset.</param>
        /// <param name="sb">String builder for the HTML output.</param>
        private void OutputVisualizationSet(int offset, StringBuilder sb)
        {
            const int IMAGE_SIZE         = 64;
            const int MAX_WIDTH_PER_LINE = 768;

            if (!mProject.VisualizationSets.TryGetValue(offset,
                                                        out VisualizationSet visSet))
            {
                sb.Append("Internal error - visualization set missing");
                Debug.Assert(false);
                return;
            }
            if (visSet.Count == 0)
            {
                sb.Append("Internal error - empty visualization set");
                Debug.Assert(false);
                return;
            }

            string imageDirFileName = Path.GetFileName(mImageDirPath);
            int    outputWidth      = 0;

            for (int index = 0; index < visSet.Count; index++)
            {
                string fileName = "vis" + offset.ToString("x6") + "_" + index.ToString("d2");

                int dispWidth, dispHeight;

                Visualization vis = visSet[index];
                if (vis is VisualizationAnimation)
                {
                    // Animated visualization.
                    VisualizationAnimation visAnim = (VisualizationAnimation)vis;
                    int frameDelay = PluginCommon.Util.GetFromObjDict(visAnim.VisGenParams,
                                                                      VisualizationAnimation.FRAME_DELAY_MSEC_PARAM, 330);
                    AnimatedGifEncoder encoder = new AnimatedGifEncoder();

                    // Gather list of frames.
                    for (int i = 0; i < visAnim.Count; i++)
                    {
                        Visualization avis = VisualizationSet.FindVisualizationBySerial(
                            mProject.VisualizationSets, visAnim[i]);
                        if (avis != null)
                        {
                            encoder.AddFrame(BitmapFrame.Create(avis.CachedImage), frameDelay);
                        }
                        else
                        {
                            Debug.Assert(false);        // not expected
                        }
                    }

#if false
                    // try feeding the animated GIF into our GIF unpacker
                    using (MemoryStream ms = new MemoryStream()) {
                        encoder.Save(ms);
                        Debug.WriteLine("TESTING");
                        UnpackedGif anim = UnpackedGif.Create(ms.GetBuffer());
                        anim.DebugDump();
                    }
#endif

                    // Create new or replace existing image file.
                    fileName += "_ani.gif";
                    string pathName = Path.Combine(mImageDirPath, fileName);
                    try {
                        using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
                            encoder.Save(stream, out dispWidth, out dispHeight);
                        }
                    } catch (Exception ex) {
                        // TODO: add an error report
                        Debug.WriteLine("Error creating animated GIF file '" + pathName + "': " +
                                        ex.Message);
                        dispWidth = dispHeight = 1;
                    }
                }
                else
                {
                    // Bitmap visualization.
                    //
                    // Encode a GIF the same size as the original bitmap.
                    GifBitmapEncoder encoder = new GifBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(vis.CachedImage));

                    // Create new or replace existing image file.
                    fileName += ".gif";
                    string pathName = Path.Combine(mImageDirPath, fileName);
                    try {
                        using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
                            encoder.Save(stream);
                        }
                    } catch (Exception ex) {
                        // Something went wrong with file creation.  We don't have an error
                        // reporting mechanism, so this will just appear as a broken or stale
                        // image reference.
                        // TODO: add an error report
                        Debug.WriteLine("Error creating GIF file '" + pathName + "': " +
                                        ex.Message);
                    }

                    dispWidth  = (int)vis.CachedImage.Width;
                    dispHeight = (int)vis.CachedImage.Height;
                }

                // Output thumbnail-size IMG element, preserving proportions.  I'm assuming
                // images will be small enough that generating a separate thumbnail would be
                // counter-productive.  This seems to look best if the height is consistent
                // across all visualization lines, but that can create some monsters (e.g.
                // a bitmap that's 1 pixel high and 40 wide), so we cap the width.
                int    dimMult = IMAGE_SIZE;
                double maxDim  = dispHeight;
                if (dispWidth > dispHeight * 2)
                {
                    // Too proportionally wide, so use the width as the limit.  Allow it to
                    // up to 2x the max width (which can't cause the thumb height to exceed
                    // the height limit).
                    maxDim   = dispWidth;
                    dimMult *= 2;
                }
                int thumbWidth  = (int)Math.Round(dimMult * (dispWidth / maxDim));
                int thumbHeight = (int)Math.Round(dimMult * (dispHeight / maxDim));
                //Debug.WriteLine(dispWidth + "x" + dispHeight + " --> " +
                //    thumbWidth + "x" + thumbHeight + " (" + maxDim + ")");

                if (outputWidth > MAX_WIDTH_PER_LINE)
                {
                    // Add a line break.  In "pre" mode the bitmaps just run off the right
                    // edge of the screen.  The way we're doing it is imprecise and doesn't
                    // flow with changes to the browser width, but it'll do for now.
                    sb.AppendLine("<br/>");
                    for (int i = 0; i < mColStart[(int)Col.Label]; i++)
                    {
                        sb.Append(' ');
                    }
                    outputWidth = 0;
                }
                else if (index != 0)
                {
                    sb.Append("&nbsp;");
                }
                outputWidth += thumbWidth;

                sb.Append("<img class=\"vis\" alt=\"vis\" src=\"");
                sb.Append(imageDirFileName);
                sb.Append('/');
                sb.Append(fileName);
                sb.Append("\" width=\"" + thumbWidth + "\" height=\"" + thumbHeight + "\"/>");
            }
        }
        private void SaveButton_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog fileDlg = new SaveFileDialog()
            {
                Filter        = Res.Strings.FILE_FILTER_GIF + "|" + Res.Strings.FILE_FILTER_ALL,
                FilterIndex   = 1,
                ValidateNames = true,
                AddExtension  = true,
                FileName      = mFileNameBase + ".gif"
            };

            if (fileDlg.ShowDialog() != true)
            {
                return;
            }
            string pathName = Path.GetFullPath(fileDlg.FileName);

            Debug.WriteLine("Save path: " + pathName);

            try {
                OutputSize item = (OutputSize)sizeComboBox.SelectedItem;
                if (mVis is VisWireframeAnimation)
                {
                    Debug.Assert(item.Width == item.Height);
                    AnimatedGifEncoder encoder = new AnimatedGifEncoder();
                    ((VisWireframeAnimation)mVis).EncodeGif(encoder, item.Width);

                    using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
                        encoder.Save(stream, out int dispWidth, out int dispHeight);
                    }
                }
                else
                {
                    BitmapSource outImage;
                    if (IsBitmap)
                    {
                        int scale = item.Width / (int)mVis.CachedImage.Width;
                        Debug.Assert(scale >= 1);
                        if (scale == 1)
                        {
                            outImage = mVis.CachedImage;
                        }
                        else
                        {
                            outImage = mVis.CachedImage.CreateScaledCopy(scale);
                        }
                    }
                    else
                    {
                        Debug.Assert(item.Width == item.Height);
                        outImage = Visualization.GenerateWireframeImage(mWireObj,
                                                                        item.Width, mVis.VisGenParams);
                    }

                    GifBitmapEncoder encoder = new GifBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(outImage));

#if false
                    // try feeding the GIF into our GIF unpacker
                    using (MemoryStream ms = new MemoryStream()) {
                        encoder.Save(ms);
                        Debug.WriteLine("TESTING");
                        UnpackedGif anim = UnpackedGif.Create(ms.GetBuffer());
                        anim.DebugDump();
                    }
#else
                    using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
                        encoder.Save(stream);
                    }
#endif
                }
            } catch (Exception ex) {
                // Error handling is a little sloppy, but this shouldn't fail often.
                MessageBox.Show(ex.Message, Res.Strings.ERR_FILE_GENERIC_CAPTION,
                                MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            // After successful save, close dialog box.
            DialogResult = true;
        }