スキップしてメイン コンテンツに移動

C#: How to Read Image MetaData from System.Drawing.Imaging.PropertyItem

I have written simple debug code for printing out PropertyItems in System.Drawing.Image object.
The key part of the code:

  • mapping between Id property of PropertyItem and description of associated to the property item.
  • decode PropertyItem value (byte array) to human readable format string

The code itself will be shown at the bottom of this post.
Below is a sample image which will be passed to the program and the corresponding output generated by the program.
Property Item 1
   Id: 0x10e
   Type: 2
   Length: 17 bytes
   Type String: ASCII
   Descriotion: PropertyTagImageDescription
   Value      : MetaData Example
Property Item 2
   Id: 0x131
   Type: 2
   Length: 7 bytes
   Type String: ASCII
   Descriotion: PropertyTagSoftwareUsed
   Value      : Picasa
Property Item 3
   Id: 0x9000
   Type: 7
   Length: 4 bytes
   Type String: Undefined
   Descriotion: PropertyTagExifVer
   Value      : 
Property Item 4
   Id: 0xa002
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagExifPixXDim
   Value      : 1440
Property Item 5
   Id: 0xa003
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagExifPixYDim
   Value      : 1440
Property Item 6
   Id: 0xa420
   Type: 2
   Length: 33 bytes
   Type String: ASCII
   Descriotion: Unknown
   Value      : 199e785efd74401dff564baa559c2f25
Property Item 7
   Id: 0x9c9b
   Type: 1
   Length: 34 bytes
   Type String: Array of bytes
   Descriotion: Unknown
   Value      : 77,0,101,0,116,0,97,0,68,0,97,0,116,0,97,0,32,0,69,0,120,0,97,0,109,0,112,0,108,0,101,0,0,0
Property Item 8
   Id: 0x9c9c
   Type: 1
   Length: 28 bytes
   Type String: Array of bytes
   Descriotion: Unknown
   Value      : 84,0,101,0,115,0,116,0,32,0,67,0,111,0,109,0,109,0,101,0,110,0,116,0,115,0,0,0
Property Item 9
   Id: 0x501b
   Type: 1
   Length: 6780 bytes
   Type String: Array of bytes
   Descriotion: PropertyTagThumbnailData
   Value      : 255,216,255,219,0,67,0,8,6,6,7,6,5,8,7,7,7,9,9,8,10,12,20,13,12,11,11,12,25,18,19,15,20,29,26,31,30,...
Property Item 10
   Id: 0x5023
   Type: 3
   Length: 2 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagThumbnailCompression
   Value      : 6
Property Item 11
   Id: 0x502d
   Type: 5
   Length: 8 bytes
   Type String: Rational
   Descriotion: PropertyTagThumbnailResolutionX
   Value      : 72,1
Property Item 12
   Id: 0x502e
   Type: 5
   Length: 8 bytes
   Type String: Rational
   Descriotion: PropertyTagThumbnailResolutionY
   Value      : 72,1
Property Item 13
   Id: 0x5030
   Type: 3
   Length: 2 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagThumbnailResolutionUnit
   Value      : 2
Property Item 14
   Id: 0x201
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagJPEGInterFormat
   Value      : 4488
Property Item 15
   Id: 0x202
   Type: 4
   Length: 4 bytes
   Type String: Long (32 bit int)
   Descriotion: PropertyTagJPEGInterLength
   Value      : 6780
Property Item 16
   Id: 0x5091
   Type: 3
   Length: 128 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagChrominanceTable
   Value      : 5,5,7,14,30,30,30,30,5,6,8,20,30,30,30,30,7,8,17,30,30,30,30,30,14,20,30,30,30,30,30,30,30,30,30,30,...
Property Item 17
   Id: 0x5090
   Type: 3
   Length: 128 bytes
   Type String: Short (16 bit int)
   Descriotion: PropertyTagLuminanceTableThe thread 'vshost.RunParkingWindow' (0x8a0) has exited with code 0 (0x0).
   Value      : 5,3,3,5,7,12,15,18,4,4,4,6,8,17,18,17,4,4,5,7,12,17,21,17,4,5,7,9,15,26,24,19,5,7,11,17,20,33,31,23,...

Code for Printing Out PropertyItem

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

