もっと

諏訪子 <suwako@076.moe>、2026-01-13 02:17
コミット 2a0956dfd4202b0930b520ba9effb291cd6df3c0 ・親 6582737 ・ファイルを見る

1個のファイル、+113 -12

@@ -96,7 +96,7 @@
9696 public array $frames = [];
9797 private ?array $currentFrame = null;
9898
99- // TODO: 残り: sBIT, cICP, mDCV, cLLI, iTXt, hIST, sPLT, tIME
99+ // TODO: 残り: sBIT, iTXt, hIST, sPLT, tIME
100100 public function parse(string $file): \stdClass {
101101 $png = new \stdClass();
102102 $fp = fopen($file, 'rb');
@@ -114,6 +114,8 @@
114114
115115 // N = ビッグエンディアン(4ビット)
116116 $this->IHDR = new \stdClass;
117+ $this->IHDR->name = 'IHDR';
118+ $this->IHDR->length = $length;
117119 $this->IHDR->width = unpack('N', substr($data, 0, 4))[1];
118120 $this->IHDR->height = unpack('N', substr($data, 4, 4))[1];
119121 $this->IHDR->bitDepth = ord($data[8]); // 1, 2, 4, 8, 16
@@ -154,6 +156,8 @@
154156 }
155157
156158 $this->PLTE = new \stdClass;
159+ $this->PLTE->name = 'PLTE';
160+ $this->PLTE->length = $length;
157161 $this->PLTE->palette = $palette;
158162 $this->PLTE->crc = $crc;
159163 $this->PLTE->crc32 = unpack('N', $crc)[1];
@@ -163,6 +167,8 @@
163167 goto next_chunk;
164168 } else if ($nextChunk === "\x74\x52\x4e\x53") { // tRNS
165169 $this->tRNS = new \stdClass;
170+ $this->tRNS->name = 'tRNS';
171+ $this->tRNS->length = $length;
166172 $vals = [];
167173 $bytes = $this->IHDR->colorType === 2 ? 3 : 1;
168174 for ($i = 0; $i < $length; $i += $bytes) {
@@ -181,6 +187,8 @@
181187 goto next_chunk;
182188 } else if ($nextChunk === "\x63\x48\x52\x4d") { // cHRM
183189 $this->cHRM = new \stdClass;
190+ $this->cHRM->name = 'cHRM';
191+ $this->cHRM->length = $length;
184192 $this->cHRM->whitePointX = unpack('N', substr($data, 0, 4))[1];
185193 $this->cHRM->whitePointY = unpack('N', substr($data, 4, 4))[1];
186194 $this->cHRM->redX = unpack('N', substr($data, 8, 4))[1];
@@ -196,6 +204,8 @@
196204 goto next_chunk;
197205 } else if ($nextChunk === "\x67\x41\x4d\x41") { // gAMA
198206 $this->gAMA = new \stdClass;
207+ $this->gAMA->name = 'gAMA';
208+ $this->gAMA->length = $length;
199209 $this->gAMA->value = unpack('N', $data)[1];
200210 $this->gAMA->crc = $crc;
201211 $this->gAMA->crc32 = unpack('N', $crc)[1];
@@ -204,6 +214,8 @@
204214 goto next_chunk;
205215 } else if ($nextChunk === "\x69\x43\x43\x50") { // iCCP
206216 $this->iCCP = new \stdClass;
217+ $this->iCCP->name = 'iCCP';
218+ $this->iCCP->length = $length;
207219
208220 $nullPos = strpos($data, "\0");
209221 if ($nullPos === false || $nullPos < 1 || $nullPos > 79) {
@@ -235,11 +247,18 @@
235247 goto next_chunk;
236248 } else if ($nextChunk === "\x73\x42\x49\x54") { // sBIT
237249 $this->sBIT = new \stdClass;
238- kys('sBIT');
250+ $this->sBIT->name = 'sBIT';
251+ $this->sBIT->length = $length;
252+ kys(['sBIT', $length, bin2hex($data)]);
253+ $this->sBIT->crc = $crc;
254+ $this->sBIT->crc32 = unpack('N', $crc)[1];
255+ $this->sBIT->crcHex = bin2hex($crc);
239256 $png->significantBits = $this->sBIT;
240257 goto next_chunk;
241258 } else if ($nextChunk === "\x73\x52\x47\x42") { // sRGB
242259 $this->sRGB = new \stdClass;
260+ $this->sRGB->name = 'sRGB';
261+ $this->sRGB->length = $length;
243262 $this->sRGB->intent = ord($data);
244263 $name = [
245264 0 => 'Perceptual',
@@ -255,34 +274,85 @@
255274 goto next_chunk;
256275 } else if ($nextChunk === "\x63\x49\x43\x50") { // cICP
257276 $this->cICP = new \stdClass;
258- kys('cICP');
277+ $this->cICP->name = 'cICP';
278+ $this->cICP->length = $length;
279+ $this->cICP->colorPrimaries = ord($data[0]);
280+ $this->cICP->transferFunction = ord($data[1]);
281+ $this->cICP->matrixCoefficients = ord($data[2]);
282+ $this->cICP->videoFullRangeFlag = ord($data[3]);
283+ $this->cICP->crc = $crc;
284+ $this->cICP->crc32 = unpack('N', $crc)[1];
285+ $this->cICP->crcHex = bin2hex($crc);
259286 $png->videoSignalTypeId = $this->cICP;
260287 goto next_chunk;
261288 } else if ($nextChunk === "\x6d\x44\x43\x56") { // mDCV
262289 $this->mDCV = new \stdClass;
263- kys('mDCV');
290+ $this->mDCV->name = 'mDCV';
291+ $this->mDCV->length = $length;
292+
293+ $u16 = fn($off) => unpack('n', substr($data, $off, 2))[1];
294+ $u32 = fn($off) => unpack('N', substr($data, $off, 4))[1];
295+ $this->mDCV->primaries = [
296+ 'red' => ['x' => $u16(0), 'y' => $u16(2)],
297+ 'green' => ['x' => $u16(4), 'y' => $u16(6)],
298+ 'blue' => ['x' => $u16(8), 'y' => $u16(10)],
299+ ];
300+ $this->mDCV->whitePoint = [
301+ 'x' => $u16(12),
302+ 'y' => $u16(14),
303+ ];
304+ $this->mDCV->luminance = [
305+ 'max' => $u16(16) * 0.0001,
306+ 'min' => $u16(20) * 0.0001,
307+ 'maxRaw' => $u16(16),
308+ 'minRaw' => $u16(20),
309+ ];
310+ $this->mDCV->crc = $crc;
311+ $this->mDCV->crc32 = unpack('N', $crc)[1];
312+ $this->mDCV->crcHex = bin2hex($crc);
264313 $png->masterDisplayColorVolume = $this->mDCV;
265314 goto next_chunk;
266315 } else if ($nextChunk === "\x63\x4c\x4c\x49") { // cLLI
267316 $this->cLLI = new \stdClass;
268- kys('cLLI');
317+ $this->cLLI->name = 'cLLI';
318+ $this->cLLI->length = $length;
319+ $this->cLLI->maxCCL = unpack('N', substr($data, 0, 4))[1] * 0.0001;
320+ $this->cLLI->maxCCLRaw = unpack('N', substr($data, 0, 4))[1];
321+ $this->cLLI->maxFALL = unpack('N', substr($data, 4, 4))[1] * 0.0001;
322+ $this->cLLI->maxFALLRaw = unpack('N', substr($data, 4, 4))[1];
323+ $this->cLLI->crc = $crc;
324+ $this->cLLI->crc32 = unpack('N', $crc)[1];
325+ $this->cLLI->crcHex = bin2hex($crc);
269326 $png->contentLightLevelInfo = $this->cLLI;
270327 goto next_chunk;
271328 } else if ($nextChunk === "\x74\x45\x58\x74") { // tEXt
329+ if (!isset($png->textualData)) $png->textualData = [];
272330 $this->tEXt = new \stdClass;
331+ $this->tEXt->name = 'tEXt';
332+ $this->tEXt->length = $length;
273333 $this->tEXt->text = $data;
274334 $this->tEXt->crc = $crc;
275335 $this->tEXt->crc32 = unpack('N', $crc)[1];
276336 $this->tEXt->crcHex = bin2hex($crc);
277- $png->textualData = $this->tEXt;
337+ $png->textualData[] = $this->tEXt;
278338 goto next_chunk;
279339 } else if ($nextChunk === "\x69\x54\x58\x74") { // iTXt
340+ if (!isset($png->internationalTextualData)) $png->textualData = [];
280341 $this->iTXt = new \stdClass;
281- kys('iTXt');
282- $png->internationalTextualData = $this->iTXt;
342+ $this->iTXt->name = 'iTXt';
343+ $this->iTXt->length = $length;
344+ kys(['iTXt', $length, bin2hex($data)]);
345+ $this->iTXt->crc = $crc;
346+ $this->iTXt->crc32 = unpack('N', $crc)[1];
347+ $this->iTXt->crcHex = bin2hex($crc);
348+ $png->internationalTextualData[] = $this->iTXt;
349+ kys($png);
283350 goto next_chunk;
284351 } else if ($nextChunk === "\x7a\x54\x58\x74") { // zTXt
352+ if (!isset($png->compressedTextualData)) $png->textualData = [];
285353 $this->zTXt = new \stdClass;
354+ $this->zTXt->name = 'zTXt';
355+ $this->zTXt->length = $length;
286356
287357 $nullPos = strpos($data, "\0");
288358 if ($nullPos === false || $nullPos < 1 || $nullPos > 79) {
@@ -325,10 +395,12 @@
325395 $this->zTXt->crc = $crc;
326396 $this->zTXt->crc32 = unpack('N', $crc)[1];
327397 $this->zTXt->crcHex = bin2hex($crc);
328- $png->compressedTextualData = $this->zTXt;
398+ $png->compressedTextualData[] = $this->zTXt;
329399 goto next_chunk;
330400 } else if ($nextChunk === "\x62\x4b\x47\x44") { // bKGD
331401 $this->bKGD = new \stdClass;
402+ $this->bKGD->name = 'bKGD';
403+ $this->bKGD->length = $length;
332404 if ($this->IHDR->colorType === 2 || $this->IHDR->colorType === 6) {
333405 $r = (ord($data[0]) << 8) | ord($data[1]);
334406 $g = (ord($data[2]) << 8) | ord($data[3]);
@@ -363,11 +435,19 @@
363435 goto next_chunk;
364436 } else if ($nextChunk === "\x68\x49\x53\x54") { // hIST
365437 $this->hIST = new \stdClass;
366- kys('hIST');
438+ $this->hIST->name = 'hIST';
439+ $this->hIST->length = $length;
440+ kys(['hIST', $length, bin2hex($data)]);
441+ $this->hIST->crc = $crc;
442+ $this->hIST->crc32 = unpack('N', $crc)[1];
443+ $this->hIST->crcHex = bin2hex($crc);
367444 $png->imageHistogram = $this->hIST;
445+ kys($png);
368446 goto next_chunk;
369447 } else if ($nextChunk === "\x70\x48\x59\x73") { // pHYs
370448 $this->pHYs = new \stdClass;
449+ $this->pHYs->name = 'pHYs';
450+ $this->pHYs->length = $length;
371451 $this->pHYs->x = unpack('N', substr($data, 0, 4))[1];
372452 $this->pHYs->y = unpack('N', substr($data, 4, 4))[1];
373453 $unit = [
@@ -383,11 +463,19 @@
383463 goto next_chunk;
384464 } else if ($nextChunk === "\x73\x50\x4c\x54") { // sPLT
385465 $this->sPLT = new \stdClass;
386- kys('sPLT');
466+ $this->sPLT->name = 'sPLT';
467+ $this->sPLT->length = $length;
468+ kys(['sPLT', $length, bin2hex($data)]);
469+ $this->sPLT->crc = $crc;
470+ $this->sPLT->crc32 = unpack('N', $crc)[1];
471+ $this->sPLT->crcHex = bin2hex($crc);
387472 $png->suggestedPalette = $this->sPLT;
473+ kys($png);
388474 goto next_chunk;
389475 } else if ($nextChunk === "\x65\x58\x49\x66") { // eXIf
390476 $this->eXIf = new \stdClass;
477+ $this->eXIf->name = 'eXIf';
478+ $this->eXIf->length = $length;
391479
392480 if (strlen($data) < 8) {
393481 $this->eXIf->valid = false;
@@ -423,11 +511,19 @@
423511 goto next_chunk;
424512 } else if ($nextChunk === "\x74\x49\x4d\x45") { // tIME
425513 $this->tIME = new \stdClass;
426- kys('tIME');
514+ $this->tIME->name = 'tIME';
515+ $this->tIME->length = $length;
516+ kys(['tIME', $length, bin2hex($data)]);
517+ $this->tIME->crc = $crc;
518+ $this->tIME->crc32 = unpack('N', $crc)[1];
519+ $this->tIME->crcHex = bin2hex($crc);
427520 $png->lastModificationTime = $this->tIME;
521+ kys($png);
428522 goto next_chunk;
429523 } else if ($nextChunk === "\x61\x63\x54\x4c") { // acTL
430524 $this->acTL = new \stdClass;
525+ $this->acTL->name = 'acTL';
526+ $this->acTL->length = $length;
431527 $this->acTL->numFrames = unpack('N', substr($data, 0, 4))[1];
432528 $this->acTL->numPlays = unpack('N', substr($data, 4, 4))[1];
433529 $this->acTL->crc = $crc;
@@ -439,6 +535,8 @@
439535 if ($this->currentFrame !== null) $this->frames[] = (object)$this->currentFrame;
440536
441537 $this->currentFrame = [
538+ 'name' => 'fcTL',
539+ 'length' => $length,
442540 'sequenceNumber' => unpack('N', substr($data, 0, 4))[1],
443541 'width' => unpack('N', substr($data, 4, 4))[1],
444542 'height' => unpack('N', substr($data, 8, 4))[1],
@@ -467,6 +565,8 @@
467565 }
468566
469567 $compressedData = ($nextChunk === "\x66\x64\x41\x54") ? substr($data, 4) : $data;
568+ $this->currentFrame['name'] = 'fdAT';
569+ $this->currentFrame['length'] = $length;
470570 $this->currentFrame['data'] = $compressedData;
471571 $this->currentFrame['dataBase64'] = base64_encode($compressedData);
472572 $this->currentFrame['dataHex'] = bin2hex($compressedData);
@@ -477,6 +577,7 @@
477577 $this->currentFrame['crcHex'] = bin2hex($crc);
478578
479579 if ($nextChunk === "\x49\x44\x41\x54") {
580+ $this->currentFrame['name'] = 'IDAT';
480581 $this->frames[] = (object)$this->currentFrame;
481582 $this->currentFrame = null;
482583 }