1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Visual Studio 2019のVisual Basic・Windows10環境にて、指定した画像中に任意のExif情報を埋め込む。コードのサンプルです。

Last updated at Posted at 2021-03-29

概要

表題の通り
Visual Studio 2019のVisual Basicにて、
指定した画像中に任意のExif情報を埋め込む。コードのサンプルでございます。

バイナリを直接強引に叩いて
特段、NuGetなどで他のプラグインや
別途外部dllを必要としないようにしています。

今回は、必要最低限な??
・カメラ名 
・撮影日時
・写真タイトル
・気温・気圧
・GPS情報
に絞って埋め込んでいます。
このため、必須のExifタグの欠落や、省略している所、私の勘違いが多分に含まれていますので、予めご了承ください。

また、以下のコートはながったるいあり合わせのものですので、ご注意ください。
※手抜きの為に、JFIFの内容も共存しています。
※特にGPS周りは、だいぶ力業でやっています。
※コード内のIDなどは決め打ちしていますので、このコードに関して、もし引用される場合は、TageSPは何ら動作不良や損害のの責任を持ちませんが、それでも良いなら、ご自身が必要なExif情報の内容に書き換えた上で使用していただけると幸いでございます。

参考ページ

この記事のコードの作成に当たり
けんしのページ - Exifファイルフォーマット -
Exif explanation
JPEGのExif情報をとっかかりにバイナリデータと戯れる | 株式会社ビヨンド
EXIF Tags
Exif固有のIFD - otouNow 日々雑々

以上のサイト様の情報を参考にさせていただきました。
この場にて御礼申し上げます。

本題

標題にある機能のための
Visual Basic 2019での
Windows10開発環境でのコードは、以下の通りでございます。
Button1_Clickのイベント内部が主幹の部分でございます。

Form1.vb
Imports System.Threading.Tasks