namespace Utility
{
    public static class ImagePropertyUtils
    {

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/xddt0dz7%28v=vs.110%29.aspx
        /// </summary>
        public static void PrintProperties(this Image image)
        {
            // Get the PropertyItems property from image.
            var propItems = image.PropertyItems;

            // For each PropertyItem in the array, display the ID, type, and length.
            int count = 0;
            foreach (var propItem in propItems)
            {
                count++;
                // raw data
                Console.WriteLine("Property Item " + count.ToString());
                Console.WriteLine("   Id: 0x" + propItem.Id.ToString("x"));
                Console.WriteLine("   Type: " + propItem.Type.ToString());
                Console.WriteLine("   Length: " + propItem.Len.ToString() + " bytes");

                // human readable string
                Console.WriteLine("   Type String: " + PropItemToTypeString[propItem.Type]);
                Console.WriteLine("   Descriotion: " + (PropItemIdToDescriotionString.ContainsKey(propItem.Id) ? PropItemIdToDescriotionString[propItem.Id]: "Unknown"));
                Console.WriteLine("   Value      : " + propItem.ReadPropertValueAsString().Trim(100));
            }
        }

        const int BYTES = 1;
        const int ASCII = 2;
        const int SHORT = 3;
        const int LONG = 4;
        const int RATIONAL = 5;
        const int SLONG = 9;
        const int SRATIONAL = 10;

        /// <summary>
        /// According to http://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.type(v=vs.110).aspx
        /// </summary>
        private readonly static Dictionary<int, string> PropItemToTypeString = new Dictionary<int, string>()
        {
            {BYTES,     "Array of bytes"},
            {ASCII,     "ASCII"},
            {SHORT,     "Short (16 bit int)"},
            {LONG,      "Long (32 bit int)"},
            {RATIONAL,  "Rational"},
            {6,         "Not Used"},
            {7,         "Undefined"},
            {8,         "Not Used"},
            {SLONG,     "SLong"},
            {SRATIONAL, "SRational"}
        };

