LoginSignup
0
0

More than 3 years have passed since last update.

iTextSharpでPDFの文字を置換する、のを超簡易版で(C#)

Last updated at Posted at 2019-12-28

ネットで探しても、あるのか無いのか。作ってみました。
あくまで基本的には、という温かい目で見てください。
簡単そうでなかなか・・・
とりあえず、ASCIIコード、つまり半角英文字と数字・記号が利用できる程度のもので、且つ"ABC"を'AAA'に置換する、という程度のものです。
PDFは漢字については、その文字コード(番号)を半角英数字で記述しています。(バイナリで0Aなら、半角数字で0Aと記述という具合です)
しかも、SJIS・UTF8は指定によりPDF文書ごとに・・・となっているようです。

サーチそのものはCONTENTSの中に出現する文字列をbyte配列の状態で比較しています。
ただ、このプログラムで取得されるのは、制御関係の半角英数字が混じっている長いbyte配列です。なので、制御系とマッチし てしまわないように5文字以上の長めの単語で使ってください。
ここから、制御の文字列ではない状態のケースのみで、マッチするか?という処理をする。というように改造していく感じだと思います。

        /// <summary>指定のPDFに、指定の文字列があれば、指定のbyte(初期値は半角SP)で埋めます。</summary>
        static private bool replace_PDF_textCONTENTS_proc(string in_in_filepath, string in_out_filepath, string in_moto_text,byte in_埋めるbyte ,int in_replace_count = 0)
        {
            if (File.Exists(in_in_filepath) == false)
                return false;

            byte[] tmp_sarch_bytes = System.Text.Encoding.UTF8.GetBytes(in_moto_text);
            PdfReader reader = new PdfReader(in_in_filepath);
            for (int i = 1; i <= reader.NumberOfPages; i++)
            {
                PdfDictionary dict = reader.GetPageN(i);
                PdfObject object2 = dict.GetDirectObject(PdfName.CONTENTS);
                if (object2 is PRStream)
                {
                    PRStream stream = (PRStream)object2;
                    byte[] data = PdfReader.GetStreamBytes(stream);

                    int match_count = 0;
                    for (int i = 0; i < data.Length - tmp_sarch_bytes.Length; i++)
                    {
                        byte type_by = data[i];



                        Func<bool> get_match = () =>
                        {
                            for (int p = 0; p < tmp_sarch_bytes.Length; p++)
                            {
                                if (data[i + p] != tmp_sarch_bytes[p])
                                    return false;
                            }
                            return true;
                        };
                        bool is_match = get_match();
                        if (is_match == false)
                            continue;
                        //
                        // 合致したケース
                        match_count++;
                        for (int p = 0; p < tmp_sarch_bytes.Length; p++)
                        {
                            data[i + p] = in_埋めるbyte;
                        }
                        if (in_replace_count != 0 && match_count == in_replace_count)   // 置換の回数指定があれば、その回数の置換で終了します。
                            break;
                    }

                    stream.SetData(data);
                }
            }

            try
            {
                PdfStamper stamper = new PdfStamper(reader, new FileStream(in_out_filepath, FileMode.Create));
                stamper.Close();
                reader.Close();
            }
            catch (Exception ex)
            {
            }
            finally
            {
                reader.Close();
            }

            return true;
        }

以下のは、異なる長さに置換できるのですが、置換後を""としたところ問題がありました。

WindowsのPDFビュワーでは問題なく表示できます。
ですが、PDFダイレクト対応プリンタ(Ricoh MPC5503)ではエラーで印刷できませんでした。
上の"ABC"を"AAA"にする、置き換え型では大丈夫でした。
文字列が無い、というのが厳密なPDF仕様ではアウトなのかもしれません・・・

        static private bool replace_PDF_textCONTENTS_proc(string in_in_filepath, string in_out_filepath, string in_moto_text,string in_new_text)
        {
            if (File.Exists(in_in_filepath) == false)
                return false;

            byte[] new_bytes = System.Text.Encoding.UTF8.GetBytes(in_new_text);

            byte[] tmp_sarch_bytes = System.Text.Encoding.UTF8.GetBytes(in_moto_text);
            PdfReader reader = new PdfReader(in_in_filepath);
            for (int page番号 = 1; page番号 <= reader.NumberOfPages; page番号++)   // このpage番号は1オリジンです
            {
                PdfDictionary dict = reader.GetPageN(page番号);
                PdfObject object2 = dict.GetDirectObject(PdfName.CONTENTS);
                if (object2 is PRStream)
                {
                    PRStream stream = (PRStream)object2;
                    byte[] data = PdfReader.GetStreamBytes(stream);
                    List<byte> new_data = new List<byte>();
                    //
                    // 制御の文字列(オペレータ)は以下に詳しく書かれています。
                    // http://www.kobu.com/docs/pdf/pdfxhand.htm
                    string debug_text_UTF8 = System.Text.Encoding.UTF8.GetString(data);
                    string debug_text_Unicode = System.Text.Encoding.Unicode.GetString(data);

                    int match_count = 0;
                    for (int i = 0; i < data.Length - tmp_sarch_bytes.Length; i++)
                    {
                        byte type_by = data[i];
                        char type_c = (char)type_by;


                        Func<bool> get_match = () =>
                        {
                            for (int p = 0; p < tmp_sarch_bytes.Length; p++)
                            {
                                if (data[i + p] != tmp_sarch_bytes[p])
                                    return false;
                            }
                            return true;
                        };
                        bool is_match = get_match();
                        if (is_match == false)
                        {
                            new_data.Add(data[i]);
                            continue;
                        }

                        //
                        // 合致したケース
                        match_count++;
                        new_data.AddRange(new_bytes);
                        i += tmp_sarch_bytes.Length;
                    }
                    //byte[] set_data = ;
                    stream.SetData(new_data.ToArray());
                }
            }

            try
            {
                PdfStamper stamper = new PdfStamper(reader, new FileStream(in_out_filepath, FileMode.Create));
                stamper.Close();
                reader.Close();
            }
            catch(Exception ex)
            {
            }

            reader.Close();

            return true;
        }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0