예제 #1
0
        static int borderThickness = 1;   // It's just 1. Won't really change, but whatever. If you change it, things will get fucky.

        public static bool MakePDF(Ragecomic comic, string pdffile)
        {
            using (System.IO.FileStream fs = new FileStream(pdffile, FileMode.Create))
            {
                int rows   = (int)Math.Ceiling((double)comic.panels / 2);
                int width  = rowWidth * 2 + borderThickness * 3;
                int height = rowHeight * rows + borderThickness * rows + borderThickness; // 239 per row, plus 1 pixel border per row, plus 1 pixel extra border

                ZipFile drawImageZip  = new ZipFile();
                bool    hasDrawImages = comic.items.getDrawImageCount() > 0;

                if (hasDrawImages)
                {
                    drawImageZip.Dispose();
                    string addition = "";
                    int    nr       = 1;
                    while (File.Exists(pdffile + ".drawimages" + addition + ".zip"))
                    {
                        addition = "_" + (nr++).ToString();
                    }
                    drawImageZip = new ZipFile(pdffile + ".drawimages" + addition + ".zip");
                }


                // Create an instance of the document class which represents the PDF document itself.
                Rectangle pageSize = new Rectangle(width, height);
                Document  document = new Document(pageSize, 0, 0, 0, 0);
                // Create an instance to the PDF file by creating an instance of the PDF
                // Writer class using the document and the filestrem in the constructor.

                PdfWriter writer = PdfWriter.GetInstance(document, fs);

                document.AddAuthor("Derp");

                document.AddCreator("RagemakerToPDF");

                document.AddKeywords("rage, comic");

                document.AddSubject("A rage comic");

                document.AddTitle("A rage comic");
                // Open the document to enable you to write to the document

                document.Open();


                PdfContentByte cb = writer.DirectContent;

                // Fill background with white
                Rectangle rect = new iTextSharp.text.Rectangle(0, 0, width, height);
                rect.BackgroundColor = new BaseColor(255, 255, 255);
                cb.Rectangle(rect);

                // Draw grid on bottom if it isn't set to be on top.
                if (!comic.gridAboveAll && comic.showGrid)
                {
                    DrawGrid(cb, width, height, rows, comic);
                }

                //List<MyMedia.FontFamily> families =  MyMedia.Fonts.SystemFontFamilies.ToList();

                // This was a neat idea, but it's much too slow
                //List<string> files = FontFinder.GetFilesForFont("Courier New").ToList();

                //string filename = FontFinder.GetSystemFontFileName(families[0].)

                //Draw.Font testFont = new Draw.Font(new Draw.FontFamily("Courier New"),12f,Draw.FontStyle.Regular  | Draw.FontStyle.Bold);

                string courierPath     = FontFinder.GetSystemFontFileName("Courier New", true);
                string courierBoldPath = FontFinder.GetSystemFontFileName("Courier New", true, Draw.FontStyle.Bold);
                string tahomaPath      = FontFinder.GetSystemFontFileName("Tahoma", true, Draw.FontStyle.Bold);

                // Define base fonts
                Font[] fonts = new Font[3];
                fonts[0] = new Font(BaseFont.CreateFont(courierPath, BaseFont.CP1252, BaseFont.EMBEDDED));
                fonts[1] = new Font(BaseFont.CreateFont(courierBoldPath, BaseFont.CP1252, BaseFont.EMBEDDED));
                fonts[2] = new Font(BaseFont.CreateFont(tahomaPath, BaseFont.CP1252, BaseFont.EMBEDDED));

                /*fonts[0] = BaseFont.CreateFont("fonts/TRCourierNew.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
                 * fonts[1] = BaseFont.CreateFont("fonts/TRCourierNewBold.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
                 * fonts[2] = new Font(BaseFont.CreateFont("fonts/Tahoma-Bold.ttf", BaseFont.CP1252, BaseFont.EMBEDDED));*/

                int drawimageindex = 0;

                int index = 0;
                foreach (var item in comic.items)
                {
                    if (item is Face)
                    {
                        Face  face = (Face)item;
                        Image pdfImage;
                        System.Drawing.Image faceImage;
                        // If mirroring is necessary, we have to read the image via C# and use RotateFlip, as iTextSharp doesn't support mirroring.
                        if (face.mirrored)
                        {
                            // If it's a JPEG, open it with Flux.JPEG.Core, because the internal JPEG decoder (and also LibJpeg.NET) creates weird dithering artifacts with greyscale JPGs, which some of the rage faces are.
                            if (Path.GetExtension(face.file).ToLower() == ".jpeg" || Path.GetExtension(face.file).ToLower() == ".jpg")
                            {
                                FileStream jpegstream            = File.OpenRead("images/" + face.file);
                                FluxJpeg.Core.DecodedJpeg myJpeg = new JpegDecoder(jpegstream).Decode();

                                // Only use this JPEG decoder if the colorspace is Gray. Otherwise the normal one is just fine.
                                if (myJpeg.Image.ColorModel.colorspace == FluxJpeg.Core.ColorSpace.Gray)
                                {
                                    myJpeg.Image.ChangeColorSpace(FluxJpeg.Core.ColorSpace.YCbCr);
                                    faceImage = myJpeg.Image.ToBitmap();
                                }
                                else
                                {
                                    faceImage = System.Drawing.Image.FromFile("images/" + face.file);
                                }
                            }
                            else
                            {
                                faceImage = System.Drawing.Image.FromFile("images/" + face.file);
                            }

                            // Apply mirroring
                            faceImage.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX);
                            pdfImage = Image.GetInstance(faceImage, System.Drawing.Imaging.ImageFormat.Png);
                        }
                        else
                        {
                            // Just let iTextSharp handle it if no mirroring is required. Will also save space (presumably)
                            pdfImage = Image.GetInstance("images/" + face.file);
                        }

                        pdfImage.ScalePercent(face.scalex * 100, face.scaley * 100);
                        pdfImage.Rotation = -(float)Math.PI * face.rotation / 180.0f;
                        pdfImage.SetAbsolutePosition(item.x, (height - item.y) - pdfImage.ScaledHeight);

                        // Set opacity to proper value
                        if (face.opacity < 1)
                        {
                            PdfGState graphicsState = new PdfGState();
                            graphicsState.FillOpacity = face.opacity;
                            cb.SetGState(graphicsState);
                        }

                        cb.AddImage(pdfImage);

                        // Set back to normal
                        if (face.opacity < 1)
                        {
                            PdfGState graphicsState = new PdfGState();
                            graphicsState.FillOpacity = 1f;
                            cb.SetGState(graphicsState);
                        }
                    }

                    else if (item is DrawImage)
                    {
                        DrawImage drawimage = (DrawImage)item;

                        drawImageZip.AddEntry("drawimage_" + (drawimageindex++).ToString() + ".png", drawimage.imagedata);

                        System.Drawing.Image pngImage = System.Drawing.Image.FromStream(new MemoryStream(drawimage.imagedata));
                        Image pdfImage = Image.GetInstance(pngImage, System.Drawing.Imaging.ImageFormat.Png);

                        // Rotation is NOT to be applied. Ragemaker actually has a bug that causes it to save rotated images in their rotated form, but save the rotation value anyway
                        // Thus rotating the image by the rotation value will actually rotate them double compared to what they originally looked like
                        // The irony is that ragemaker *itself* cannot properly load an xml it created with this rotation value, as it will also apply the rotation
                        // As such, this tool is currently the only way to correctly display that .xml file as it was originally meant to look, not even ragemaker itself can properly load it again.
                        //pdfImage.Rotation = -(float)Math.PI * item.rotation / 180.0f;

                        pdfImage.SetAbsolutePosition(item.x, (height - item.y) - pdfImage.ScaledHeight);

                        // Opacity likewise seems to be baked in, and in fact the opacity value doesn't even exist.
                        // Implementing it anyway, in case it ever becomes a thing.
                        if (drawimage.opacity < 1)
                        {
                            PdfGState graphicsState = new PdfGState();
                            graphicsState.FillOpacity = drawimage.opacity;
                            cb.SetGState(graphicsState);
                        }
                        cb.AddImage(pdfImage);

                        // Set back to normal
                        if (drawimage.opacity < 1)
                        {
                            PdfGState graphicsState = new PdfGState();
                            graphicsState.FillOpacity = 1f;
                            cb.SetGState(graphicsState);
                        }
                    }


                    else if (item is Text)
                    {
                        int  padding = 4;
                        Text text    = (Text)item;

                        // Create template
                        PdfTemplate xobject = cb.CreateTemplate(text.width, text.height);

                        // Background color (if set)
                        if (text.bgOn)
                        {
                            Rectangle            bgRectangle = new Rectangle(0, 0, text.width, text.height);
                            System.Drawing.Color bgColor     = System.Drawing.ColorTranslator.FromHtml(text.bgColor);
                            rect.BackgroundColor = new BaseColor(bgColor.R, bgColor.G, bgColor.B, (int)Math.Floor(text.opacity * 255));

                            xobject.Rectangle(rect);
                        }

                        // Create text
                        Rectangle  textangle = new Rectangle(padding, 0, text.width - padding, text.height);
                        ColumnText ct        = new ColumnText(xobject);
                        ct.SetSimpleColumn(textangle);
                        Paragraph paragraph = new Paragraph(text.text);

                        Font myFont = fonts[text.style];



                        // More specific treatment if it's an AnyFont element which allows the user to select any font and styles, not just the normal 3 presets
                        // This isn't perfect, as the current FontFinder doesn't indicate whether he actually found an Italic/Bold typeface, hence it's not possible
                        // to determine whether faux-italic/faux-bold should be applied. Currently it will only work correctly if each used font has a specific typeface
                        // for the needed styles (bold or italic), otherwise incorrect results.
                        // TODO Fix, for example let FontFinder return array of strings, one of which is indicating the suffix that was found.
                        if (text is AnyFontText)
                        {
                            AnyFontText anyfont  = (AnyFontText)text;
                            string      fontname = anyfont.font;
                            string      fontfile = "";
                            if (anyfont.bold)
                            {
                                fontfile = FontFinder.GetSystemFontFileName(fontname, true, Draw.FontStyle.Bold);
                                int fontStyle = 0;
                                if (anyfont.italic)
                                {
                                    fontStyle |= Font.ITALIC;
                                }
                                if (anyfont.underline)
                                {
                                    fontStyle |= Font.UNDERLINE;
                                }
                                myFont = new Font(BaseFont.CreateFont(fontfile, BaseFont.CP1252, BaseFont.EMBEDDED), 100f, fontStyle);
                            }
                            else if (anyfont.italic)
                            {
                                fontfile = FontFinder.GetSystemFontFileName(fontname, true, Draw.FontStyle.Italic);
                                int fontStyle = 0;
                                if (anyfont.underline)
                                {
                                    fontStyle |= Font.UNDERLINE;
                                }
                                myFont = new Font(BaseFont.CreateFont(fontfile, BaseFont.CP1252, BaseFont.EMBEDDED), 100f, fontStyle);
                            }
                            else
                            {
                                fontfile = FontFinder.GetSystemFontFileName(fontname, true, Draw.FontStyle.Regular);
                                int fontStyle = 0;
                                if (anyfont.underline)
                                {
                                    fontStyle |= Font.UNDERLINE;
                                }
                                myFont = new Font(BaseFont.CreateFont(fontfile, BaseFont.CP1252, BaseFont.EMBEDDED), 100f, fontStyle);
                            }
                        }



                        myFont.Size = text.size;
                        System.Drawing.Color color = (System.Drawing.Color)(new System.Drawing.ColorConverter()).ConvertFromString(text.color);
                        myFont.Color        = new BaseColor(color.R, color.G, color.B, (int)Math.Floor(text.opacity * 255));
                        paragraph.Font      = myFont;
                        paragraph.Alignment = text.align == Text.ALIGN.LEFT ? PdfContentByte.ALIGN_LEFT : (text.align == Text.ALIGN.RIGHT ? PdfContentByte.ALIGN_RIGHT : PdfContentByte.ALIGN_CENTER);
                        paragraph.SetLeading(0, 1.12f);
                        ct.AddElement(paragraph);
                        ct.Go();


                        // Angle to radians
                        float angle = (float)Math.PI * text.rotation / 180.0f;

                        // Calculate Bounding Box size for correct placement later
                        GraphicsPath gp = new GraphicsPath();
                        gp.AddRectangle(new System.Drawing.Rectangle(0, 0, (int)Math.Round(text.width), (int)Math.Round(text.height)));
                        Matrix translateMatrix = new Matrix();
                        translateMatrix.RotateAt(text.rotation, new System.Drawing.PointF(text.width / 2, text.height / 2));
                        gp.Transform(translateMatrix);
                        var   gbp = gp.GetBounds();
                        float newWidth = gbp.Width, newHeight = gbp.Height;

                        // Create correct placement
                        // Background info: I rotate around the center of the text box, thus the center of the text box is what I attempt to place correctly with the initial .Translate()
                        AffineTransform transform = new AffineTransform();
                        transform.Translate(item.x + newWidth / 2 - text.width / 2, height - (item.y + newHeight / 2 - text.height / 2) - text.height);
                        transform.Rotate(-angle, text.width / 2, text.height / 2);

                        cb.AddTemplate(xobject, transform);
                    }


                    index++;
                }

                if (comic.gridAboveAll && comic.showGrid)
                {
                    DrawGrid(cb, width, height, rows, comic);
                }

                //document.Add(new Paragraph("Hello World!"));
                // Close the document

                document.Close();
                // Close the writer instance

                writer.Close();
                // Always close open filehandles explicity
                fs.Close();

                if (hasDrawImages)
                {
                    drawImageZip.Save();
                }
                drawImageZip.Dispose();
            }


            return(false);
        }