        /// <summary>
        /// According to http://msdn.microsoft.com/de-de/library/ms534416.aspx
        /// </summary>
        private readonly static Dictionary<int, string> PropItemIdToDescriotionString = new Dictionary<int, string>()
        {
            {0x013B, "PropertyTagArtist"},
            {0x0102, "PropertyTagBitsPerSample"},
            {0x0109, "PropertyTagCellHeight"},
            {0x0108, "PropertyTagCellWidth"},
            {0x5091, "PropertyTagChrominanceTable"},
            {0x0140, "PropertyTagColorMap"},
            {0x501A, "PropertyTagColorTransferFunction"},
            {0x0103, "PropertyTagCompression"},
            {0x8298, "PropertyTagCopyright"},
            {0x0132, "PropertyTagDateTime"},
            {0x010D, "PropertyTagDocumentName"},
            {0x0150, "PropertyTagDotRange"},
            {0x010F, "PropertyTagEquipMake"},
            {0x0110, "PropertyTagEquipModel"},
            {0x9202, "PropertyTagExifAperture"},
            {0x9203, "PropertyTagExifBrightness"},
            {0xA302, "PropertyTagExifCfaPattern"},
            {0xA001, "PropertyTagExifColorSpace"},
            {0x9102, "PropertyTagExifCompBPP"},
            {0x9101, "PropertyTagExifCompConfig"},
            {0x9004, "PropertyTagExifDTDigitized"},
            {0x9292, "PropertyTagExifDTDigSS"},
            {0x9003, "PropertyTagExifDTOrig"},
            {0x9291, "PropertyTagExifDTOrigSS"},
            {0x9290, "PropertyTagExifDTSubsec"},
            {0x9204, "PropertyTagExifExposureBias"},
            {0xA215, "PropertyTagExifExposureIndex"},
            {0x8822, "PropertyTagExifExposureProg"},
            {0x829A, "PropertyTagExifExposureTime"},
            {0xA300, "PropertyTagExifFileSource"},
            {0x9209, "PropertyTagExifFlash"},
            {0xA20B, "PropertyTagExifFlashEnergy"},
            {0x829D, "PropertyTagExifFNumber"},
            {0x920A, "PropertyTagExifFocalLength"},
            {0xA210, "PropertyTagExifFocalResUnit"},
            {0xA20E, "PropertyTagExifFocalXRes"},
            {0xA20F, "PropertyTagExifFocalYRes"},
            {0xA000, "PropertyTagExifFPXVer"},
            {0x8769, "PropertyTagExifIFD"},
            {0xA005, "PropertyTagExifInterop"},
            {0x8827, "PropertyTagExifISOSpeed"},
            {0x9208, "PropertyTagExifLightSource"},
            {0x927C, "PropertyTagExifMakerNote"},
            {0x9205, "PropertyTagExifMaxAperture"},
            {0x9207, "PropertyTagExifMeteringMode"},
            {0x8828, "PropertyTagExifOECF"},
            {0xA002, "PropertyTagExifPixXDim"},
            {0xA003, "PropertyTagExifPixYDim"},
            {0xA004, "PropertyTagExifRelatedWav"},
            {0xA301, "PropertyTagExifSceneType"},
            {0xA217, "PropertyTagExifSensingMethod"},
            {0x9201, "PropertyTagExifShutterSpeed"},
            {0xA20C, "PropertyTagExifSpatialFR"},
            {0x8824, "PropertyTagExifSpectralSense"},
            {0x9206, "PropertyTagExifSubjectDist"},
            {0xA214, "PropertyTagExifSubjectLoc"},
            {0x9286, "PropertyTagExifUserComment"},
            {0x9000, "PropertyTagExifVer"},
            {0x0152, "PropertyTagExtraSamples"},
            {0x010A, "PropertyTagFillOrder"},
            {0x5100, "PropertyTagFrameDelay"},
            {0x0121, "PropertyTagFreeByteCounts"},
            {0x0120, "PropertyTagFreeOffset"},
            {0x0301, "PropertyTagGamma"},
            {0x5102, "PropertyTagGlobalPalette"},
            {0x0006, "PropertyTagGpsAltitude"},
            {0x0005, "PropertyTagGpsAltitudeRef"},
            {0x0018, "PropertyTagGpsDestBear"},
            {0x0017, "PropertyTagGpsDestBearRef"},
            {0x001A, "PropertyTagGpsDestDist"},
            {0x0019, "PropertyTagGpsDestDistRef"},
            {0x0014, "PropertyTagGpsDestLat"},
            {0x0013, "PropertyTagGpsDestLatRef"},
            {0x0016, "PropertyTagGpsDestLong"},
            {0x0015, "PropertyTagGpsDestLongRef"},
            {0x000B, "PropertyTagGpsGpsDop"},
            {0x000A, "PropertyTagGpsGpsMeasureMode"},
            {0x0008, "PropertyTagGpsGpsSatellites"},
            {0x0009, "PropertyTagGpsGpsStatus"},
            {0x0007, "PropertyTagGpsGpsTime"},
            {0x8825, "PropertyTagGpsIFD"},
            {0x0011, "PropertyTagGpsImgDir"},
            {0x0010, "PropertyTagGpsImgDirRef"},
            {0x0002, "PropertyTagGpsLatitude"},
            {0x0001, "PropertyTagGpsLatitudeRef"},
            {0x0004, "PropertyTagGpsLongitude"},
            {0x0003, "PropertyTagGpsLongitudeRef"},
            {0x0012, "PropertyTagGpsMapDatum"},
            {0x000D, "PropertyTagGpsSpeed"},
            {0x000C, "PropertyTagGpsSpeedRef"},
            {0x000F, "PropertyTagGpsTrack"},
            {0x000E, "PropertyTagGpsTrackRef"},
            {0x0000, "PropertyTagGpsVer"},
            {0x0123, "PropertyTagGrayResponseCurve"},
            {0x0122, "PropertyTagGrayResponseUnit"},
            {0x5011, "PropertyTagGridSize"},
            {0x500C, "PropertyTagHalftoneDegree"},
            {0x0141, "PropertyTagHalftoneHints"},
            {0x500A, "PropertyTagHalftoneLPI"},
            {0x500B, "PropertyTagHalftoneLPIUnit"},
            {0x500E, "PropertyTagHalftoneMisc"},
            {0x500F, "PropertyTagHalftoneScreen"},
            {0x500D, "PropertyTagHalftoneShape"},
            {0x013C, "PropertyTagHostComputer"},
            {0x8773, "PropertyTagICCProfile"},
            {0x0302, "PropertyTagICCProfileDescriptor"},
            {0x010E, "PropertyTagImageDescription"},
            {0x0101, "PropertyTagImageHeight"},
            {0x0320, "PropertyTagImageTitle"},
            {0x0100, "PropertyTagImageWidth"},
            {0x5103, "PropertyTagIndexBackground"},
            {0x5104, "PropertyTagIndexTransparent"},
            {0x014D, "PropertyTagInkNames"},
            {0x014C, "PropertyTagInkSet"},
            {0x0209, "PropertyTagJPEGACTables"},
            {0x0208, "PropertyTagJPEGDCTables"},
            {0x0201, "PropertyTagJPEGInterFormat"},
            {0x0202, "PropertyTagJPEGInterLength"},
            {0x0205, "PropertyTagJPEGLosslessPredictors"},
            {0x0206, "PropertyTagJPEGPointTransforms"},
            {0x0200, "PropertyTagJPEGProc"},
            {0x0207, "PropertyTagJPEGQTables"},
            {0x5010, "PropertyTagJPEGQuality"},
            {0x0203, "PropertyTagJPEGRestartInterval"},
            {0x5101, "PropertyTagLoopCount"},
            {0x5090, "PropertyTagLuminanceTable"},
            {0x0119, "PropertyTagMaxSampleValue"},
            {0x0118, "PropertyTagMinSampleValue"},
            {0x00FE, "PropertyTagNewSubfileType"},
            {0x014E, "PropertyTagNumberOfInks"},
            {0x0112, "PropertyTagOrientation"},
            {0x011D, "PropertyTagPageName"},
            {0x0129, "PropertyTagPageNumber"},
            {0x5113, "PropertyTagPaletteHistogram"},
            {0x0106, "PropertyTagPhotometricInterp"},
            {0x5111, "PropertyTagPixelPerUnitX"},
            {0x5112, "PropertyTagPixelPerUnitY"},
            {0x5110, "PropertyTagPixelUnit"},
            {0x011C, "PropertyTagPlanarConfig"},
            {0x013D, "PropertyTagPredictor"},
            {0x013F, "PropertyTagPrimaryChromaticities"},
            {0x5005, "PropertyTagPrintFlags"},
            {0x5008, "PropertyTagPrintFlagsBleedWidth"},
            {0x5009, "PropertyTagPrintFlagsBleedWidthScale"},
            {0x5007, "PropertyTagPrintFlagsCrop"},
            {0x5006, "PropertyTagPrintFlagsVersion"},
            {0x0214, "PropertyTagREFBlackWhite"},
            {0x0128, "PropertyTagResolutionUnit"},
            {0x5003, "PropertyTagResolutionXLengthUnit"},
            {0x5001, "PropertyTagResolutionXUnit"},
            {0x5004, "PropertyTagResolutionYLengthUnit"},
            {0x5002, "PropertyTagResolutionYUnit"},
            {0x0116, "PropertyTagRowsPerStrip"},
            {0x0153, "PropertyTagSampleFormat"},
            {0x0115, "PropertyTagSamplesPerPixel"},
            {0x0155, "PropertyTagSMaxSampleValue"},
            {0x0154, "PropertyTagSMinSampleValue"},
            {0x0131, "PropertyTagSoftwareUsed"},
            {0x0303, "PropertyTagSRGBRenderingIntent"},
            {0x0117, "PropertyTagStripBytesCount"},
            {0x0111, "PropertyTagStripOffsets"},
            {0x00FF, "PropertyTagSubfileType"},
            {0x0124, "PropertyTagT4Option"},
            {0x0125, "PropertyTagT6Option"},
            {0x0151, "PropertyTagTargetPrinter"},
            {0x0107, "PropertyTagThreshHolding"},
            {0x5034, "PropertyTagThumbnailArtist"},
            {0x5022, "PropertyTagThumbnailBitsPerSample"},
            {0x5015, "PropertyTagThumbnailColorDepth"},
            {0x5019, "PropertyTagThumbnailCompressedSize"},
            {0x5023, "PropertyTagThumbnailCompression"},
            {0x503B, "PropertyTagThumbnailCopyRight"},
            {0x501B, "PropertyTagThumbnailData"},
            {0x5033, "PropertyTagThumbnailDateTime"},
            {0x5026, "PropertyTagThumbnailEquipMake"},
            {0x5027, "PropertyTagThumbnailEquipModel"},
            {0x5012, "PropertyTagThumbnailFormat"},
            {0x5014, "PropertyTagThumbnailHeight"},
            {0x5025, "PropertyTagThumbnailImageDescription"},
            {0x5021, "PropertyTagThumbnailImageHeight"},
            {0x5020, "PropertyTagThumbnailImageWidth"},
            {0x5029, "PropertyTagThumbnailOrientation"},
            {0x5024, "PropertyTagThumbnailPhotometricInterp"},
            {0x502F, "PropertyTagThumbnailPlanarConfig"},
            {0x5016, "PropertyTagThumbnailPlanes"},
            {0x5036, "PropertyTagThumbnailPrimaryChromaticities"},
            {0x5017, "PropertyTagThumbnailRawBytes"},
            {0x503A, "PropertyTagThumbnailRefBlackWhite"},
            {0x5030, "PropertyTagThumbnailResolutionUnit"},
            {0x502D, "PropertyTagThumbnailResolutionX"},
            {0x502E, "PropertyTagThumbnailResolutionY"},
            {0x502B, "PropertyTagThumbnailRowsPerStrip"},
            {0x502A, "PropertyTagThumbnailSamplesPerPixel"},
            {0x5018, "PropertyTagThumbnailSize"},
            {0x5032, "PropertyTagThumbnailSoftwareUsed"},
            {0x502C, "PropertyTagThumbnailStripBytesCount"},
            {0x5028, "PropertyTagThumbnailStripOffsets"},
            {0x5031, "PropertyTagThumbnailTransferFunction"},
            {0x5035, "PropertyTagThumbnailWhitePoint"},
            {0x5013, "PropertyTagThumbnailWidth"},
            {0x5037, "PropertyTagThumbnailYCbCrCoefficients"},
            {0x5039, "PropertyTagThumbnailYCbCrPositioning"},
            {0x5038, "PropertyTagThumbnailYCbCrSubsampling"},
            {0x0145, "PropertyTagTileByteCounts"},
            {0x0143, "PropertyTagTileLength"},
            {0x0144, "PropertyTagTileOffset"},
            {0x0142, "PropertyTagTileWidth"},
            {0x012D, "PropertyTagTransferFunction"},
            {0x0156, "PropertyTagTransferRange"},
            {0x013E, "PropertyTagWhitePoint"},
            {0x011E, "PropertyTagXPosition"},
            {0x011A, "PropertyTagXResolution"},
            {0x0211, "PropertyTagYCbCrCoefficients"},
            {0x0213, "PropertyTagYCbCrPositioning"},
            {0x0212, "PropertyTagYCbCrSubsampling"},
            {0x011F, "PropertyTagYPosition"},
            {0x011B, "PropertyTagYResolution"},
        };