Public Class Form1
    'デスクトップのパスを格納
    ReadOnly desktop_path As String = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)

    '出力jpegバイナリを入れるところ
    Dim ary_jpeg_file As List(Of Byte)

    '各ヘッダーなど固定値を入れるところ
    ReadOnly JPEG_SOI As Byte() = New Byte(19) {&HFF, &HD8, &HFF, &HE0, &H0, &H10, &H4A, &H46, &H49, &H46, &H0, &H1, &H1, &H1, &H0, &H60, &H0, &H60, &H0, &H0}
    ReadOnly APP1_Marker As Byte() = New Byte(1) {&HFF, &HE1}
    ReadOnly Exif_Header As Byte() =
        New Byte(5) {&H45, &H78, &H69, &H66, &H0, &H0}
    ReadOnly Little_Endian As Byte() = New Byte(1) {&H49, &H49}
    ReadOnly TIFF_Header As Byte() = New Byte(5) {&H2A, &H0, &H8, &H0, &H0, &H0}
    ReadOnly No_next_IFD As Byte() = New Byte(3) {0, 0, 0, 0}


    '動的に作るコントロール
    Dim txtBox(10) As TextBox
    Dim lblBox(6) As Label
    Dim cmbBox(1) As ComboBox
    Dim Button1 As Button

    Private Sub Button1_Click(sender As Object, e As EventArgs)

        Dim Out_FileName As String '最終的に出力する画像フルパス
        Dim temp_FileName As String '一旦出力するExifがない画像のフルパス(あとで消す)

        'ファイルを開く
        Using ofd As New OpenFileDialog()
            ofd.Filter = "画像ファイル(*.jpg;*.jpeg;*.png;*.gif;*.bmp)|*.jpg;*.jpeg;*.png;*.gif;*.bmp"
            ofd.Title = "Exifを入れ込む画像ファイルを選択してください"

            'ダイアログを表示する
            If ofd.ShowDialog() = DialogResult.OK Then
                '選択したファイルパスの取得
                Out_FileName = ofd.FileName

                '出力ファイルパスの取得
                Out_FileName = IO.Path.Combine(desktop_path, IO.Path.GetFileNameWithoutExtension(Out_FileName) & "_EXIF_TEST.jpg")
                '仮出力した画像パスの取得
                temp_FileName = IO.Path.Combine(desktop_path, IO.Path.GetFileNameWithoutExtension(Out_FileName) & "_EXIF_TEST.tmp")

                '一旦EXIFが無い画像を出力する
                Using task2 As Task = Task.Run(
                    Sub()
                        '今回は一旦ストリームを介する方法にて画像ファイルを取り扱っている
                        Using fs As New System.IO.FileStream(
                                ofd.FileName,
                                System.IO.FileMode.Open,
                                System.IO.FileAccess.Read)
                            Dim img As System.Drawing.Image = System.Drawing.Image.FromStream(fs)
                            fs.Close()

                            Using bmp = New Bitmap(img)
                                img.Dispose()
                                '元画像をロードする

                                '96(&H60)DPIで固定する[JPEG_SOIの所にそう書いているから]
                                bmp.SetResolution(96, 96)

                                'jpeg形式で一旦保存する
                                bmp.Save(temp_FileName, Imaging.ImageFormat.Jpeg)
                            End Using
                        End Using
                        Application.DoEvents()
                        Threading.Thread.Sleep(50)
                        Application.DoEvents()

                    End Sub
                    )

                    '処理が終わるまで待機させる
                    '⇒たまに画像保存しないうちに先に進んでしまう事があるため
                    task2.Wait()
                End Using

            Else
                'キャンセル時
                Exit Sub
            End If
        End Using

        '出力バイナリの初期化
        ary_jpeg_file = New List(Of Byte)
        ary_jpeg_file.Clear()

        'APP1_Dataの開始位置を格納
        Dim APP1_Data_Start_Pos As Integer = 0

        'APP1_Dataのサイズを格納
        Dim APP1_Data_Size As Int16 = 0

        'TIFF Headerの開始位置を格納
        Dim TIFF_Data_Start_Pos As Int16 = 0


        '★★★↓ここから★★メモリ上で疑似書き込みを行う★★★(オフセット位置取得などのため)
        ary_jpeg_file.AddRange(JPEG_SOI)
        ary_jpeg_file.AddRange(APP1_Marker)

        'APP1の開始位置を記憶
        APP1_Data_Start_Pos = ary_jpeg_file.Count

        'APP1の領域を0バイトとして仮登録
        ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt16(0)))

        '各ヘッダの書き込み
        ary_jpeg_file.AddRange(Exif_Header)

        'TIFFの開始位置を記憶
        TIFF_Data_Start_Pos = ary_jpeg_file.Count
        ary_jpeg_file.AddRange(Little_Endian)
        ary_jpeg_file.AddRange(TIFF_Header)

        'IDの個数を仮登録
        ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt16(0)))

        '各コンテンツの情報を格納
        Dim contents_list_id As New List(Of UInt16)
        Dim contents_list_type As New List(Of UInt16)
        Dim contents_list_binary As New List(Of Byte())
        Dim contents_list_offset As New List(Of UInt32)

        'カメラの名称ID
        contents_list_id.Add(Convert.ToUInt16(&H110))
        'カメラの名称TYPE(ASCII)
        contents_list_type.Add(Convert.ToUInt16(&H2))
        'カメラの名前のバイナリ
        contents_list_binary.Add(System.Text.Encoding.ASCII.GetBytes(txtBox(0).Text))


        '作成日時のID
        contents_list_id.Add(Convert.ToUInt16(&H9003))
        '作成日時の名称TYPE(ASCII)
        contents_list_type.Add(Convert.ToUInt16(&H2))
        '作成日時の名前のバイナリ
        contents_list_binary.Add(System.Text.Encoding.ASCII.GetBytes(txtBox(1).Text.Replace("/", ":")))

        '写真のタイトルID
        contents_list_id.Add(Convert.ToUInt16(&H10E))
        '写真のタイトルTYPE(ASCII)
        contents_list_type.Add(Convert.ToUInt16(&H2))
        '写真のタイトルのバイナリ
        contents_list_binary.Add(System.Text.Encoding.ASCII.GetBytes(txtBox(2).Text))

        '気温の値のバイナリ取得
        Dim temp_dec As Decimal = 10
        Decimal.TryParse(txtBox(3).Text, temp_dec)
        Dim bs3 As New List(Of Byte)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToInt32(temp_dec * 10)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToInt32(10)))

        '気温ID
        contents_list_id.Add(Convert.ToUInt16(&H9400))
        '気温TYPE(ASCII)
        contents_list_type.Add(Convert.ToUInt16(&HA))
        '気温のバイナリ
        contents_list_binary.Add(bs3.ToArray())
        bs3.Clear()


        '気圧の値のバイナリ取得
        temp_dec = 1013.25
        Decimal.TryParse(txtBox(4).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec * 100)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(100)))

        '気圧ID
        contents_list_id.Add(Convert.ToUInt16(&H9402))
        '気圧TYPE(ASCII)
        contents_list_type.Add(Convert.ToUInt16(&H5))
        '気圧のバイナリ
        contents_list_binary.Add(bs3.ToArray())
        bs3.Clear()

        '▽▽▽▽GPS関係▽▽▽▽▽▽▽▽▽▽▽
        'https://otounow.jimdofree.com/exif%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88/exif%E5%9B%BA%E6%9C%89%E3%81%AEifd/
        'GPSへのポインタID
        contents_list_id.Add(Convert.ToUInt16(&H8825))
        'GPSへのポインタTYPE
        contents_list_type.Add(Convert.ToUInt16(&H4))

        'GPSのバイナリ作成
        Dim gps_tags_count As Int16 = 0
        Dim gps_tags_offsetN As Int32 = 0
        Dim gps_offsetN_index As Int32 = 0
        Dim gps_tags_offsetE As Int32 = 0
        Dim gps_offsetE_index As Int32 = 0

        bs3.Clear()
        'GPS IFD
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H4)))

        '北緯or南緯
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H1)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H2))) 'ASCII
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H2))) 'データ長さ
        bs3.AddRange(System.Text.Encoding.ASCII.GetBytes(cmbBox(0).SelectedItem)) 'NorS
        bs3.Add(0)
        bs3.Add(0)
        bs3.Add(0)
        gps_tags_count += 1

        '緯度
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H2)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H5)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H3))) 'データ長さ
        gps_offsetN_index = bs3.Count '格納開始インデックスを記録しておく
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H0))) 'データへのオフセット
        gps_tags_count += 1

        '東経or西経
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H3)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H2))) 'ASCII
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H2))) 'データ長さ
        bs3.AddRange(System.Text.Encoding.ASCII.GetBytes(cmbBox(1).SelectedItem)) 'EorW
        bs3.Add(0)
        bs3.Add(0)
        bs3.Add(0)
        gps_tags_count += 1

        '経度
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H4)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt16(&H5)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H3))) 'データ長さ
        gps_offsetE_index = bs3.Count '格納開始インデックスを記録しておく
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H0))) 'データへのオフセット
        gps_tags_count += 1


        '緯度
        gps_tags_offsetN = bs3.Count 'ここまでのバイト数を記録しておく
        temp_dec = 34
        Decimal.TryParse(txtBox(5).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H1)))
        temp_dec = 36
        Decimal.TryParse(txtBox(6).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H1)))
        temp_dec = 21.5496
        Decimal.TryParse(txtBox(7).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec * 10000)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(10000)))

        '経度
        gps_tags_offsetE = bs3.Count 'ここまでのバイト数を記録しておく
        temp_dec = 135
        Decimal.TryParse(txtBox(8).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H1)))
        temp_dec = 42
        Decimal.TryParse(txtBox(9).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(&H1)))
        temp_dec = 2.4186
        Decimal.TryParse(txtBox(10).Text, temp_dec)
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(temp_dec * 10000)))
        bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(10000)))

        'GPSのバイナリ
        contents_list_binary.Add(bs3.ToArray())

        bs3.Clear()
        '△△△△GPS関係△△△△△△△△△△△△△△△△


        '各IDとバイナリなどの仮入力
        For i As Integer = 0 To contents_list_id.Count - 1
            'ID
            ary_jpeg_file.AddRange(BitConverter.GetBytes(contents_list_id(i)))
            'TYPE
            ary_jpeg_file.AddRange(BitConverter.GetBytes(contents_list_type(i)))
            'バイナリ長
            ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt32(contents_list_binary(i).Length)))
            'TIFF_Data_Start_Posからのオフセット位置
            ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt32(0)))
        Next


        '以下ASCII領域
        ary_jpeg_file.AddRange(No_next_IFD)

        '各オフセット位置の取得
        For i As Integer = 0 To contents_list_id.Count - 1
            Dim offset As UInt32 = ary_jpeg_file.Count - TIFF_Data_Start_Pos

            If contents_list_id(i) = &H8825 Then
                'GPSの場合
                'さらに緯度・経度のデータへのオフセットを格納
                gps_tags_offsetN += offset
                gps_tags_offsetE += offset

                'オフセット位置の訂正
                bs3.Clear()
                bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(gps_tags_offsetN)))
                contents_list_binary(i)(gps_offsetN_index) = bs3(0)
                contents_list_binary(i)(gps_offsetN_index + 1) = bs3(1)
                contents_list_binary(i)(gps_offsetN_index + 2) = bs3(2)
                contents_list_binary(i)(gps_offsetN_index + 3) = bs3(3)

                bs3.Clear()
                bs3.AddRange(BitConverter.GetBytes(Convert.ToUInt32(gps_tags_offsetE)))
                contents_list_binary(i)(gps_offsetE_index) = bs3(0)
                contents_list_binary(i)(gps_offsetE_index + 1) = bs3(1)
                contents_list_binary(i)(gps_offsetE_index + 2) = bs3(2)
                contents_list_binary(i)(gps_offsetE_index + 3) = bs3(3)

                bs3.Clear()
            End If

            contents_list_offset.Add(offset)
            ary_jpeg_file.AddRange(contents_list_binary(i))
            ary_jpeg_file.Add(0) '1バイト開ける
        Next

        'APP1のサイズを取得
        APP1_Data_Size = ary_jpeg_file.Count - APP1_Data_Start_Pos

        '初期化
        ary_jpeg_file.Clear()


        '★★★↓ここから★★実際にファイルを作成して書き込んで行く
        Using fs = New System.IO.FileStream(Out_FileName,
            System.IO.FileMode.Create,
            System.IO.FileAccess.Write)

            ary_jpeg_file.AddRange(JPEG_SOI)
            ary_jpeg_file.AddRange(APP1_Marker)

            'APP1の領域サイズ
            ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt16(APP1_Data_Size)).Reverse)

            ary_jpeg_file.AddRange(Exif_Header)
            ary_jpeg_file.AddRange(Little_Endian)
            ary_jpeg_file.AddRange(TIFF_Header)

            'IDの個数を登録
            ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt16(contents_list_id.Count)))

            '各IDとバイナリなどの仮入力
            For i As Integer = 0 To contents_list_id.Count - 1
                'ID
                ary_jpeg_file.AddRange(BitConverter.GetBytes(contents_list_id(i)))
                'TYPE
                ary_jpeg_file.AddRange(BitConverter.GetBytes(contents_list_type(i)))
                'バイナリ長
                Select Case contents_list_type(i)
                    Case 2 'ASCIIの場合は文字列長
                        ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt32(contents_list_binary(i).Length)))
                    Case Else '数値の場合は1で固定
                        ary_jpeg_file.AddRange(BitConverter.GetBytes(Convert.ToUInt32(1)))
                End Select
                'TIFF_Data_Start_Posからのオフセット位置
                ary_jpeg_file.AddRange(BitConverter.GetBytes(contents_list_offset(i)))
            Next


            '以下ASCII領域
            ary_jpeg_file.AddRange(No_next_IFD)

            '各バイナリの入力
            For i As Integer = 0 To contents_list_id.Count - 1
                ary_jpeg_file.AddRange(contents_list_binary(i))
                ary_jpeg_file.Add(0) '1バイト開ける
            Next

            '一旦、バイト型配列の内容をすべて上書き
            fs.Write(ary_jpeg_file.ToArray(), 0, ary_jpeg_file.Count)
            fs.Flush()
            ary_jpeg_file.Clear()

            Using fs2 As New System.IO.FileStream(
                               temp_FileName,
                               System.IO.FileMode.Open,
                               System.IO.FileAccess.Read)
                Dim pos As Integer = 2
                Dim bs(1) As Byte
                Dim BUFSIZE As Integer = 1023
                Do
                    fs2.Seek(pos, IO.SeekOrigin.Begin)
                    fs2.Read(bs, 0, bs.Count)
                    If bs(0) = &HFF AndAlso bs(1) = &HDB AndAlso pos > 2 Then
                        '本体データの書き込み開始位置の捜索
                        Exit Do
                    End If
                    pos += 1
                Loop

                ReDim bs(BUFSIZE)
                '画像の本体ファイルの残りをすべて読み込む→書き込む 
                While True
                    'ファイルの一部を読み込む 
                    fs2.Seek(pos, IO.SeekOrigin.Begin)
                    Dim readSize As Integer = fs2.Read(bs, 0, BUFSIZE)

                    fs.Write(bs, 0, readSize)
                    fs.Flush()
                    'ファイルをすべて読み込んだときは終了する 
                    If readSize < BUFSIZE Then
                        Exit While
                    End If

                    pos += BUFSIZE
                End While
            End Using
        End Using

        '初期化
        contents_list_id.Clear()
        contents_list_type.Clear()
        contents_list_binary.Clear()
        contents_list_offset.Clear()

        '一時ファイルを消す
        Try
            IO.File.Delete(temp_FileName)

        Catch ex As Exception

        End Try
        '終了のお知らせ
        MessageBox.Show("END")

        '出来た画像を開きます
        Process.Start(Out_FileName)
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.SuspendLayout()

        '動的にコントロール(ボタン)を配置する
        For i As Integer = 0 To txtBox.Count - 1
            txtBox(i) = New TextBox

            Me.Controls.Add(txtBox(i))

            txtBox(i).Left = 110

            txtBox(i).Top = i * 30 + 10

            txtBox(i).Width = 120
        Next

        For i As Integer = 0 To lblBox.Count - 1
            lblBox(i) = New Label

            Me.Controls.Add(lblBox(i))

            lblBox(i).Left = 30

            lblBox(i).Top = i * 30 + 10

            lblBox(i).AutoSize = True
        Next

        For i As Integer = 0 To cmbBox.Count - 1
            cmbBox(i) = New ComboBox

            Me.Controls.Add(cmbBox(i))

            cmbBox(i).Width = 120
        Next

        'クリックした際にButton1_Click()イベントが起きるボタンを生成
        Button1 = New Button
        Me.Controls.Add(Button1)
        AddHandler Button1.Click, AddressOf Button1_Click   '動的にイベントを関連付ける

        '各コントロールに初期値の入力
        txtBox(0).Text = "camera_name"
        lblBox(0).Text = "カメラ名"

        txtBox(1).Text = DateTime.Now.AddDays(-3).ToString()
        lblBox(1).Text = "撮影日時"

        txtBox(2).Text = "syashinn_title"
        lblBox(2).Text = "写真タイトル"

        txtBox(3).Text = "21.2"
        lblBox(3).Text = "気温"

        txtBox(4).Text = "1013.25"
        lblBox(4).Text = "気圧"

        lblBox(5).Text = "緯度"
        txtBox(5).Text = "1013.25"
        cmbBox(0).Items.Clear()
        cmbBox(0).Items.Add("N")
        cmbBox(0).Items.Add("S")
        cmbBox(0).SelectedIndex = 0
        cmbBox(0).Location = New Point(lblBox(5).Left + 80, lblBox(5).Top)
        For i As Integer = 5 To 7
            txtBox(i).Location = New Point(cmbBox(0).Left + (130 * (i - 4)), cmbBox(0).Top)
        Next
        txtBox(5).Text = "34"
        txtBox(6).Text = "36"
        txtBox(7).Text = "21.5496"

        lblBox(6).Text = "経度"
        cmbBox(1).Items.Clear()
        cmbBox(1).Items.Add("E")
        cmbBox(1).Items.Add("W")
        cmbBox(1).SelectedIndex = 0
        cmbBox(1).Location = New Point(lblBox(6).Left + 80, lblBox(6).Top)
        For i As Integer = 8 To 10
            txtBox(i).Location = New Point(cmbBox(1).Left + (130 * (i - 7)), cmbBox(1).Top)
        Next
        txtBox(8).Text = "135"
        txtBox(9).Text = "42"
        txtBox(10).Text = "2.4186"

        Button1.Location = New Point(cmbBox(1).Left, cmbBox(1).Top + 30)
        Button1.Width = 360
        Button1.Text = "画像を選択して、上記のExif情報を付与する"
        Me.ResumeLayout()
    End Sub


End Class

なお、埋め込んだExif情報がある程度正常なのかを確認するために
online metadata and exif viewer
のサイト様など。
オンラインでExifを確認するサイトにて、確認を行っております。

↓上記のコードを初期値のままでExifを書き込んだ写真

↓その写真のExifをonline metadata and exif viewer様にて確認した画像

サンプル

上記のコードを
新規作成した新しいVisualBasic2019のForm1のコードに丸っと書き写して
実行すると、以下のような画面が表示されますので。

画面に必要事項を入力してから、「画像を選択して~」のボタンをクリックください。
コードは最低限の内容となっていまので、異常な値を入力した場合は、
エラーが発生したり、そのまま処理されても不都合が生じますので、気を付けてください。

私としては、写真を加工して出力する際に
元々扱った写真に入っていたExifの情報を、加工後に出力した画像にも、引き継げられるように出来たらいいなと考えて作成いたしました。

以上
ありがとうございました

1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?