예제 #2
0
        public static void DrawGrid(PdfContentByte cb, int width, int height, int rows, Ragecomic comic)
        {
            if (!comic.showGrid)
            {
                return;
            }

            // Outer box
            Rectangle rect = new iTextSharp.text.Rectangle(0, 0, width, height);

            //rect.Border = iTextSharp.text.Rectangle.LEFT_BORDER | iTextSharp.text.Rectangle.RIGHT_BORDER;
            rect.Border      = iTextSharp.text.Rectangle.BOX;
            rect.BorderWidth = 1;
            rect.BorderColor = new BaseColor(0, 0, 0);
            cb.Rectangle(rect);


            int matricesCount = comic.gridLines.GetLength(0);


            cb.SetColorStroke(new BaseColor(0, 0, 0));
            PdfGState graphicsState = new PdfGState();

            graphicsState.FillOpacity = 0f;
            cb.SetGState(graphicsState);

            // The first dimension of the array represents "rows" in a sense.
            // And the second dimension has 5 values each, representing various gridlines.
            // Gridlines row format:
            // 0 - bottom left
            // 1 - center
            // 2 - bottom right
            // 3 - left diagonal
            // 4 - right diagonal
            // diagonals can be 0,1 or 2.
            // 0 - disabled
            // 1 - bottom left to top right
            // 2 - top left to bottom right
            for (int i = 0; i < matricesCount; i++)
            {
                int ipp = i + 1;

                // bottom left
                if (comic.gridLines[i, 0] > 0)
                {
                    cb.MoveTo(0, height - rowHeight * ipp - borderThickness * ipp);
                    cb.LineTo(borderThickness + rowWidth, height - rowHeight * ipp - borderThickness * ipp);
                    cb.Stroke();
                }

                // center vertical
                if (comic.gridLines[i, 1] > 0)
                {
                    cb.MoveTo(borderThickness + rowWidth, height - rowHeight * ipp - borderThickness * ipp);
                    cb.LineTo(borderThickness + rowWidth, height - rowHeight * i - borderThickness * i);
                    cb.Stroke();
                }

                // bottom right
                if (comic.gridLines[i, 2] > 0)
                {
                    cb.MoveTo(borderThickness + rowWidth, height - rowHeight * ipp - borderThickness * ipp);
                    cb.LineTo(borderThickness * 2 + rowWidth * 2, height - rowHeight * ipp - borderThickness * ipp);
                    cb.Stroke();
                }

                // left: bottom left to top right
                if (comic.gridLines[i, 3] == 1)
                {
                    cb.MoveTo(0, height - rowHeight * ipp - borderThickness * ipp);
                    cb.LineTo(borderThickness + rowWidth, height - rowHeight * i - borderThickness * i);
                    cb.Stroke();
                }
                // left: top left to bottom right
                else if (comic.gridLines[i, 3] == 2)
                {
                    cb.MoveTo(0, height - rowHeight * i - borderThickness * i);
                    cb.LineTo(borderThickness + rowWidth, height - rowHeight * ipp - borderThickness * ipp);
                    cb.Stroke();
                }

                // right: bottom left to top right
                if (comic.gridLines[i, 4] == 1)
                {
                    cb.MoveTo(borderThickness + rowWidth, height - rowHeight * ipp - borderThickness * ipp);
                    cb.LineTo(borderThickness * 2 + rowWidth * 2, height - rowHeight * i - borderThickness * i);
                    cb.Stroke();
                }
                // right: top left to bottom right
                else if (comic.gridLines[i, 4] == 2)
                {
                    cb.MoveTo(borderThickness + rowWidth, height - rowHeight * i - borderThickness * i);
                    cb.LineTo(borderThickness * 2 + rowWidth * 2, height - rowHeight * ipp - borderThickness * ipp);
                    cb.Stroke();
                }
            }

            // Lastly, the existence of the center gridline in the bottommost row is determined by the panel count
            if (comic.panels % 2 == 0)
            {
                int i   = matricesCount;
                int ipp = i + 1;

                // center vertical
                cb.MoveTo(borderThickness + rowWidth, height - rowHeight * ipp - borderThickness * ipp);
                cb.LineTo(borderThickness + rowWidth, height - rowHeight * i - borderThickness * i);
                cb.Stroke();
            }


            graphicsState.FillOpacity = 1f;
            cb.SetGState(graphicsState);
        }