        public static string ReadPropertValueAsString(this PropertyItem propItem)
        {
            switch (propItem.Type)
            {
                case BYTES:
                    {
                        return propItem.Value.ToCommaSeparatedString();
                    }
                case ASCII: 
                    {
                        return System.Text.Encoding.ASCII.GetString(propItem.Value).TrimEnd('\0');
                    }
                case SHORT: 
                    {
                        var value = propItem.Value;
                        var ret = new ushort[propItem.Len / 2];
                        for (int i = 0; i < propItem.Len; i += 2)
                        {
                            ret[i / 2] = (ushort)(value[i + 1] << 8 | value[i]);
                        }
                        return ret.ToCommaSeparatedString();
                    }
                case LONG:
                case RATIONAL:
                    {
                        var value = propItem.Value;
                        var ret = new uint[propItem.Len / 4];
                        for (int i = 0; i < propItem.Len; i += 4)
                        {
                            ret[i / 4] = (uint)(value[i + 3] << 24 | value[i + 2] << 16 | value[i + 1] << 8 | value[i]);
                        }
                        return ret.ToCommaSeparatedString();
                    }
                case SLONG:
                case SRATIONAL:
                    {
                        var value = propItem.Value;
                        var ret = new int[propItem.Len / 4];
                        for (int i = 0; i < propItem.Len; i += 4)
                        {
                            ret[i / 4] = value[i + 3] << 24 | value[i + 2] << 16 | value[i + 1] << 8 | value[i];
                        }
                        return ret.ToCommaSeparatedString();
                    }
                default:
                    return "";
            }
        }

