20210725のC#に関する記事は7件です。

Oculus Integrationを使用しないUnityVRの入力スターターキット

準備 UnityVRテンプレートから超簡単にワールド内を移動できるようになります。 検証エディタ:Unity2021.1 UnityHubで新しいプロジェクトを作る際にテンプレート「VR」を選択して作成。 プロジェクト設定のXRPluginManagementでOculusをチェック 以下のスクリプトを適当にアセットフォルダに作成します。 VR_Input.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; public class VR_Input : MonoBehaviour { public enum InputVRBool { Primary, Secondary, Trigger, Grip, Menu, PrimaryAxis }; public enum InputVRFloat { Trigger, Grip }; public static bool GetPresseButton(XRNode node, InputVRBool inputVRBool) { bool value = false; var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { switch (inputVRBool) { case InputVRBool.Trigger: device.TryGetFeatureValue(CommonUsages.triggerButton, out value); break; case InputVRBool.Grip: device.TryGetFeatureValue(CommonUsages.gripButton, out value); break; case InputVRBool.Primary: device.TryGetFeatureValue(CommonUsages.primaryButton, out value); break; case InputVRBool.Secondary: device.TryGetFeatureValue(CommonUsages.secondaryButton, out value); break; case InputVRBool.PrimaryAxis: device.TryGetFeatureValue(CommonUsages.primary2DAxisClick, out value); break; case InputVRBool.Menu: if (node == XRNode.LeftHand) { device.TryGetFeatureValue(CommonUsages.menuButton, out value); } break; } } } return value; } public static float GetAxis1D(XRNode node, InputVRFloat inputVRFloat) { float value = 0; var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { switch (inputVRFloat) { case InputVRFloat.Trigger: device.TryGetFeatureValue(CommonUsages.trigger, out value); break; case InputVRFloat.Grip: device.TryGetFeatureValue(CommonUsages.grip, out value); break; } } } return value; } public static Vector2 GetAxis2D(XRNode node) { Vector2 value = Vector2.zero; var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { device.TryGetFeatureValue(CommonUsages.primary2DAxis, out value); } } return value; } public static void Recenter() { var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(XRNode.CenterEye, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { device.subsystem.TryRecenter(); } } } } 次に、以下のスクリプトを作成、サンプルシーンにある「XRRig」というオブジェクトにくっつけます。 VR_BasicController.cs using UnityEngine; [RequireComponent(typeof(CharacterController))] public class VR_BasicController : MonoBehaviour { private CharacterController cc; [SerializeField] private float speed = 2; [SerializeField] private int angle = 30; private bool RT, LT; private Vector2 stickL; private Vector2 stickR; private float gravity = 20;//9.81f; void Start() { cc = GetComponent<CharacterController>(); VR_Input.Recenter(); } void Update() { stickL = VR_Input.GetAxis2D(UnityEngine.XR.XRNode.LeftHand); stickR = VR_Input.GetAxis2D(UnityEngine.XR.XRNode.RightHand); Move(); Rotate(); if (VR_Input.GetPresseButton(UnityEngine.XR.XRNode.RightHand, VR_Input.InputVRBool.PrimaryAxis)) { VR_Input.Recenter(); } } void Move() { cc.enabled = true; Vector3 direction = new Vector3(stickL.x, 0, stickL.y); Vector3 velocity = direction * speed; velocity.y -= gravity; velocity = transform.TransformDirection(velocity); cc.Move(velocity * Time.deltaTime); } void Rotate() { if (stickR.x < -0.25f && !LT) { LT = true; transform.Rotate(0, -angle, 0); } if (0.25f < stickR.x && !RT) { RT = true; transform.Rotate(0, angle, 0); } if (stickR.x == 0) { LT = false; RT = false; } } } 使い方 左スティックで移動 右スティックで回転 右スティック押し込みでリセンタリング(デバッグ時のみ) 余談 Oculus+UnityでVRやりたい場合はアセットストアから「Oculus Integration」をインポートすれば大体のことはできる。 が、そんなに機能要らない。。もっと簡単にスクリプトちょっとくっつけるだけでワールドを歩き回りたい! と思っていたらUnityがVRテンプレートを提供してくれてたので使わせてもらいました。入力関連はどんどんアップデートしてくれているので、 今後さらにシンプルに使えるようになれたらいいね。Unityさんマジ最高です。 参考 Unityマニュアル:Unity の XR 入力
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityVR入力スターターキット

準備 UnityVRテンプレートから超簡単にワールド内を移動できるようになります。 検証エディタ:Unity2021.1 UnityHubで新しいプロジェクトを作る際にテンプレート「VR」を選択して作成。 プロジェクト設定のXRPluginManagementでOculusをチェック 以下のスクリプトを適当にアセットフォルダに作成します。 VR_Input.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; public class VR_Input : MonoBehaviour { public enum InputVRBool { Primary, Secondary, Trigger, Grip, Menu, PrimaryAxis }; public enum InputVRFloat { Trigger, Grip }; public static bool GetPresseButton(XRNode node, InputVRBool inputVRBool) { bool value = false; var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { switch (inputVRBool) { case InputVRBool.Trigger: device.TryGetFeatureValue(CommonUsages.triggerButton, out value); break; case InputVRBool.Grip: device.TryGetFeatureValue(CommonUsages.gripButton, out value); break; case InputVRBool.Primary: device.TryGetFeatureValue(CommonUsages.primaryButton, out value); break; case InputVRBool.Secondary: device.TryGetFeatureValue(CommonUsages.secondaryButton, out value); break; case InputVRBool.PrimaryAxis: device.TryGetFeatureValue(CommonUsages.primary2DAxisClick, out value); break; case InputVRBool.Menu: if (node == XRNode.LeftHand) { device.TryGetFeatureValue(CommonUsages.menuButton, out value); } break; } } } return value; } public static float GetAxis1D(XRNode node, InputVRFloat inputVRFloat) { float value = 0; var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { switch (inputVRFloat) { case InputVRFloat.Trigger: device.TryGetFeatureValue(CommonUsages.trigger, out value); break; case InputVRFloat.Grip: device.TryGetFeatureValue(CommonUsages.grip, out value); break; } } } return value; } public static Vector2 GetAxis2D(XRNode node) { Vector2 value = Vector2.zero; var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { device.TryGetFeatureValue(CommonUsages.primary2DAxis, out value); } } return value; } public static void Recenter() { var inputdevice = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(XRNode.CenterEye, inputdevice); if (0 < inputdevice.Count) { foreach (var device in inputdevice) { device.subsystem.TryRecenter(); } } } } 次に、以下のスクリプトを作成、サンプルシーンにある「XRRig」というオブジェクトにくっつけます。 VR_BasicController.cs using UnityEngine; [RequireComponent(typeof(CharacterController))] public class VR_BasicController : MonoBehaviour { private CharacterController cc; [SerializeField] private float speed = 2; [SerializeField] private int angle = 30; private bool RT, LT; private Vector2 stickL; private Vector2 stickR; private float gravity = 20;//9.81f; void Start() { cc = GetComponent<CharacterController>(); VR_Input.Recenter(); } void Update() { stickL = VR_Input.GetAxis2D(UnityEngine.XR.XRNode.LeftHand); stickR = VR_Input.GetAxis2D(UnityEngine.XR.XRNode.RightHand); Move(); Rotate(); if (VR_Input.GetPresseButton(UnityEngine.XR.XRNode.RightHand, VR_Input.InputVRBool.PrimaryAxis)) { VR_Input.Recenter(); } } void Move() { cc.enabled = true; Vector3 direction = new Vector3(stickL.x, 0, stickL.y); Vector3 velocity = direction * speed; velocity.y -= gravity; velocity = transform.TransformDirection(velocity); cc.Move(velocity * Time.deltaTime); } void Rotate() { if (stickR.x < -0.25f && !LT) { LT = true; transform.Rotate(0, -angle, 0); } if (0.25f < stickR.x && !RT) { RT = true; transform.Rotate(0, angle, 0); } if (stickR.x == 0) { LT = false; RT = false; } } } 使い方 左スティックで移動 右スティックで回転 右スティック押し込みでリセンタリング(デバッグ時のみ) 余談 Oculus+UnityでVRやりたい場合はアセットストアから「Oculus Integration」をインポートすれば大体のことはできる。 が、そんなに機能要らない。。もっと簡単にスクリプトちょっとくっつけるだけでワールドを歩き回りたい! と思っていたらUnityがVRテンプレートを提供してくれてたので使わせてもらいました。入力関連はどんどんアップデートしてくれているので、 今後さらにシンプルに使えるようになれたらいいね。Unityさんマジ最高です。 参考 Unityマニュアル:Unity の XR 入力
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「cannot assign method group to an implicitly-typed variable」のエラーが出た

C#の学習をしているときに、 var data10 = Enumerable.Repeat(1, 10).ToList; という書き方をすると、エラーが出てしまった。 cannot assign method group to an implicitly-typed variable というものだった。 解決策 ToListがメソッドなので、「ToList()」と書かないといけないので、これを直したた解決。 var data10 = Enumerable.Repeat(1, 10).ToList(); 今回発生したエラーは返す型が指定されているのに、nullを返すことが分かっていると発生するエラーみたいだ。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オブジェクト指向 - 用語まとめ -

1.はじめに C#の超入門本を読み、オブジェクト指向で出てくる用語がいくつかあったため、内容を整理しアウトプットするためにこの記事を書きました。 そのことから、オブジェクト指向の概要(クラス・インスタンス・カプセル化・継承・ポリモーフィズムなどの)説明は省きます。 2.用語の説明 2-1.メンバ変数とメンバメソッド メンバ変数・・・クラス内で宣言した変数のこと インスタンス生成時の変数名.メンバ変数 // 上記のように書くことでメンバ変数を使用することができる メンバメソッド・・・クラス内で定義したメソッドのこと インスタンス生成時の変数名.メンバメソッド // 上記のように書くことでメンバ変数を使用することができる 2-2.コンストラクタ コンストラクタは、インスタンス生成時にnewの後ろに記述するあれです。 クラス名 変数名 = new クラス名() // newの後ろに書かれている クラス名() がコンストラクタです。 コンストラクタは、インスタンス生成と同時にメンバ変数の初期値を代入してくれる仕組みです。 クラスには、以下のようにコンストラクタを書くことができます。 例えば、Personクラスがあったとして・・・ class Person { public int age; //年齢 public string langage; //話せる言語 //クラス内で宣言したメンバ変数 public Person() { this.age = 0; this.langage = "日本語"; } } //クラス内で宣言したメンバ変数に初期値を設定しているブロックがコンストラクタ コンストラクタは必ずしもクラスに書かなければならないわけではなく、書かなくてもOK。 その場合、コンパイラさんがインスタンス生成時に 「引数も初期値もないデフォルトコンストラクタを作ればいいのね」 と、自動で判断してくれるのです。(ありがたいですよね。) そして、何も書かれていないコンストラクタをデフォルトコンストラクタと呼びます。 もちろん引数ありバージョンで書くなら、インスタンス生成時に引数を渡してあげればOKです。 class Person { public int age; //年齢 public string langage; //話せる言語 public Person(int age, string langage) { this.age = age; this.langage = langage; //インスタンス生成時に渡された引数をそれぞれ代入 } } Person person = new Person(0, "日本語"); 2-3.アクセス修飾子 アクセス修飾子は以下3種類。 どれをクラスで使用するかによって、インスタンス生成後にどこからアクセスできるかが決まってきます。 また、これらを使い分けることで、メンバ変数に意図しない値が入れられないようにしたり、使ってほしい機能だけを使ってもらえるようにコントロールしています。 public protected private public そのまんまの意味ですが、すべてのクラスからアクセスできる。 protected 自分のクラス、もしくは派生したクラスだけアクセスできる。 英語の意味は、保護されるや守られるという意味があるので、 身内以外からアクセスできないように保護しているんだなと私は覚えるようにしました。 private こちらもそのまんまの意味ですが、自分のクラス内でしかアクセスできません。 ほかのクラスは一切アクセスできないプライベートな場所 書き方は、以下のようになります。 private int age; //アクセス修飾子 型名 メンバ変数名 public void Speak(){ 処理 } //アクセス修飾子 戻り値の型 メンバメソッド名(){} //voidは戻り値なしという意味 2-4.アクセサ アクセス修飾子をprivateにして、変数宣言されたメンバ変数にはほかのクラスから一切アクセスできないようになりました。 これはアクセスできないようにしたかったので問題ないのですが、正しい値を代入したい場合もアクセスできなくなってしまうようです。 そこで、メンバ変数へアクセスできるようにするためのメソッドを用意することになるのですが、これをアクセサと呼びます。 class Person { private int age; //privateになっているので、直接的にageの値を取得することができない public Person(int age) { this.age = age; } //コンストラクタを記述 public int GetAge() { return this.age; } //アクセサを記述 } Person person = new Person(20); person.GetAge(); //GetAgeメソッドを通じて、ageメンバ変数の20が取得できる 上記のようにメソッドを通じてメンバ変数にアクセスすることができます。 2-5.プロパティ アクセサを作る仕組みのことです。 privateで書かれているメンバ変数は直接的にアクセスできないため、メンバ変数へアクセスしようとするとどうしてもコードが冗長になってしまいます。 冗長になることを防ぐ機能としてプロパティがあるようです。 書き方は、以下のようになります。プロパティ名は先頭大文字で書きます。 class Person { private int age; //privateになっているので、直接的にageの値を取得することができない public Person(int age) { this.age = age; } //コンストラクタを記述 public int Age { set { this.age = value; if (this.age < 0) { this.age = 0; } } get { return this.age; } } //プロパティ名の先頭を大文字にして記述 } Person person = new Person(20); person.Age += 10; //PersonクラスのAgeプロパティに代入 Console.WriteLine(person.Age + "歳のときにはアメリカに住んでいたい") //「30歳のときにはアメリカに住んでいたい」 と出力される 2-6.オーバーロード 引数の数と型が違っていれば、同じ名前のメソッドを複数定義することができます。 このことをメソッドのオーバーロードと呼びます。 また、コンストラクタもオーバーロードすることができます。 以下に例となるコードを記述します。 class Person { private int age; public Person() //引数なしのコンストラクタ { this.age = 0; } public Person(int age) //引数ありのコンストラクタ { this.age = age; } } 引数なしでインスタンスが生成されたときは、引数なしのコンストラクタが実行されます。 引数ありでインスタンスが生成されたときは、引数ありのコンストラクタが実行されます。 2-7.メソッドオーバーライド 基本クラスから継承したメソッドを派生クラスで定義し直すことができるのが、メソッドオーバーライドです。 オーバーライドするときはvirtual修飾子を基本クラス側で使う必要があります。 また、override修飾子が派生クラス側では必要となります。 //基本クラス class Person { public virtual void Speak() { Console.WriteLine("英語が話せます"); } } //派生クラス class Japanese : Person { public override void Speak() { Console.WriteLine("日本語が話せます"); } } //基本クラスをインスタンス化 Person person = new Person(); person.Speak(); //「英語が話せます」と出力される //派生クラスをインスタンス化 Japanese japanese = new Japanese(); japanese.Speak(); //「日本語が話せます」と出力される 2-8.abstractキーワード 派生させることを前提とした中身がないメソッドを定義することもでき、実装する際はabstractキーワードを付ける。 //基本クラス abstract class Person { public abstract void Write(); } //派生クラス class Japanese : Person { public override void Write() //overrideを使って定義し直す { Console.WriteLine("漢字を書きます"); } } 3.参考資料 【C#の基礎】override修飾子でオーバーライドをする方法 書籍:確かな力が身につく C# 超入門 こちらの書籍結構わかりやすかったので、おすすめです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ASP.NET Core 5.0 MVC + SQLiteで作ったアプリをDocker上で動かしてみた!

はじめに Dockerの勉強として、以前ASP.NET Coreで自作したアプリをDocker上で動かしてみました。 動作環境 Windows10 Pro .NET Core SDK 5.0.205 Docker Version 19.03.12 Visual Studio 2019 C:\Work>ver Microsoft Windows [Version 10.0.19042.1110] C:\Work>dotnet --version 5.0.205 C:\Work>docker --version Docker version 19.03.12, build 48a66213fe Dockerfileの作成 続いてDockerfileを作成します。 Visual Studioを利用している方はプロジェクトを右クリック > 追加 > Dockerサポート > Linuxを選択するとテンプレートのDockerfileができますので利用すると良いかもしれません。 僕の場合はプロジェクトを分けているため、一部ファイルの内容を変更しています。 Dockerfile FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 #ポート5000を利用するので追加します EXPOSE 5000 FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /src #プロジェクトを分けており、一つ上の階層からDockerfileをビルドするのでパスをテンプレートから変更しています COPY ["TestMaker/TestMaker.csproj", "TestMaker/"] COPY ["DDD.Domain/DDD.Domain.csproj", "DDD.Domain/"] RUN dotnet restore "TestMaker/TestMaker.csproj" COPY . . WORKDIR "/src/TestMaker" RUN dotnet build "TestMaker.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "TestMaker.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "TestMaker.dll"] Dockerfileをビルドする docker build -t testmaker -f "TestMaker/Dockerfile" . ※Dockerfileの一つ上の階層からビルドしました。 以下のようにイメージが作られていることを確認します。 C:\Work\TestMakerProject\TestMaker>docker images REPOSITORY TAG IMAGE ID CREATED SIZE testmaker latest addaa2f7e45d 16 minutes ago 263MB <none> <none> a353b688a51d 16 minutes ago 1.3GB mcr.microsoft.com/dotnet/sdk 5.0 fa98367f9017 3 days ago 631MB mcr.microsoft.com/dotnet/aspnet 5.0 44ffd671d35d 3 days ago 205MB 対象のイメージからコンテナを作成します。 ポートは8080としていますが、こちらは任意の値でいいかと思います。 C:\Work\TestMakerProject\TestMaker>docker run --rm -p 8080:5000 testmaker testmaker_onDocker warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60] Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35] No XML encryptor configured. Key {7ab3713d-e0fb-40e3-9902-73b9ca437986} may be persisted to storage in unencrypted form. info: Microsoft.Hosting.Lifetime[0] Now listening on: http://[::]:5000 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Production info: Microsoft.Hosting.Lifetime[0] Content root path: /app 完成 http://localhost:8080 へアクセスすると無事に以下のようにアプリが正しく立ち上がることが確認できました! 終わりに 今回はDockerの勉強として以前作成したアプリをコンテナ化してみました! Linux上でも動くことを簡単に確認できるのでDockerは便利ですね。 アプリのソースコードは以下にあるのでもし参考になりそうでしたらどうぞ~ https://github.com/Oooooomin2/TestMaker おまけ もしDockerfileが無事にビルドできたけど正常にアプリが立ち上がらない場合は以下の処理が抜けている可能性があります。 https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/host/web-host?view=aspnetcore-5.0#server-urls 2021/07/26追記 こちらの「おまけ」についてですが、別途ご教示をいただいた「おまけ2」の方より良い方法ですのでそちらをご確認くださいませ~! 今回はProgram.csに以下のコードを追記しています。 program.cs public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://*:5000"); // <- 新たに追加 webBuilder.UseStartup<Startup>(); }); おまけ2(2021/07/26追記) 「おまけ」として書いた上記の内容について、お客様先(現在常駐している会社)の上司にもっと良い方法あるよ~!と2点教えてもらったので忘れないように追記します! その1:ASPNETCORE_URLSを環境変数として渡す 上記の「おまけ」ではソースコード上にサーバのURLを記載していましたが、DockerfileにASPNETCore_URLを環境変数として渡す内容を追記することでアクセスが可能になります。上記で記載していたDockerfileの下から2行目に「ENV ASPNETCORE_URLS http://*:5000」を追記します。 Dockerfile FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 EXPOSE 5000 FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /src COPY ["TestMaker/TestMaker.csproj", "TestMaker/"] COPY ["DDD.Domain/DDD.Domain.csproj", "DDD.Domain/"] RUN dotnet restore "TestMaker/TestMaker.csproj" COPY . . WORKDIR "/src/TestMaker" RUN dotnet build "TestMaker.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "TestMaker.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . # ASPNETCORE_URLSを環境変数として渡す ENV ASPNETCORE_URLS http://*:5000 ENTRYPOINT ["dotnet", "TestMaker.dll"] これでDockerfileをビルドして元の手順通りに進めてもブラウザからアクセスできるようになるかと思います。 その2:ASPNETCORE_ENVIRONMENTがProductionの場合はポート80でバインドされるので直接ポート80を指定する 環境変数ASPNETCORE_ENVIRONMENTはデフォルトでは"Production"となります。 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-5.0#environments その際はポート80でバインドされるため、docker runの際に-pで5000:80を指定する。 C:\Work\TestMakerProject\TestMaker>docker run --rm -p 5000:80 testmaker testmaker_onDocker ※この場合は上記「その1:ASPNETCORE_URLSを環境変数として渡す」で記載したASPNETCORE_URLSはDockerfileに記載していません。 どちらもソースコードをいじらずに実現できるのでこちらの方が便利です!! 色々とご教示いただけるので本当に感謝です!(^^)!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(C#) PDFを読み込んで、埋め込まれたTiff画像を書き出す(CCITTFaxDecode)

(C#) PDFを読み込んで、埋め込まれたTiff画像を書き出す(CCITTFaxDecode) 受信したFAXから生成されたPDFから、Tiff画像を書き出すサンプルソースです。 Tiff画像の情報は、幅高さ以外は、すべて決め打ち(固定値)にしているので、 対象のPDFの内容に応じて、変更してください。(解像度など) Tiffのタグについて タグ数15個(固定) ImageWidth[256] = ※画像より取得 ImageLength[257] = ※画像より取得 BitsPerSample[258] = 1(固定) Compression[259] = 4(固定) PhotometricInterpretation[262] = 0(固定) FillOrder[266] = 1(固定) StripOffsets[273] = 8(固定) Orientation[274] = 1(固定) SamplesPerPixel[277] = 1(固定) RowsPerStrip[278] = ※画像より取得 StripByteCounts[279] = ※画像より取得 XResolution[282] (192/1 = 192.000000)(固定)*適宜修正 …アドレス値 YResolution[283] (192/1 = 192.000000)(固定)*適宜修正 …アドレス値 PlanarConfiguration[284] = 1(固定) ResolutionUnit[296] = 2(固定) ※型 >3: SHORT型(2バイト短整数) >4: LONG型(4バイト長整数) >5: RATIONAL型(はじめの4バイトが分子で、残り4バイトが分母) pdf_CCITTFD_out1.cs //c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe pdf_CCITTFD_out1.cs using System; using System.IO; class pdf_CCITTFD_out1 { //*1 static byte[] rtIIBytes(int i){ byte[] rtBt = new byte[2]; string t0 = "0000" + Convert.ToString(i, 16); string t1 = t0.Substring(t0.Length - 4, 4); string t2_r = t1.Substring(t1.Length - 2, 2); string t2_l = t1.Substring(0, 2); rtBt[0] = Convert.ToByte(t2_r,16); rtBt[1] = Convert.ToByte(t2_l,16); return rtBt; } static byte[] rtTag(int i1,int i2,int i3,int i4,int i5,int i6){ byte[] rtBt = new byte[12]; Array.Copy(rtIIBytes(i1),0,rtBt,0,2); Array.Copy(rtIIBytes(i2),0,rtBt,2,2); Array.Copy(rtIIBytes(i3),0,rtBt,4,2); Array.Copy(rtIIBytes(i4),0,rtBt,6,2); Array.Copy(rtIIBytes(i5),0,rtBt,8,2); Array.Copy(rtIIBytes(i6),0,rtBt,10,2); return rtBt; } static void Main(string[] args) { //*2 string p_fn = @"" + args[0]; byte[] data = File.ReadAllBytes(p_fn); int ImgCnt = 1; int ARCN = 9; //array_count string[] st = new string[ARCN]; st[0] = "/CCITTFaxDecode"; st[1] = " obj"; st[2] = "endobj"; st[3] = ">stream"; st[4] = "endstream"; st[5] = "/Columns "; st[6] = "/Rows "; st[7] = "/Width "; st[8] = "/Height "; byte[][] d = new byte[ARCN][]; for(int i=0; i<ARCN; ++i) d[i] = System.Text.Encoding.ASCII.GetBytes(st[i]); byte[][] dm = new byte[ARCN][]; for(int i=0; i<ARCN; ++i) dm[i] = new byte[d[i].Length]; int stream_stt = 0; int stream_size = 0; int intColumns = 0; int intRows = 0; int intWidth = 0; int intHeight = 0; bool outFlg = false; byte[] TiffHeader = {0x49,0x49,0x2A,0x00}; for(int i=0;i<data.Length-st[0].Length;i++){ for(int j=0; j<ARCN; ++j) Array.Copy(data,i,dm[j],0,d[j].Length); bool[] aEq = new bool[ARCN]; for(int j=0; j<ARCN; ++j){ aEq[j] = System.Linq.Enumerable.SequenceEqual(d[j], dm[j]); if(aEq[j]){ //" obj" if(j==1){ outFlg = false; //リセット } //"/CCITTFaxDecode" if(j==0){ outFlg = true; } //">stream" if(j==3){ stream_stt = (int)(i+(int)d[j].Length+2); } //"endstream" if(j==4){ stream_size = (int)((int)i-3) - stream_stt +1; if(outFlg){ /* Console.WriteLine("intColumns= " + intColumns); Console.WriteLine("intRows= " + intRows); Console.WriteLine("intWidth= " + intWidth); Console.WriteLine("intHeight= " + intHeight); */ byte[] data_out = new byte[stream_size]; Array.Copy(data,stream_stt,data_out,0,stream_size); var fileName = @".\CCITTFD_stream_out" +ImgCnt+ ".tif"; using (var writer = new BinaryWriter(new FileStream(fileName, FileMode.Create))) { writer.Write(TiffHeader); writer.Write(rtIIBytes(stream_size+8)); writer.Write((byte)0x00); writer.Write((byte)0x00); writer.Write(data_out); writer.Write(rtIIBytes(15));//タグ数 writer.Write(rtTag(256,3,1,0,intWidth,0));//ImageWidth[256] writer.Write(rtTag(257,3,1,0,intHeight,0));//ImageLength[257] writer.Write(rtTag(258,3,1,0,1,0));//BitsPerSample[258] writer.Write(rtTag(259,3,1,0,4,0));//Compression[259] writer.Write(rtTag(262,3,1,0,0,0));//PhotometricInterpretation[262] writer.Write(rtTag(266,3,1,0,1,0));//FillOrder[266] writer.Write(rtTag(273,4,1,0,8,0));//StripOffsets[273] writer.Write(rtTag(274,3,1,0,1,0));//Orientation[274] writer.Write(rtTag(277,3,1,0,1,0));//SamplesPerPixel[277] writer.Write(rtTag(278,3,1,0,intHeight,0));//RowsPerStrip[278] writer.Write(rtTag(279,4,1,0,stream_size,0));//StripByteCounts[279] writer.Write(rtTag(282,5,1,0,stream_size+8+2+180+4,0));//XResolution[282] writer.Write(rtTag(282,5,1,0,stream_size+8+2+180+4+8,0));//YResolution[283] writer.Write(rtTag(284,3,1,0,1,0));//PlanarConfiguration[284] writer.Write(rtTag(296,3,1,0,2,0));//ResolutionUnit[296] writer.Write(rtIIBytes(0)); writer.Write(rtIIBytes(0)); //XResolution writer.Write(rtIIBytes(192)); writer.Write(rtIIBytes(0)); writer.Write(rtIIBytes(1)); writer.Write(rtIIBytes(0)); //YResolution writer.Write(rtIIBytes(192)); writer.Write(rtIIBytes(0)); writer.Write(rtIIBytes(1)); writer.Write(rtIIBytes(0)); //File.WriteAllBytes("CCITTFD_stream_out" +ImgCnt+ ".bin", TiffHeader, False); //File.WriteAllBytes("CCITTFD_stream_out" +ImgCnt+ ".bin", data_out, true); } ImgCnt++; } } string tx = System.Text.Encoding.ASCII.GetString(dm[j]); //Console.Write(i + "_" + tx + ":"); //Columns Rows Width Height なら、数値を拾いにいく if(j>=5){ //int r = BitConverter.ToInt32(data[i+1], 0); int c=0; for(int c1=0;c1<20;c1++){ int c2 =(int)data[c1+i+d[j].Length]; //数字なら文字コードが48~57 *改行考慮せず if(c2>=48&&c2<=57){ }else{c=c1;break;} } byte[] b = new byte[c]; Array.Copy(data,i+d[j].Length,b,0,c); string tx1 = System.Text.Encoding.ASCII.GetString(b); //Console.Write(tx1); switch (j) { case 5: intColumns = Int32.Parse(tx1); break; case 6: intRows = Int32.Parse(tx1); break; case 7: intWidth = Int32.Parse(tx1); break; case 8: intHeight = Int32.Parse(tx1); break; default: break; } } //Console.WriteLine("_"); } } } } //*2 } //*1 過去投稿 (C#) PDFを読み込んで、埋め込まれた画像をJPGファイルとして書き出す(DCTDecodeのStream内をママ書き出しているだけなのでかなり雑) https://qiita.com/santarou6/items/5f011e266929558ede34 (C#) PDFを読み込んで、Stream内をすべて別ファイルに書き出す、サンプルソース https://qiita.com/santarou6/items/5272458b1e9ff2058327 C# JpgからPDFへ変換(1Jpgファイルを1ページとしたPDFファイルの作成) https://qiita.com/santarou6/items/ff24500c13d05b12a940 外部サイト TIFFのフォーマット TIFFのフォーマット(その1) https://jprogramer.com/libtiffcate/3188 TIFFのフォーマット(その2) https://jprogramer.com/libtiffcate/3211 iTextSharp https://itextpdf.com/en/products/itext-7 https://github.com/itext/itext7-dotnet iText 7 Community for .NET (former iTextSharp) consists of several dlls. C#でPDFファイルから画像を抜き出す モノクロTIFF編 (iTextSharp) https://araramistudio.jimdo.com/2021/03/19/c-%E3%81%A7pdf%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89%E7%94%BB%E5%83%8F%E3%82%92%E6%8A%9C%E3%81%8D%E5%87%BA%E3%81%99-%E3%83%A2%E3%83%8E%E3%82%AF%E3%83%ADtiff%E7%B7%A8-itextsharp/ Tiff Analyzer Tiff解析ソフト「Tiff Analyzer」 https://www.vector.co.jp/soft/dl/winnt/art/se251005.html TiffファイルのTAGを検出して表示とCSVファイルに保存
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(C#) PDFを読み込んで、埋め込まれた画像をJPGファイルとして書き出す(DCTDecodeのStream内をママ書き出しているだけなのでかなり雑)

(C#) PDFを読み込んで、埋め込まれた画像をJPGファイルとして書き出す (DCTDecodeのStream内をママ書き出しているだけなのでかなり雑) ・前回 の応用です ・C#単体で、PDFをバイト列に読み込んで、処理しています ・objの中に、DCTDecodeと記載ある時のみ、streamの中身を.jpgという名で、書き出しているだけです。 ・画像形式などを一切判定していないので、書き出されたものが画像として読めない場合も往々にしてありますが、割り切ればそこそこ有用です。 pdf_jpg_out1.cs //c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe pdf_jpg_out1.cs using System; using System.IO; class pdf_jpg_out1 { //*1 static void Main(string[] args) { //*2 string p_fn = @"" + args[0]; byte[] data = File.ReadAllBytes(p_fn); int ImgCnt = 1; int ARCN = 5; //array_count string[] st = new string[ARCN]; st[0] = "/DCTDecode"; st[1] = " obj"; st[2] = "endobj"; st[3] = ">stream"; st[4] = "endstream"; byte[][] d = new byte[ARCN][]; for(int i=0; i<ARCN; ++i) d[i] = System.Text.Encoding.ASCII.GetBytes(st[i]); byte[][] dm = new byte[ARCN][]; for(int i=0; i<ARCN; ++i) dm[i] = new byte[d[i].Length]; int stream_stt = 0; int stream_size = 0; bool outFlg = false; for(int i=0;i<data.Length-st[0].Length;i++){ for(int j=0; j<ARCN; ++j) Array.Copy(data,i,dm[j],0,d[j].Length); bool[] aEq = new bool[ARCN]; for(int j=0; j<ARCN; ++j){ aEq[j] = System.Linq.Enumerable.SequenceEqual(d[j], dm[j]); if(aEq[j]){ //" obj" if(j==1){ outFlg = false; //リセット } //"/DCTDecode" if(j==0){ outFlg = true; } //">stream" if(j==3){ stream_stt = (int)(i+(int)d[j].Length+2); } //"endstream" if(j==4){ stream_size = (int)((int)i-3) - stream_stt +1; if(outFlg){ byte[] data_out = new byte[stream_size]; Array.Copy(data,stream_stt,data_out,0,stream_size); File.WriteAllBytes("_Jpg_out" +ImgCnt+ ".jpg", data_out); Console.WriteLine("_Jpg_out" +ImgCnt+ ".jpg"); ImgCnt++; } } string tx = System.Text.Encoding.ASCII.GetString(dm[j]); //Console.WriteLine(i + "_" + tx); } } } } //*2 } //*1 実行例 対象例 ためしにこのPDFでやってみると (総務省のサイトより) https://www.soumu.go.jp/main_content/000542668.pdf 1)PDFでの表示 2)抜き出したJPG 参考 (C#) PDFを読み込んで、Stream内をすべて別ファイルに書き出す、サンプルソース https://qiita.com/santarou6/items/5272458b1e9ff2058327 C# JpgからPDFへ変換(1Jpgファイルを1ページとしたPDFファイルの作成) https://qiita.com/santarou6/items/ff24500c13d05b12a940 iTextSharp きっちりやりたい方は、以下DLLなどを使ってください https://itextpdf.com/en/products/itext-7 https://github.com/itext/itext7-dotnet iText 7 Community for .NET (former iTextSharp) consists of several dlls. C#でPDFファイルから画像を抜き出す 導入編 (iTextSharp) https://araramistudio.jimdo.com/2021/03/19/c-%E3%81%A7pdf%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89%E7%94%BB%E5%83%8F%E3%82%92%E6%8A%9C%E3%81%8D%E5%87%BA%E3%81%99-itextsharp/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む