예제 #3
0
        private async void LoadRageXML_Click(object sender, RoutedEventArgs e)
        {
            Ragecomic comic = new Ragecomic();

            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            //ofd.InitialDirectory = ".";
            ofd.RestoreDirectory = true;
            ofd.Filter           = "Ragemaker .xml file (*.xml)|*.xml";
            ofd.Title            = "Select ragemaker .xml file to convert to PDF";
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string filename = ofd.FileNames[0];

                // Open File
                using (FileStream fs = new FileStream(filename, FileMode.Open))
                {
                    XmlReaderSettings settings = new XmlReaderSettings();
                    settings.Async = true;

                    // Read XML
                    using (XmlReader reader = XmlReader.Create(fs, settings))
                    {
                        while (await reader.ReadAsync())
                        {
                            string elementName = reader.Name;
                            switch (elementName)
                            {
                            /*
                             * <panels>8</panels>
                             * <gridLinesArray>111001110011100</gridLinesArray>
                             * <gridAboveAll>true</gridAboveAll>
                             * <showGrid>true</showGrid>
                             * <redditWatermark>false</redditWatermark>
                             */
                            case "panels":
                                int panels = int.Parse(reader.ReadInnerXml());
                                status.Text += "panels: " + panels.ToString() + "\n";
                                comic.panels = panels;
                                break;

                            case "gridLinesArray":
                                string gridLinesArray = reader.ReadInnerXml();
                                status.Text += "gridLinesArray: " + gridLinesArray + "\n";
                                int matrices = gridLinesArray.Length / 5;
                                comic.gridLines = new int[matrices, 5];
                                for (var i = 0; i < gridLinesArray.Length; i++)
                                {
                                    int matrixIndex = (int)Math.Floor((double)i / 5);
                                    int subIndex    = i % 5;
                                    comic.gridLines[matrixIndex, subIndex] = int.Parse(gridLinesArray[i].ToString());
                                    //status.Text += comic.gridLines[i] + "\n";
                                }
                                //comic.panels = panels;
                                break;

                            case "gridAboveAll":
                                comic.gridAboveAll = bool.Parse(reader.ReadInnerXml());
                                status.Text       += "gridAboveAll: " + comic.gridAboveAll + "\n";
                                break;

                            case "showGrid":
                                comic.showGrid = bool.Parse(reader.ReadInnerXml());
                                status.Text   += "showGrid: " + comic.showGrid + "\n";
                                break;

                            case "redditWatermark":
                                comic.redditWatermark = bool.Parse(reader.ReadInnerXml());
                                status.Text          += "redditWatermark: " + comic.redditWatermark + "\n";
                                break;

                            case "Face":
                            case "Text":
                            case "AnyFont":
                            case "Draw":
                            case "Image":
                                if (reader.NodeType == XmlNodeType.EndElement)
                                {
                                    break;
                                }
                                using (XmlReader subtreeReader = reader.ReadSubtree())
                                {
                                    RageItem newItem = await RageItem.createRageItem(elementName, subtreeReader);

                                    comic.items.Add(newItem);
                                    status.Text += "new item: " + newItem.ToString() + "\n";
                                }
                                break;

                            default:
                                break;
                            }
                        }
                    }
                }
                status.Text += filename + " was parsed successfully.\n\n\nProceeding to PDF generation\n\n\n";

                RagecomicToPDF.MakePDF(comic, filename + ".pdf");
            }
            else
            {
                MessageBox.Show("error");
            }

            Thread thread = new Thread(LoadAndProcessRageXML);

            thread.Start();
        }