        private static string ToCommaSeparatedString<T>(this ICollection<T> collection)
        {
            return collection != null ? string.Join(",", collection.ToArray()) : null;
        }

        private static string Trim(this string text, int limit, string suffix="...")
        {
            if (text.Length > limit)
            {
                return text.Substring(0, limit) + suffix;
            }
            return text;
        }
    }
}

コメント

このブログの人気の投稿

Eclipseでコードカバレッジのハイライトを削除する方法

Eclipseには便利なコードカバレッジ表示機能が搭載されていますが、コード内に緑、赤、黄の色付けがされて煩く感じるときもあると思います。 1度カバレッジの色付けが出てしまった後に消す方法の紹介です(方法は簡単)。 下記のキャプチャの青いマーカーで示した「Remove All Sessions」のボタンを押せばすべて消えます。

「特定の文字から始まらない文字列」にマッチする正規表現

「特定の文字から始まらない文字列」 にマッチする正規表現の例です。  以下の例では、Aから始まらない文字列にマッチする正規表現を示しています。 ^(?!A).*$ 私も正規表現の組み方で四苦八苦することがあります。以下の書籍は実践的に様々な正規表現のパターンを例示してくれているので、重宝しています。

ダイソーで買った200円のドライバーセットでHDDを分解

HDDの処分 最近は個人情報の問題もあって、HDDを処分する前にちゃんとデータの消去を気にすることも多くなってきました。消去方法としては大きく分けて下記の3つがあります。 データ消去ソフトでフォーマット HDD内部のプラッタを物理破壊 データ消去を行ってくれる専門の業者や家電量販店(Sofmapやビックカメラで実施していると思います。費用発生。)に持ち込み。 データ消去ソフトでのフォーマットは簡単ですが、欠点として「フォーマットに時間がかかる」「セクタ破損などで中途半端に壊れたディスクのフォーマットができない」などがあります。 またHDD内部のプラッタの物理破壊については、HDDを分解するために、通常のプラスやマイナスドライバーではなく、星形ネジに対応したトルクスドライバーが必要とのこともあって、少し面倒です。 筆者は今回、今後もHDDの廃棄をするだろうなあと思い、思い切って自分で分解して廃棄することにチャレンジしてみました。(家電量販店に持って行くよりも安くできないかというどケチ丸出しですw) HDDの星形ネジ こんなやつです。ちなみに写真はSeagateのST2000DL003というHDDで撮影しました。 トルクスドライバー というわけで、分解のために Amazonでトルクスドライバー を探しました。 調べると T8のもだと使えそう とのことで、いろいろと物色。 セットのものとか T8一本で立派なやつとか 色々あったのですが、HDD壊すだけで800円かぁ(←どケチ)、と思って購入を躊躇。 ネット上で調べると100円ショップのダイソーでも、トルクスドライバーを販売しているとの情報をキャッチ!近所のダイソーに行って、探したところ星形のヘッド交換に対応した精密ドライバーセットがありました。 プラスが10種類、マイナスが8種類、六角が6種類、星形が6種類(今回ほしかったもの)のセットで、何とお値段税抜き200円!、税抜き200円!と安かったので、ダメもとで購入しました。 結論から言うと 買って大正解 でした。 ダイソーの精密ドライバーセット こんな商品です! 星形対応のヘッドを装着するとこんな感じ。ドライバーのグリップもゴムで滑らない様になっていて使いやす

SQLで特定の文字を組み合わせたランダムな文字列を生成

簡易的な方法として「指定した文字列からランダムに1文字選ぶ」を必要な文字の長さ分concat関数でつなげれば実現できます。 1文字ずつ文字を選ぶので、あまり性能もよくない上、セキュリティ的な観点からのランダム性も担保されていないので、あくまで開発中に必要になった時に使う程度が無難だと思います。 下記に英数字大文字小文字を含んだランダムな3文字の文字列を生成するクエリを示します。 # RAND関数で指定した文字列からランダムに1文字選択。 # 下記の例の62の部分はa~z、A~Z、1~9の文字数の合計値を入れた結果 SELECT CONCAT( SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1) ) AS random_string;

PHPの配列(array)のメモリ使用量の考察

はじめに 最近PHP上に大量のデータをメモリ上に展開していたのですが、配列(array)の形式(連想配列 or 単純な配列)や配列の要素のデータ構造(数字、配列、文字列など)で大きくメモリ使用量に差が出てくることに気づき、簡単なプログラムを組んで調べてみました。 あくまで筆者の環境での結果なので、細かい数値は参考程度に見てください。 測定環境と方法 OS: Windows 10 PHP 7.4.5 (php-7.4.5-nts-Win32-vc15-x64) 配列に要素を追加するプログラムを書いて、PHPのmemory_get_usage(true)関数を使って実メモリ使用量を計測しました。 計測結果 No. 方式 1MB当たり作成できる 要素数 プログラム 補足 1 キーも値も整数の配列 (整数IDを想定) 28571 // 2,000,000 / 70MB $row = []; for($i = 0; $i < 2000000; $i++) { $row[] = $i; } No.2~6でテストしたプログラム中の要素数は200,000。これだけ一桁多い! 2 キーが文字列、値が整数の連想配列 8333 // 200,000 / 24MB $row = []; for($i = 0; $i < 200000; $i++) { $row[$i.'_key_string'] = $i; } キーの文字列が長い方がメモリ使用量多くなる。 3 キーが整数、値が連想配列の配列 DBから取得してきたデータを想定 2325 // 200,000 / 86MB $row = []; for($i = 0; $i < 200000; $i++) { row[] = ['id' => $i]; } 4 キーが整数、値が連想配列の配列(配列に複数の値を保持) DBから取得してきたデータを想定 2127 // 200,000 /

ADODB.streamオブジェクトを使って文字列とByte配列を相互変換(Excel VBA)

ADODB.streamオブジェクトを使って文字列をByte配列に変換するコードのサンプルです。 ExcelVBAでADODB.streamを使う際には、 1. ExcelのMicrosoft Visual Basic エディタのメニューバーから「ツール->参照設定」とたどる。 2. 表示されたダイアログからMicrosoft ActiveX Data Objectsにチェックを入れる。 という手順が必要です。 文字列からByte配列へ Private Function ADOS_EncodeStringToByte(ByVal cset As String, ByRef strUni As String) As Byte() On Error GoTo e Dim objStm As ADODB.stream: Set objStm = New ADODB.stream objStm.Mode = adModeReadWrite objStm.Open objStm.Type = adTypeText objStm.Charset = cset objStm.WriteText strUni objStm.Position = 0 objStm.Type = adTypeBinary Select Case UCase(cset) Case "UNICODE", "UTF-16" objStm.Position = 2 Case "UTF-8" objStm.Position = 3 End Select ADOS_EncodeStringToByte = objStm.Read() objStm.Close Set objStm = Nothing Exit Function e: Debug.Print "Error occurred while encoding characters" & Err.Description If objStm Is No

MySQLのSQL_CALC_FOUND_ROWS使用上の注意

MySQLのSQL_CALC_FOUND_ROWSを使用する際の無駄なメモリ消費に注意 ページング機能の実装などのために、ヒットした全件数を取得する必要のある場合があるかと思います。 その場合、下記のようにSQL_CALC_FOUND_ROWSを使うと、検索結果に加えて、そのクエリの全ヒット件数が取得できます。 SELECT SQL_CALC_FOUND_ROWS table.column1, table.column2 ...(途中省略)... FROM table WHERE (条件) しかし、SQL_CALC_FOUND_ROWSを使うと、「絞り込んだ結果にヒットする全べての行の結果のセットを作成する」という大きな欠点があります。 これは、LIMIT, OFFSETを指定していても実行されてしまうので、 SELECTで指定するカラム数やデータ量が多い SELECTの結果返ってくる行数が多い 場合、無駄に領域(≒メモリ)を消費してしまうので注意が必要です。 例えば、100万行検索対象としてヒットするクエリの場合、仮にLIMIT 20と指定して最初の20行を取得するようにクエリを書いても、その100万行分の結果セットが作成されてしまうということになります。 対応策 根本的な対応策としては、SQL_CALC_FOUND_ROWSを使わない(結果行数の取得はCOUNTを用いた別クエリで取得する、結果行数をあらかじめサマリーテーブルに保持しておく)ことですが、 SQL_CALC_FOUND_ROWSをどうしても使う必要がある場合は、 SELECT SQL_CALC_FOUND_ROWS primary_id のように最低限のカラムを指定して結果行セットを取得 (LIMIT OFFSET指定前提) 取得したprimary_idを使って必要なデータを取得 して、SQL_CALC_FOUND_ROWSで使用する領域をできるだけ減らすことで、対応するしかないと思います。 世の中ではLIMIT, OFFSETは使わない方がよいとよく書かれていますが、 SQL_CALC_FOUND_ROWSは、書いてしまえばどんなときも検索にヒットする全結果行セットを作成するので、同じくらい使用する際には注意が必要です。

Visual Studio 2010 SP1のアンインストール

Visual Studio 2013に乗り換えるためにVisual Studio 2010をアンインストールしようとしたところで問題発生。。。 先にVisual Studio 2010本体をアンインストールした後、Visual Studio 2010 SP1をアンインストールできなくて困っていました。 Google先生で調べたところ、以下の情報が見つかり、書かれていた通り実施したところ無事Visual Studio 2010 SP1のアンインストールに成功しました。 How to uninstall/remove Visual Studio SP1 アンインストール手順は以下の通りです。 http://www.microsoft.com/en-gb/download/details.aspx?id=23691 からMicrosoft Visual Studio 2010 Service Pack 1 (Installer)をダウンロード VS10sp1-KB983509.exeというファイル名でダウンロードされる(はず)。 コマンドプロンプトから以下のコマンドを実行 (以下の例は、c:\tempにVS10sp1-KB983509.exeがある場合) c:\temp\VS10sp1-KB983509.exe /uninstall /force ダイアログが立ち上がるので、アンインストールを選択して次へ進めばOK!

WinHttp.WinHttpRequestを使ってHttp PostでByte配列やString配列を送信するプログラム(Excel VBA)

WinHttp.WinHttpRequestオブジェクトを使って使ってHttp PostでByte配列のデータを送信するExcel VBAプログラムです。 WinHttp.WinHttpRequestを使う際には、 1. ExcelのMicrosoft Visual Basic エディタのメニューバーから「ツール->参照設定」とたどる。 2. 表示されたダイアログからMicrosoft WinHTTP Serviceにチェックを入れる。 という手順が必要です。 Byte配列をPOST Private Const BOUNDARY As String = "SOMETHING" Private Function httpPostServletByte(url As String, data() As Byte) As Byte() On Error GoTo e Dim WinHttpReq As WinHttp.WinHttpRequest If (WinHttpReq Is Nothing) Then Set WinHttpReq = New WinHttpRequest End If WinHttpReq.Open "POST", url, False WinHttpReq.SetRequestHeader "Content-Type", "application/x-www-form-urlencoded; boundary=" & BOUNDARY WinHttpReq.send data Dim response() As Byte: response = WinHttpReq.ResponseBody httpPostServletByte = response Set WinHttpReq = Nothing Exit Function e: Set WinHttpReq = Nothing Debug.Print "httpPost Error:" & Err.

MySQL: SELECTの結果をUNIONして ORDER BYする際の最適化方法

SELECTの結果をUNIONして ORDER BY する際には下記の点に注意する必要があります。 無駄なメモリ消費 ソートにINDEXが利かない (≒CPU負荷増大) 対応策 可能であればPush-down Condition (各サブクエリ内でORDER BY, LIMIT, OFFSETを適用してからUNION, ORDER BYを実行する)を利用することで、 パフォーマンスを改善できる場合があります。 下記に例を示します。 もともとのクエリ SELECT tmp.* FROM ( SELECT tableA.column1, tableA.column2 FROM tableA WHERE (条件) UNION ALL SELECT tableB.column1, tableB.column2 FROM tableB WHERE (条件) ) AS tmp ORDER BY tmp.column1, tmp.column2 LIMIT 100, 20 Push-down Conditionを用いて書き直したクエリ SELECT tmp.* FROM ( SELECT tableA.column1, tableA.column2 FROM tableA WHERE (条件) ORDER BY tableA.column1, tableA.column2 LIMIT 30 # <- 10 (offset) + 20 (limit) UNION ALL SELECT tableB.column1, tableB.column2 FROM tableB WHERE (条件) ORDER BY tableB.column1, tableB.column2 LIMIT 30 # <- 10 (offset) + 20 (limit) ) AS tmp ORDER BY tmp.column1, tmp.column2 LIMIT 10, 20 ただしこのPush-down Conditionの手法も下記の場合は、効果が半減しますので注意が必要です。 OFFSETの値が大きい場合は、結局全結果セットUNIONと変わらない サブクエリ内のソートで、INDEXが効かない場合